I'm trying to force the WordPress login function to fail on certain conditions. Basically, we have a situation where we have users that have allowed their accounts to expire in our membership environment. The idea is that if they try to login, it just fails their login because they won't be able to access anything anyhow so I figure we just let them know with a custom login_errors message.

The issue is that the user has to have a login error in order to make this happen (meaning they have to use an incorrect username/password combination). In this case, they would still have logins but they just don't have a valid membership to interact with the content on the site.

I'm intercepting the process using the wp_authenticate hook and I'm able to successfully grab the information from the user logging in but I can't seem to force it throw an error. If I return false or return new WP_Error() it doesn't work. If I change the credentials in the flow, that doesn't seem to matter either.

Any ideas on how to force it to fail the login and redirect to the login page with the new error message?

  • maybe try using the wp_login_errors filter for this?
    – majick
    Commented Jul 22, 2016 at 8:15
  • 1
    @majick That hook allows you to filter and react to login errors after they happen. The OP wants to throw a new error. Commented Jul 22, 2016 at 8:23
  • yes true, I didn't really elaborate did I, I was really meaning save the error somehow (globally?) and check for that in the provided filter.
    – majick
    Commented Jul 22, 2016 at 8:26

1 Answer 1


A long time since I last did this on a site, but this is the gist.

You want to hook into wp_authenticate_user which will fire after WP has tried to authenticate the user but before logging the user in.

You'll receive either a WP_User object or a WP_Error object and you should return either a WP_User object (if your own authentication check succeeds) or a WP_Error object (if your auth fails). Something like this should work:

function wpse_232915_authenticate_user( $user ) {

    /* already failed login attempt
       return existing error or you'll subvert the login process:
    if ( is_wp_error( $user ) ) {
        return $user;

    $failure = your_own_authentication_tests( $user->ID ); // test if the user should be allowed in by your own rules

    if ( $failure ) {
        return new WP_Error( 'wpse_232915_user_expired', 'Sorry, you have expired!' );

    return $user;

add_filter( 'wp_authenticate_user', 'wpse_232915_authenticate_user' );

Depending on how complex your test is, you could return the WP_Error object from that function rather than true/false as I've assumed here.

I'm not handy enough with WP_Error to know whether you can chain the errors, or whether the login error notification box would be happy with that, but that's an improvement that might be worth looking into.

  • I edited the answer. By this point of the process, the $user object doesn't actually return a WP_Error() yet (I tested it). I've edited to run wp_check_password() which returns false on a failed login attempt. This is assuming that we want that to be the very first check. In my case, if they have the wrong username or password, I want it to error out at that point. If they validate correctly then I'll put them through the rest of the flow. Commented Jul 22, 2016 at 21:37
  • Ah. Cool. Glad you got it working. I'll have to have a look at source - if the default password check is added with the same hook then just adjusting the priority might be tidier. Commented Jul 22, 2016 at 21:47
  • Good call on the priority. I know when I investigate the tracing, it hits the wp_signon then the wp_authenticate_username_password and then wp_authenticate so you may be right there. It may work if we adjust it before the username_password function. I may have a sec to try it out here in a minute. Commented Jul 22, 2016 at 22:36
  • I just tried with priorities and it didn't do the trick unfortunately. I agree though, there probably is a cleaner more 'WordPress-friendly' way to do this but this validation works for me for now. Commented Jul 22, 2016 at 22:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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