By Vayu


2010-11-24 10:34:04 8 Comments

I have set up a WordPress site for a client. The client has the Editor role, however I have installed the Members plugin and given the client the capability to add new users to the WP admin. This is working just fine.

The question I have is that I would like for the client to have the ability to create new user as with the roles of a Contributor, Subscriber, Editor and Author, but NOT Administrator. The new users the client creates should not have the Administrator role. Is it possible to hide this option somehow?

Thanks Vayu

4 comments

@rassoh 2019-04-25 21:56:59

@John P Blochs solution still works fine, but I thought I would throw in my little filter for 'map_meta_cap' as well. Just a little shorter and cleaner, at least for my eyes ;)

function my_map_meta_cap( $caps, $cap, $user_id, $args ) {
  $check_caps = [
    'edit_user',
    'remove_user',
    'promote_user',
    'delete_user',
    'delete_users'
  ];
  if( !in_array( $cap, $check_caps ) || current_user_can('administrator') ) {
    return $caps;
  }
  $other = get_user_by( 'id', $args[0] ?? false ); // PHP 7 check for variable in $args... 
  if( $other && $other->has_cap('administrator') ) {
    $caps[] = 'do_not_allow';
  }
  return $caps;
}
add_filter('map_meta_cap', 'my_map_meta_cap', 10, 4 );

@John P Bloch 2010-11-24 22:07:34

It's actually pretty easy. You need to filter into map_meta_caps and stop editors from creating/editing admins, and remove the administrator role from the 'editable roles' array. This class, as a plugin or in your theme's functions.php file would do it:

class JPB_User_Caps {

  // Add our filters
  function __construct(){
    add_filter( 'editable_roles', array($this, 'editable_roles'));
    add_filter( 'map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
  }

  // Remove 'Administrator' from the list of roles if the current user is not an admin
  function editable_roles( $roles ){
    if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
      unset( $roles['administrator']);
    }
    return $roles;
  }

  // If someone is trying to edit or delete and admin and that user isn't an admin, don't allow it
  function map_meta_cap( $caps, $cap, $user_id, $args ){

    switch( $cap ){
        case 'edit_user':
        case 'remove_user':
        case 'promote_user':
            if( isset($args[0]) && $args[0] == $user_id )
                break;
            elseif( !isset($args[0]) )
                $caps[] = 'do_not_allow';
            $other = new WP_User( absint($args[0]) );
            if( $other->has_cap( 'administrator' ) ){
                if(!current_user_can('administrator')){
                    $caps[] = 'do_not_allow';
                }
            }
            break;
        case 'delete_user':
        case 'delete_users':
            if( !isset($args[0]) )
                break;
            $other = new WP_User( absint($args[0]) );
            if( $other->has_cap( 'administrator' ) ){
                if(!current_user_can('administrator')){
                    $caps[] = 'do_not_allow';
                }
            }
            break;
        default:
            break;
    }
    return $caps;
  }

}

$jpb_user_caps = new JPB_User_Caps();

EDIT

Ok, so I took a look into why it was letting user deletion slip through. It looks like delete_user is handled slightly differently from edit_user; I've modified the map_meta_cap method to work around this. I've tested on 3.0.3 and this will prevent anybody but administrators from actually deleting, editing, or creating an administrator.

EDIT 2

I updated the code to reflect @bugnumber9 's answer below. Please go give that answer an upvote!

@somatic 2010-12-15 12:47:17

Can someone verify that this code prevents others from deleting admins? I can't reproduce that behaviour. It does prevent them from editing, but the "delete" hover link still appears, and WP allows the user to go through with the deletion...

@John P Bloch 2010-12-20 17:24:34

@somatic - you were spot on. Thanks for pointing that out. The issue is fixed now.

@v3nt 2011-07-27 12:16:42

i need to do this also but unsure where i put this code! In the functions.php? If not how could it be done to work from the functions.php? best, Dc

@John P Bloch 2011-07-27 14:02:44

@daniel read the first paragraph.

@user9984 2011-11-04 03:32:32

if anyone else is looking to restrict additional roles you just need to add an additional line per role under this line: unset( $roles['administrator']); … so after this line you can add for example: unset( $roles['editor']);

@Jon Raasch 2012-09-13 23:11:39

Worked great in 3.4.1, thanks! Make sure to add capabilities for create_users, delete_users, add_users, remove_users, edit_users, list_users and promote_users

@Eric 2017-07-11 06:40:24

Great code. For anyone using this, be sure to see the small tweak below by @bugnumber9. (Maybe John P Block will edit his code?)

@bugnumber9 2017-07-02 09:51:59

Despite of being ~7 years old, this thread can be googled easily and still provides a working solution. I mean the code provided by @John P Bloch.

That said, under PHP 7 it produces a non-critical error (PHP Deprecated) as follows:

PHP Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; JPB_User_Caps has a deprecated constructor in ...

In order to fix this simply replace this piece:

// Add our filters
  function JPB_User_Caps(){
    add_filter( 'editable_roles', array(&$this, 'editable_roles'));
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'),10,4);
  }

with this:

// Add our filters
  function __construct() {
    add_filter( 'editable_roles', array(&$this, 'editable_roles') );
    add_filter( 'map_meta_cap', array(&$this, 'map_meta_cap'), 10, 4 );
  }

This will fix the problem.

@John P Bloch 2017-07-18 03:04:09

Thank you thank you thank you. I appreciate the dedication to code quality and have updated my answer so that casual googlers will also get the memo. You rock!

@SilbinaryWolf 2014-11-13 23:47:53

I was looking for a solution where the Editor could edit only menus AND create/edit users without needing a plugin. So I ended up making it for those who are interested.

// Customizes 'Editor' role to have the ability to modify menus, add new users
// and more.
class Custom_Admin {
    // Add our filters
    public function __construct(){
        // Allow editor to edit theme options (ie Menu)
        add_action('init', array($this, 'init'));
        add_filter('editable_roles', array($this, 'editable_roles'));
        add_filter('map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
    }

    public function init() {
        if ($this->is_client_admin()) {
            // Disable access to the theme/widget pages if not admin
            add_action('admin_head', array($this, 'modify_menus'));
            add_action('load-themes.php', array($this, 'wp_die'));
            add_action('load-widgets.php', array($this, 'wp_die'));
            add_action('load-customize.php', array($this, 'wp_die'));

            add_filter('user_has_cap', array($this, 'user_has_cap'));
        }
    }

    public function wp_die() {
        _default_wp_die_handler(__('You do not have sufficient permissions to access this page.'));
    }

    public function modify_menus() 
    {
        remove_submenu_page( 'themes.php', 'themes.php' ); // hide the theme selection submenu
        remove_submenu_page( 'themes.php', 'widgets.php' ); // hide the widgets submenu

        // Appearance Menu
        global $menu;
        global $submenu;
        if (isset($menu[60][0])) {
            $menu[60][0] = "Menus"; // Rename Appearance to Menus
        }
        unset($submenu['themes.php'][6]); // Customize
    }

    // Remove 'Administrator' from the list of roles if the current user is not an admin
    public function editable_roles( $roles ){
        if( isset( $roles['administrator'] ) && !current_user_can('administrator') ){
            unset( $roles['administrator']);
        }
        return $roles;
    }

    public function user_has_cap( $caps ){
        $caps['list_users'] = true;
        $caps['create_users'] = true;

        $caps['edit_users'] = true;
        $caps['promote_users'] = true;

        $caps['delete_users'] = true;
        $caps['remove_users'] = true;

        $caps['edit_theme_options'] = true;
        return $caps;
    }

    // If someone is trying to edit or delete and admin and that user isn't an admin, don't allow it
    public function map_meta_cap( $caps, $cap, $user_id, $args ){
        // $args[0] == other_user_id
        foreach($caps as $key => $capability)
        {
            switch ($cap)
            {
                case 'edit_user':
                case 'remove_user':
                case 'promote_user':
                    if(isset($args[0]) && $args[0] == $user_id) {
                        break;
                    }
                    else if(!isset($args[0])) {
                        $caps[] = 'do_not_allow';
                    }
                    // Do not allow non-admin to edit admin
                    $other = new WP_User( absint($args[0]) );
                    if( $other->has_cap( 'administrator' ) ){
                        if(!current_user_can('administrator')){
                            $caps[] = 'do_not_allow';
                        }
                    }
                    break;
                case 'delete_user':
                case 'delete_users':
                    if( !isset($args[0])) {
                        break;
                    }
                    // Do not allow non-admin to delete admin
                    $other = new WP_User(absint($args[0]));
                    if( $other->has_cap( 'administrator' ) ){
                        if(!current_user_can('administrator')){
                            $caps[] = 'do_not_allow';
                        }
                    }
                    break;
                break;
            }
        }
        return $caps;
    }

    // If current user is called admin or administrative and is an editor
    protected function is_client_admin() {
        $current_user = wp_get_current_user();
        $is_editor = isset($current_user->caps['editor']) ? $current_user->caps['editor'] : false;
        return ($is_editor);
    }
}
new Custom_Admin();

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] Remove admin AND editor from the "change role to" menu in user listing

  • 2015-05-28 14:09:57
  • Ismael Latorre
  • 2627 View
  • 3 Score
  • 1 Answer
  • Tags:   admin user-roles

3 Answered Questions

1 Answered Questions

[SOLVED] How to hide a specific user role option in a user role list?

3 Answered Questions

[SOLVED] How to get all users with Author role capabilities?

2 Answered Questions

4 Answered Questions

2 Answered Questions

[SOLVED] How can I allow user to select minimum privilege smartly

  • 2015-11-25 02:27:29
  • Abirvab
  • 33 View
  • 2 Score
  • 2 Answer
  • Tags:   user-roles

1 Answered Questions

[SOLVED] How to get a users list by who created them?

Sponsored Content