14

I have three extra roles in my site.

  1. Doctor
  2. Receptionist
  3. Guest

those roles are added by following code:

* adding Doctor role */
$doctor_role = add_role('Doctor', __('Doctor'), array('read'=>'true'));

/* adding Receptionist role */
$receptionist_role = add_role('Receptionist', __('Receptionist'), array('read'=>'true'));

/* adding Guest role */
$guest_role = add_role('Guest', __('Guest'), array('read'=>'true'));

By default Administrator role create all other roles. But I want to limit this assigning role by user level. What I mean is:

  1. Administrator - should be able to create all role users - possible by default.
  2. Doctor - should be able to create Receptionist and Guest role users ONLY
  3. Receptionist - should be able to create Guest role users ONLY
  4. Guest - Not allowed to create any users.

How can do this? Better if I can achieve this without using any plugins.

23

Firstly, you need to add the following capabilities to the Doctor and Receptionist role:

  • list_users
  • edit_users
  • create_users
  • delete_users

Now we can get to work with controlling which users they can create/edite/delete. Let's start with a "helper" function that will return which roles a user is allowed to edit:

/**
 * Helper function get getting roles that the user is allowed to create/edit/delete.
 *
 * @param   WP_User $user
 * @return  array
 */
function wpse_188863_get_allowed_roles( $user ) {
    $allowed = array();

    if ( in_array( 'administrator', $user->roles ) ) { // Admin can edit all roles
        $allowed = array_keys( $GLOBALS['wp_roles']->roles );
    } elseif ( in_array( 'Doctor', $user->roles ) ) {
        $allowed[] = 'Receptionist';
        $allowed[] = 'Guest';
    } elseif ( in_array( 'Receptionist', $user->roles ) ) {
        $allowed[] = 'Guest';
    }

    return $allowed;
}

And to set which roles they can assign a user:

/**
 * Remove roles that are not allowed for the current user role.
 */
function wpse_188863_editable_roles( $roles ) {
    if ( $user = wp_get_current_user() ) {
        $allowed = wpse_188863_get_allowed_roles( $user );

        foreach ( $roles as $role => $caps ) {
            if ( ! in_array( $role, $allowed ) )
                unset( $roles[ $role ] );
        }
    }

    return $roles;
}

add_filter( 'editable_roles', 'wpse_188863_editable_roles' );

And finally, limit which users they can edit/delete based on their role:

/**
 * Prevent users deleting/editing users with a role outside their allowance.
 */
function wpse_188863_map_meta_cap( $caps, $cap, $user_ID, $args ) {
    if ( ( $cap === 'edit_user' || $cap === 'delete_user' ) && $args ) {
        $the_user = get_userdata( $user_ID ); // The user performing the task
        $user     = get_userdata( $args[0] ); // The user being edited/deleted

        if ( $the_user && $user && $the_user->ID != $user->ID /* User can always edit self */ ) {
            $allowed = wpse_188863_get_allowed_roles( $the_user );

            if ( array_diff( $user->roles, $allowed ) ) {
                // Target user has roles outside of our limits
                $caps[] = 'not_allowed';
            }
        }
    }

    return $caps;
}

add_filter( 'map_meta_cap', 'wpse_188863_map_meta_cap', 10, 4 );
  • Perfect thanks a lot.. After I added capabilities and your code it works as we expected. But Doctors , Receptionist and Guest are unable to edit their own profile too. I want them to edit their own profile. How can I do that? – Riffaz Starr May 21 '15 at 5:24
  • hi TheDeadMedic.. Are u there? I've upvoted ur answer. could u plz look into my the above comment?? – Riffaz Starr May 22 '15 at 3:45
  • Check my revision. – TheDeadMedic May 22 '15 at 10:48
  • @TheDeadMedic Your code helped me a lot. I only have one trouble. I use this on a Multisite. And while this code solved my problem, it created another one. When logged in as the Super Administrator I cannot select any roles at all from the Super Admin's Network Pages. How do I solve this? – jockebq Mar 26 '18 at 13:25
  • 1
    This is a brilliant answer to the question. I found Wordpress' own documentation wholly lacking in this area, even full of grammatical errors. This is a really efficient solution to the problem. – Benji May 22 '18 at 20:45
0

The above answer worked great. However, the roles need to be lowercase for

function wpse_188863_get_allowed_roles( $user ) { }

For instance:

if ( in_array( 'administrator', $user->roles ) ) { // Admin can edit all roles
    $allowed = array_keys( $GLOBALS['wp_roles']->roles );
} elseif ( in_array( 'doctor', $user->roles ) ) {
    $allowed[] = 'receptionist';
    $allowed[] = 'guest';
} elseif ( in_array( 'receptionist', $user->roles ) ) {
    $allowed[] = 'guest';
}
  • The case of the roles should likely be lowercase in most instances. In the above example, both the slug and name are given using title case, so this is technically correct, although not recommended. – Benji May 22 '18 at 20:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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