23

I'm using wp_login_form() to display login form in a jQuery dialog window.

If user enters wrong password, the user is taken to the backend. I don't want that. Is there a way to notify user that he entered wrong password and still remain on the same page?

Before wp_login_form() came I was using a plugin. I'm kind of hoping I can avoid using a plugin for this.

My code:

wp_login_form( array(
  'label_remember' => __( 'Remember me' ),
  'label_log_in' => __( 'Login' )
) );

8 Answers 8

6

wp_login_form() creates a form with an action attribute of site_url/wp-login.php, which means that when you click the submit button the form is posted to site_url/wp-login.php which ignores redirect_to on errors (like wrong password) so in your case either go back to using a plugin or recreate the whole login process and that way you will have control on errors, take a look at Check for correct username on custom login form which is very similar question.

0
34

I came here from google. But the answer didn't satisfy me. I was looking for a while and found a better solution.

Add this to your functions.php:

add_action( 'wp_login_failed', 'my_front_end_login_fail' );  // hook failed login

function my_front_end_login_fail( $username ) {
   $referrer = $_SERVER['HTTP_REFERER'];  // where did the post submission come from?
   // if there's a valid referrer, and it's not the default log-in screen
   if ( !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') ) {
      wp_redirect( $referrer . '?login=failed' );  // let's append some information (login=failed) to the URL for the theme to use
      exit;
   }
}
4
  • Thanks Alexey, I will test this (as I'm still using a plugin)
    – Steven
    Commented Jun 19, 2012 at 23:29
  • 10
    Alexey's solution works when wrong credentials are entered, but unfortunately fails when the user forgets to enter username or password. Apparently Wordpress doesn't even try to log the user in in this case, so wp_login_failed action is not performed. Commented Sep 12, 2012 at 7:39
  • 1
    I would use wp_get_referer() here to save some time: codex.wordpress.org/Function_Reference/wp_get_referer
    – Jake
    Commented Jul 3, 2013 at 17:00
  • 3
    Also, you definitely use add_query_arg here, so the wp_redirect should be: "wp_redirect( add_query_arg('login', 'failed', $referrer) );"
    – Jake
    Commented Jul 3, 2013 at 17:14
25

The current method I am using to deal with all of the issues outlined here works great even with blank username/password and doesn't rely on javascript (though the js could be good along with this).

add_action( 'wp_login_failed', 'custom_login_failed' );
function custom_login_failed( $username )
{
    $referrer = wp_get_referer();

    if ( $referrer && ! strstr($referrer, 'wp-login') && ! strstr($referrer,'wp-admin') )
    {
        wp_redirect( add_query_arg('login', 'failed', $referrer) );
        exit;
    }
}

The key is this filter to change how a blank username/password is treated:

add_filter( 'authenticate', 'custom_authenticate_username_password', 30, 3);
function custom_authenticate_username_password( $user, $username, $password )
{
    if ( is_a($user, 'WP_User') ) { return $user; }

    if ( empty($username) || empty($password) )
    {
        $error = new WP_Error();
        $user  = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid username or incorrect password.'));

        return $error;
    }
}

You can take this a step further and completely replace wp-login.php by redirecting users to your custom login page and use that page for the login_failed redirect also. Full code:

/**
 * Custom Login Page Actions
 */
// Change the login url sitewide to the custom login page
add_filter( 'login_url', 'custom_login_url', 10, 2 );
// Redirects wp-login to custom login with some custom error query vars when needed
add_action( 'login_head', 'custom_redirect_login', 10, 2 );
// Updates login failed to send user back to the custom form with a query var
add_action( 'wp_login_failed', 'custom_login_failed', 10, 2 );
// Updates authentication to return an error when one field or both are blank
add_filter( 'authenticate', 'custom_authenticate_username_password', 30, 3);
// Automatically adds the login form to "login" page
add_filter( 'the_content', 'custom_login_form_to_login_page' );

/**
 * Custom Login Page Functions
 */
function custom_login_url( $login_url='', $redirect='' )
{
    $page = get_page_by_path('login');
    if ( $page )
    {
        $login_url = get_permalink($page->ID);

        if (! empty($redirect) )
            $login_url = add_query_arg('redirect_to', urlencode($redirect), $login_url);
    }
    return $login_url;
}
function custom_redirect_login( $redirect_to='', $request='' )
{
    if ( 'wp-login.php' == $GLOBALS['pagenow'] )
    {
        $redirect_url = custom_login_url();

        if (! empty($_GET['action']) )
        {
            if ( 'lostpassword' == $_GET['action'] )
            {
                return;
            }
            elseif ( 'register' == $_GET['action'] )
            {
                $register_page = get_page_by_path('register');
                $redirect_url = get_permalink($register_page->ID);
            }
        }
        elseif (! empty($_GET['loggedout'])  )
        {
            $redirect_url = add_query_arg('action', 'loggedout', custom_login_url());
        }

        wp_redirect( $redirect_url );
        exit;
    }
}
function custom_login_failed( $username )
{
    $referrer = wp_get_referer();

    if ( $referrer && ! strstr($referrer, 'wp-login') && ! strstr($referrer, 'wp-admin') )
    {
        if ( empty($_GET['loggedout']) )
        wp_redirect( add_query_arg('action', 'failed', custom_login_url()) );
        else
        wp_redirect( add_query_arg('action', 'loggedout', custom_login_url()) );
        exit;
    }
}
function custom_authenticate_username_password( $user, $username, $password )
{
    if ( is_a($user, 'WP_User') ) { return $user; }

    if ( empty($username) || empty($password) )
    {
        $error = new WP_Error();
        $user  = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid username or incorrect password.'));

        return $error;
    }
}
function custom_login_form_to_login_page( $content )
{
    if ( is_page('login') && in_the_loop() )
    {
        $output = $message = "";
        if (! empty($_GET['action']) )
        {
            if ( 'failed' == $_GET['action'] )
                $message = "There was a problem with your username or password.";
            elseif ( 'loggedout' == $_GET['action'] )
                $message = "You are now logged out.";
            elseif ( 'recovered' == $_GET['action'] )
                $message = "Check your e-mail for the confirmation link.";
        }

        if ( $message ) $output .= '<div class="message"><p>'. $message .'</p></div>';
        $output .= wp_login_form('echo=0&redirect='. site_url());
        $output .= '<a href="'. wp_lostpassword_url( add_query_arg('action', 'recovered', get_permalink()) ) .'" title="Recover Lost Password">Lost Password?</a>';

        $content .= $output;
    }
    return $content;
}

Customize and add these to add your logo to the wp-login page for password recovery:

// calling it only on the login page
add_action( 'login_enqueue_scripts', 'custom_login_css', 10 );
function custom_login_css() { wp_enqueue_style( 'custom_login_css', get_template_directory_uri() .'/library/css/login.css', false ); }
// changing the logo link from wordpress.org to your site
add_filter( 'login_headerurl', 'custom_login_logo_url' );
function custom_login_logo_url() { return home_url(); }
// changing the alt text on the logo to show your site name
add_filter( 'login_headertitle', 'custom_login_title' );
function custom_login_title() { return get_option('blogname'); }

Login logo css:

.login h1 a {
    background: url(../images/login-logo.png) no-repeat top center;
    width: 274px;
    height: 63px;
    text-indent: -9999px;
    overflow: hidden;
    padding-bottom: 15px;
    display: block;
}

EDIT: I just implemented this on another site form scratch, and found the above "step further" to be more complete, and fixed small syntax errors in the "add_actions". Added some comments and a method to automatically add the login form to login page without a separate template file. The login form method should work in most instances, since it is attached to "the_content", it could cause and issue if you have more than one loop on the login page, just use a page-login.php template in that case.

4
  • 1
    Thanks, I will take a look at this (and see if I can make it work in conjunction with 3rd party login like Twitter and FB)
    – Steven
    Commented Jul 3, 2013 at 21:15
  • 1
    Jake - this is a nice complete solution. Thanks for sharing. +1 Commented Sep 29, 2013 at 21:39
  • This is basically wrapped into a plugin called Sewn In Template Login, a pretty complete, small plugin. wordpress.org/plugins/sewn-in-template-log-in
    – Jake
    Commented Jan 30, 2016 at 22:05
  • Nice, the only issue is that it doesn't actually throw out errors in the front-end....
    – Siyah
    Commented May 9, 2019 at 8:43
4

A solution for Szczepan Hołyszewski's point about empty fields in the accepted solution, the following jQuery will prevent going to the standard wp-login page: (add to login page template or footer.php)

jQuery("#loginform-custom").submit(function(){
     var isFormValid = true;
       jQuery("input").each(function()
       {
       if (jQuery.trim($(this).val()).length == 0){
       jQuery(this).addClass("submit_error");
       isFormValid = false;
       }     
     else {
     jQuery(this).removeClass("submit_error");
     }
     });
     return isFormValid;
});
2

The following worked for me. Both of these hooks can be found within the function wp_authenticate within wp-includes/puggabel.php.

  1. Check via the authenticate filter if the login form is missing the username or password.
function wpse_15633_redirectMissingDataLoginForm($user, $username, $password)
{
    $errors = [];
    empty(trim($password)) && $errors[] = 'password_empty';
    empty(trim($username)) && $errors[] = 'username_empty';

    if (! empty($errors)) {

        $redirect_url = add_query_arg([
            'errors' => join(',', $errors),
        ], site_url('login', 'login_post'));

        if (wp_safe_redirect($redirect_url)) {
            exit;
        }
    }
    return $user;
}
add_filter('authenticate', 'wpse_15633_redirectMissingDataLoginForm', 10, 3);
  1. Check via the wp_login_failed action if the authentication of the supplied username and password has failed.
function wpse_15633_redirectFailedLoginForm($username, $error)
{
    $redirect_url = add_query_arg([
        'errors' => $error->get_error_code(),
    ], site_url('login', 'login_post'));

    if (wp_safe_redirect($redirect_url)) {
        exit;
    }
}
add_action('wp_login_failed', 'wpse_15633_redirectFailedLoginForm', 10, 2);
0

One addition to Alexey's answer. You can add a jquery function to check that one of the fields is not blank. That way the form will not submit unless there is something to check, preventing WordPress from redirecting to /wp-login.php.

  <script>
        $("#wp-submit").click(function() {
          var user = $("input#user_login").val();
            if (user == "") {
            $("input#user_login").focus();
            return false;
          }
         });
  </script>   

Still not sure how to fix the forgot password aspect

2
  • 3
    Please be aware that WordPress loads jQuery in "No Conflict" mode. The $ alias does not work.
    – s_ha_dum
    Commented Feb 26, 2013 at 5:38
  • You also have to consider that user hits [enter] and not clicking t he login button. Also, you need to check for blank password as well.
    – Steven
    Commented Feb 26, 2013 at 11:07
0

Just adding to @alexey's helpful answer and adding something to deal with the issue that others have mentioned.

His code to put in the functions.php file:

add_action( 'wp_login_failed', 'my_front_end_login_fail' );  // hook failed login

function my_front_end_login_fail( $username ) {
   $referrer = $_SERVER['HTTP_REFERER'];  // where did the post submission come from?
   // if there's a valid referrer, and it's not the default log-in screen
   if ( !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') ) {
      wp_redirect( $referrer . '?login=failed' );  // let's append some information (login=failed) to the URL for the theme to use
      exit;
   }
}

However, as other's have noted, if the fields are empty, Wordpress doesn't bother validating and users still end up at the backend login screen.

To workaround this, I add a script right after the form creation which adds required to the inputs so that the browser will stop any submission if the fields are blank.

On the page where your form is:

<?php 
$args = array(
    'form_id' => 'YOUR-FORM-NAME',
); 
wp_login_form( $args );
?>
<script>
if(jQuery('form#YOUR-FORM-NAME').length) { 
    jQuery('form#YOUR-FORM-NAME input').each(function() {
        jQuery(this).attr("required", true);
    });
}
</script>
-1
jQuery("#loginform-custom").submit(function(){
     var isFormValid = true;
       jQuery("input").each(function()
       {
       if (jQuery.trim($(this).val()).length == 0){
       jQuery(this).addClass("submit_error");
       isFormValid = false;
       }     
     else {
     jQuery(this).removeClass("submit_error");
     }
     });
     return isFormValid;
});
1
  • 1
    Please edit your answer, and add an explanation: why could that solve the problem?
    – fuxia
    Commented May 11, 2018 at 13:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.