0

I have this function which prevents my three custom roles (used for multisite admins) to create users with other roles than "User". The three roles I have made are called, Basic, Standard and Premium, and they are only allowed to create users on their multisite with the role "User". This is what the function looks like:

function restrict_roles_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( 'basic', $user->roles ) ) { // If role is "Basic"
        $allowed[] = 'user'; // Allow only role User
         /* $allowed[] = 'additionalrole'; */ // Allow only role additionalrole
   } elseif ( in_array( 'standard', $user->roles ) ) { // If role is "Standard"
        $allowed[] = 'user'; // Allow only role User
    } elseif ( in_array( 'premium', $user->roles ) ) { // If role is "Premium"
        $allowed[] = 'user'; // Allow only role User
    }

    return $allowed;
}

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

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

    return $roles;
}
add_filter( 'editable_roles', 'restrict_roles_editable_roles' );

/* Prevent users deleting/editing users with a role outside their allowance. */
function restrict_roles_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 = restrict_roles_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', 'restrict_roles_map_meta_cap', 10, 4 );

if ( ! function_exists( 'unregister_post_type' ) ) :
function unregister_post_type() {
    global $wp_post_types;
    if ( isset( $wp_post_types[ 'post' ] ) ) {
        unset( $wp_post_types[ 'post' ] );
        return true;
    }
    return false;
}
endif;

add_action('init', 'unregister_post_type',100);

This works fantastic except one part. When I am logged in as a super admin, and I Edit a site in the network there is an ability to add a new user or add an existing user. I cannot do this, as the function above somehow breaks the dropdown User role selection for Super Admin. But I cannot figure out why?

  • Hi. Are you sure that this code breaks that? Did you try removing the code to see if it fixes it? Because I added this code to my multisite and both dropdown menus seem fine to me. I haven't added actual users though. Also what is the problem exactly with the dropdown? – Nikolay May 2 '18 at 10:00
  • Yes, sadly! If I remove the function I can go to Network Admin->All Sites->Edit Example site->Users and here I will be able to Add new user or Add existing user, and the dropdown called Role will let me select the roles. But with the function enabled the dropdown is all empty! – jockebq May 2 '18 at 10:38
  • Fine, I will give you an answer below without testing it unfortunately, hope it works for you. – Nikolay May 2 '18 at 11:22
1

I cannot test this, since I am not getting your problem when I add the code, but try these changes below. I have made the code to work only if the page is not in the network admin. Please test it as a super admin and as other users to verify that it works well.

function restrict_roles_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( 'basic', $user->roles ) ) { // If role is "Basic"
        $allowed[] = 'user'; // Allow only role User
         /* $allowed[] = 'additionalrole'; */ // Allow only role additionalrole
   } elseif ( in_array( 'standard', $user->roles ) ) { // If role is "Standard"
        $allowed[] = 'user'; // Allow only role User
    } elseif ( in_array( 'premium', $user->roles ) ) { // If role is "Premium"
        $allowed[] = 'user'; // Allow only role User
    }

    return $allowed;
}

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

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

    return $roles;
}

/* Prevent users deleting/editing users with a role outside their allowance. */
function restrict_roles_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 = restrict_roles_get_allowed_roles( $the_user );

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

    return $caps;
}

if ( ! function_exists( 'unregister_post_type' ) ) :
function unregister_post_type() {
    global $wp_post_types;
    if ( isset( $wp_post_types[ 'post' ] ) ) {
        unset( $wp_post_types[ 'post' ] );
        return true;
    }
    return false;
}
endif;

if ( ! is_network_admin() ) {
    add_action('init', 'unregister_post_type',100);
    add_filter( 'map_meta_cap', 'restrict_roles_map_meta_cap', 10, 4 );
    add_filter( 'editable_roles', 'restrict_roles_editable_roles' );
}
  • I tried it now, and this fixes the problem as super admin, I can now see and select all user roles. But this breaks it for everyone else. So now I am not able to see any roles at all when trying to add a user as a site admin (role: basic, standard or premium). So the dropdown is now empty for the site admins instead! – jockebq May 2 '18 at 11:28
  • @jockebq Interesting. This should happen only if the administrator you are testing with is also a super admin. Please verify that he is not. Also I have now changed the answer with new code, that checks based on the URL, not the role. So this should work then. Please try. – Nikolay May 2 '18 at 12:54
  • This works very well! Thank you so much for solving this. Weird that it did not work correctly before, because as you said, it should have! – jockebq May 2 '18 at 13:01
  • @jockebq Awesome. By the way, the correct way to check if it is a network admin page is to use this function is_network_admin(). Can you try changing the whole line with the IF that checks the server variable to this and let me know if it works to edit the answer: if ( ! is_network_admin() ) { – Nikolay May 2 '18 at 13:40
  • You mean this line right? if ( strpos( $_SERVER['REQUEST_URI'], '/network/' ) === false ) { I replaced it, and it still works perfectly! – jockebq May 2 '18 at 13:59

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.