Ban a user and end their session

I’m working on a plugin derived from this tutorial. So far, the plugin adds a checkbox on a user’s profile edit page where admins can ban the user.

checkbox

Read More

If checked, the user will receive a message upon logging in:

banned

It works fine. The problem is, if the user is already logged in (has an active session) and gets banned, the user can continue to interact with the site until either the session ends or the user logs out.

How do I end the user’s session upon banning so the user is forced out?

Here is the code:

/**
 * Admin init
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_admin_init(){

    // Edit user profile
    add_action( 'edit_user_profile', 'rc_edit_user_profile' );
    add_action( 'edit_user_profile_update', 'rc_edit_user_profile_update' );

}
add_action('admin_init', 'rc_admin_init' );


/**
 * Adds custom checkbox to user edition page
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_edit_user_profile() {
    if ( !current_user_can( 'edit_users' ) ) {
        return;
    }

    global $user_id;

    // User cannot disable itself
    $current_user = wp_get_current_user();
    $current_user_id = $current_user->ID;
    if ( $current_user_id == $user_id ) {
        return;
    }
    ?>
    <h3>Ban user</h3>
    <table class="form-table">
    <tr>
        <th scope="row"></th>
        <td><label for="rc_ban"><input name="rc_ban" type="checkbox" id="rc_ban"  /> Check to ban user.</label></td>
    </tr>
    </table>
    <?php
}


/**
 * Save custom checkbox
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_edit_user_profile_update() {

    if ( !current_user_can( 'edit_users' ) ) {
        return;
    }

    global $user_id;

    // User cannot disable itself
    $current_user    = wp_get_current_user();
    $current_user_id = $current_user->ID;
    if ( $current_user_id == $user_id ) {
        return;
    }

    // Lock
    if( isset( $_POST['rc_ban'] ) && $_POST['rc_ban'] = 'on' ) {
        rc_ban_user( $user_id );
    } else { // Unlock
        rc_unban_user( $user_id );
    }

}


/**
 * Ban user
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_ban_user( $user_id ) {

    $old_status = rc_is_user_banned( $user_id );

    // Update status
    if ( !$old_status ) {
        update_user_option( $user_id, 'rc_banned', true, false );
    }
}


/**
 * Un-ban user
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_unban_user( $user_id ) {

    $old_status = rc_is_user_banned( $user_id );

    // Update status
    if ( $old_status ) {
        update_user_option( $user_id, 'rc_banned', false, false );
    }
}


/**
 * Checks if a user is already banned
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_is_user_banned( $user_id ) {
    return get_user_option( 'rc_banned', $user_id, false );
}


/**
 * Check if user is locked while login process
 *
 * @access      public
 * @since       1.0 
 * @return      void
*/
function rc_authenticate_user( $user ) {

    if ( is_wp_error( $user ) ) {
        return $user;
    }

    // Return error if user account is banned
    $banned = get_user_option( 'rc_banned', $user->ID, false );
    if ( $banned ) {
        return new WP_Error( 'rc_banned', __('<strong>ERROR</strong>: This user account is disabled.', 'rc') );
    }

    return $user;
}

add_filter( 'wp_authenticate_user', 'rc_authenticate_user', 1 );

So the ending of the session should go in the rc_ban_user() function.

EDIT: Full plugin posted below.

Related posts

4 comments

  1. Use wp_logout(). It calls wp_clear_auth_cookie() and invalidates the current log-in information immediately.

    Sample code, not tested:

    add_action( 'init', 'log_out_banned_user' );
    
    function log_out_banned_user() {
        if ( ! is_user_logged_in() )
            return;
    
        $user = wp_get_current_user();
    
        if ( ! get_user_option( 'rc_banned', $user->ID, false ) )
            return;
    
        wp_logout();
        wp_redirect( home_url( '/' ) );
        exit;
    }
    
  2. While toscho’s method works, a simpler approach might be to use the authenticate hook to prevent them from authenticating via cookie, or any other means, in a more direct fashion.

    Totally untested code. Should work though.

    // the priority of 999 is to ensure it's last in the auth chain
    add_filter('authenticate', 'force_fail_banned_users', 999, 3); 
    
    function force_fail_banned_users($user, $username, $password) {
        if ( ! is_a($user, 'WP_User') ) { 
            // we only care about actual users who already auth'd okay via some means
            return $user; 
        }
    
        if ( rc_is_user_banned( $user->ID ) ) {
            // user is banned, so return a failure case
            return new WP_Error('banned_user', 'Banned message goes here.');
        }
    
        // user not banned, so return the user normally
        return $user;
    }
    

    The authenticate filter chain lets you decide whether or not a user is authenticated at every possible opportunity for them to authenticate. Returning a value WP_User logs them in. Returning a WP_Error of any sort fails their authentication attempt, no matter how it was done, whether via username/password or via cookie.

  3. I also write similar plugin and already published it on WordPress.org. I think the best solution drop user session immediately then administrator click “ban” (block) button (link). This possible with WP_Session_Tokens class:

    $manager = WP_Session_Tokens::get_instance( $user_id );
    $manager->destroy_all();
    

    And even if user currently authorised and some pages from /wp-admin/ opened they will be force log out because we already drop sessions (immediately).

    Source code: https://wordpress.org/plugins/mark-user-as-spammer/

  4. The plugin is now ready to be used and functions elegantly. Thanks to Remi for the original tutorial and toscho (the bot) for the working solution to end users session upon banning.

    Future Updates

    I plan the following for future updates:

    • Option to delete a user’s comments or/and posts upon banning.
    • Add a custom ban message for specific user.
    • Allow admins to ban multiple users on users listing page in wp-admin.

    Leave a comment if you have any update suggestions. I will edit this answer whenever there are any updates to the plugin.

    Ban Users Plugin

    Create a folder named ban-users in your plugin folder and create a file named ban-users.php with the following code:

    <?php
    /*
    Plugin Name: Ban Users
    Plugin URI: http://wordpress.stackexchange.com/questions/123902/ban-a-user-and-end-their-session
    Description: Allows you to ban users
    Author: Christine Cooper, Remi, toscho
    Version: 1.1
    Author URI: http://wordpress.stackexchange.com/questions/123902/ban-a-user-and-end-their-session
    */
    
    
    /**
     * Admin init
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_admin_init(){
    
        // Edit user profile
        add_action( 'edit_user_profile', 'rc_edit_user_profile' );
        add_action( 'edit_user_profile_update', 'rc_edit_user_profile_update' );
    
    }
    add_action('admin_init', 'rc_admin_init' );
    
    
    /**
     * Adds custom checkbox to user edition page
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_edit_user_profile() {
        if ( !current_user_can( 'edit_users' ) ) {
            return;
        }
    
        global $user_id;
    
        // User cannot disable itself
        $current_user = wp_get_current_user();
        $current_user_id = $current_user->ID;
        if ( $current_user_id == $user_id ) {
            return;
        }
        ?>
        <h3>Ban User</h3>
        <table class="form-table">
        <tr>
            <th scope="row"></th>
            <td><label for="rc_ban"><input name="rc_ban" type="checkbox" id="rc_ban" <?php if ( get_user_option( 'rc_banned', $user_id, false ) ) { echo 'checked'; } ?> /> Check to ban user </label></td>
        </tr>
        </table>
        <?php
    }
    
    
    /**
     * Save custom checkbox
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_edit_user_profile_update() {
    
        if ( !current_user_can( 'edit_users' ) ) {
            return;
        }
    
        global $user_id;
    
        // User cannot disable itself
        $current_user    = wp_get_current_user();
        $current_user_id = $current_user->ID;
        if ( $current_user_id == $user_id ) {
            return;
        }
    
        // Lock
        if( isset( $_POST['rc_ban'] ) && $_POST['rc_ban'] = 'on' ) {
            rc_ban_user( $user_id );
        } else { // Unlock
            rc_unban_user( $user_id );
        }
    
    }
    
    
    /**
     * Ban user
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_ban_user( $user_id ) {
    
        $old_status = rc_is_user_banned( $user_id );
    
        // Update status
        if ( !$old_status ) {
            update_user_option( $user_id, 'rc_banned', true, false );
        }
    }
    
    
    /**
     * Un-ban user
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_unban_user( $user_id ) {
    
        $old_status = rc_is_user_banned( $user_id );
    
        // Update status
        if ( $old_status ) {
            update_user_option( $user_id, 'rc_banned', false, false );
        }
    }
    
    
    /**
     * Checks if a user is already banned
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_is_user_banned( $user_id ) {
        return get_user_option( 'rc_banned', $user_id, false );
    }
    
    
    
    /**
     * End a users active session if they are banned
     * By toscho http://wordpress.stackexchange.com/a/123903/24875
     *
     * @access      public
     * @since       1.1 
     * @return      void
    */
    add_action( 'init', 'log_out_banned_user' );
    
    function log_out_banned_user() {
        if ( ! is_user_logged_in() )
            return;
    
        $user = wp_get_current_user();
    
        if ( ! get_user_option( 'rc_banned', $user->ID, false ) )
            return;
    
        wp_logout();
        wp_redirect( home_url( '/' ) );
        exit;
    }
    
    
    
    /**
     * Check if user is locked while login process
     *
     * @access      public
     * @since       1.0 
     * @return      void
    */
    function rc_authenticate_user( $user ) {
    
        if ( is_wp_error( $user ) ) {
            return $user;
        }
    
        // Return error if user account is banned
        $banned = get_user_option( 'rc_banned', $user->ID, false );
        if ( $banned ) {
            return new WP_Error( 'rc_banned', __('<strong>ERROR</strong>: Your user account has been disabled.', 'rc') );
        }
    
        return $user;
    }
    
    add_filter( 'wp_authenticate_user', 'rc_authenticate_user', 1 );
    

Comments are closed.