Leave a Reply

7 comments

  1. 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.

  2. 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;
       }
    }
    
  3. 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. 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;
    });
    
  5. 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);
    
  6. 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

  7. 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;
    });