Question

To reduce spam registrations, users are assigned the pending role until they're vetted (at which point they're assigned the subscriber role). The pending role has no capabilities. When pending users log in, I want to log them out immediately and direct them to a page with an explanation. First, I tried the following:

function logout_pending_users() {
    $current_user = wp_get_current_user() ;
    if ( ! $current_user->has_cap( 'read' ) ) {
        $url = 'https://example.com/pending/' ;
        wp_redirect( $url ) ;
        wp_logout() ;
        exit ;
    }
} add_action('wp_login', 'logout_pending_users') ;

Result: both pending and subscriber users are logged out. I tried inverting the order of wp_redirect() and wp_logout():

        $url = 'https://example.com/pending/' ;
        wp_logout() ;
        wp_redirect( $url ) ;
        exit ;

Same result. Then I tried checking roles instead of caps (I know, you shouldn't...):

function logout_pending_users() {
    $current_user = wp_get_current_user() ;
    $role = $current_user->roles[0] ;
    if ( $role === 'pending' ) {
        $url = 'https://example.com/pending/' ;
        wp_redirect( $url ) ;
        wp_logout() ;
        exit ;
    }
} add_action('wp_login', 'logout_pending_users') ;

Again, same result. Next, I tried something based on an example on the WP Developer site:

function logout_pending_users() {
    $current_user = wp_get_current_user() ;
    if ( ! $current_user->has_cap( 'read' ) ) {
        wp_logout() ;
    }
} add_action('wp_login', 'logout_pending_users');

function redirect_pending_users() {
    $current_user = wp_get_current_user() ;
    if ( ! $current_user->has_cap( 'read' ) ) {
        $url = 'https://example.com/pending/' ;
        wp_redirect( $url ) ;
        exit;
} add_action( 'wp_logout()', 'redirect_pending_users');

Result: both pending and subscriber users are stuck at the login page, with URL: https://example.com/wp-login.php?redirect_to=https%3A%2F%2Fexample.com%2Fwp-admin%2Fprofile.php&reauth=1

During each attempt, I verified that the pending role has no read capacity (or any capacity), and that the subscriber role does. I also verified that $current_user->roles[0] does, indeed, contain the correct role.

What am I missing? Is there another way? Thank you for any help!

Was it helpful?

Solution

There are a couple of "timing" issues you're running into here.

When you're calling wp_get_current_user() this isn't really available at the moment of logging in, so to capture the logging-in user, you have to use a slightly different approach.

The same is with logout, as it uses the same method of getting the current user.

In the solution below you're capturing the logging-in user directly from the wp_login hook, and then instead of calling wp_logout(), you're calling the actual functions that do the logging-out for you. And, instead of adding multiple hooks, you're doing it all within the one hook: wp_login

There's also a sanity check to ensure the $user is actually an \WP_User object, or you'll get a fatal error on checking the capability.

function logout_pending_users( $username, $user ) {
    
    if ( $user instanceof \WP_User && !$user->has_cap( 'read' ) ) {

        wp_destroy_current_session();
        wp_clear_auth_cookie();
        wp_set_current_user( 0 );
        
        wp_redirect( 'https://example.com/pending/' );
        
        exit;
    }
}
add_action( 'wp_login', 'logout_pending_users', 100, 2 );
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top