Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am using this snippet to redirect failed logins to my custom page...

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') ) {
      $pos = strpos($referrer, '?login=failed');
        if($pos === false) {
            // add the failed
            wp_redirect( $referrer . '?login=failed' );  // let's append some     information (login=failed) to the URL for the theme to use
        }
        else {
            // already has the failed don't appened it again
            wp_redirect( $referrer );  // already appeneded redirect back
        }   
      exit;
   }
}

This works brilliantly but only if the users actually fails the login process ie; they enter an incorrect username or password.

If the user does any of the following then it doesn't work....

  • Enters no username
  • Enters no password
  • Enters nothing in either field

The URL returned does not have ?login=failed attatched to it which I guess is the reason the snippet isn't catching it. Anyone any ideas?

share|improve this question
    
I don't know how you are using this code (plugin etc), but be aware that the HTTP_REFERER variable is not reliable. –  vancoder Apr 12 '13 at 17:39

2 Answers 2

Managed to resolve this with the help of the following code from http://css.dzone.com/articles/create-your-own-wordpress

add_action( 'authenticate', 'pu_blank_login');
function pu_blank_login( $user ){
    // check what page the login attempt is coming from
    $referrer = $_SERVER['HTTP_REFERER'];
    $error = false;
    if($user == null || $_POST['pwd'] == '')
    {
        $error = true;
    }
    // check that were not on the default login page
    if ( !empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin') && $error ) {
        // make sure we don't already have a failed login attempt
        if ( !strstr($referrer, '?login=failed') ) {
            // Redirect to the login page and append a querystring of login failed
            wp_redirect( $referrer . '?login=failed_empty' );
        } else {
            wp_redirect( $referrer );
        }
    exit;
    }
}

This works perfectly in conjunction with my originally posted code and covers both failed login attempts and failed login attempts where the password and username fields are empty

EDIT

Actually scrap that, the snipped works but seems to stop me from logging in successfully, wierd...........

share|improve this answer
add_action( 'wp_authenticate', 'my_front_end_login_fail', 1, 2 );

function my_front_end_login_fail( $user, $pwd ) {
}

Did you noticed that the hook wp_authenticate takes two arguments? And did you know that you have to pass the number of arguments with the add_action() call?

From time to time you should have a look at the core files:

  $ignore_codes = array('empty_username', 'empty_password');

  if (is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes) ) {
    do_action('wp_login_failed', $username);
  }

The wp_login_failed hook is only executed when the username or userpassword is not empty.

So. Let's start from the beginning and cleanup some things:

add_action( 'wp_authenticate', 'my_front_end_login_fail', 1, 2 );
add_action( 'wp_login_failed', 'my_front_end_login_fail', 1, 1 );

function my_front_end_login_fail( $user, $pwd = '' ) {

    // reasons to stop here
    // $user is not empty
    // $user is not a wp-error object
    // $pwd is not empty
    if ( ! empty( $user ) && ! empty( $pwd ) && ! is_wp_error( $user ) )
        return false;

    // if a referer is set, use it. else setup the standard login file
    $referrer = ( isset( $_SERVER['HTTP_REFERER'] ) && ! empty( $_SERVER['HTTP_REFERER'] ) ) ?
        $_SERVER['HTTP_REFERER'] : home_url( 'wp-login.php' ); // take the safe one, use home_url()

    /*
     * since PHP5 we can parse an url
     * @see http://php.net/manual/en/function.parse-url.php
     *
     * parse_url( 'http://www.example.com/wp-login.php?login=failed&foo=bar' ) gives us something like that:
     *
     * array (
     *  'scheme' => 'http'
     *  'host'   => 'www.example.com'
     *  'path'   => '/wp-login.php'
     *  'query'  => 'login=failed&foo=bar'
     *  )
     */

    $parsed_url = parse_url( $referrer );

    /*
     * Another fine function is parse_str()
     * @see: http://php.net/manual/en/function.parse-str.php
     * 
     * parse( 'login=failed&foo=bar', $query ); results in
     * array(
     *  'login' => 'failed'
     *  'foo'   => 'bar'
     *  )
     *
     */
    parse_str( $parsed_url['query'], $query );

    // if there's a valid referrer, and it's not the default log-in screen
    if ( ! strstr( $parsed_url['path'], 'wp-login' ) && ! strstr( $parsed_url['path'], 'wp-admin' ) ) {


        // already has the failed don't appened it again
        $redirect_to = $referrer;

        if( ! isset( $query['login'] ) || 'failed' !== $query['login'] ) {
            // add the failed
            // but never ever use a simple string concaternation
            // what will result if the referer is 'example.com?foo=bar'?
            // it will result in 'example.com?foo=bar?login=failed' OUTCH!
            $redirect_to = add_query_arg( array( 'login' => 'failed_empty' ), $referrer );
        }

        // you don't want to redirect to google or somewhere else, you want to redirect to your
        // own domain. so use wp_safe_redirect()
        wp_safe_redirect( $redirect_to );
        exit;
    }

}

This is a bit tricky. We hook the function into two different actions. The first action passes two arguments, the second one only one. Our callback always takes two arguments, but if only one is passed, the second one is predefined with an empty string.

The rest of the function is explained in the comments.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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