Allow roles below admin to add subscribers only

I want to give a group of user types (Editor + a custom role) the add_users /create_users capability. The only catch is that I wanted to limit that capability to adding ‘subscriber’ type users only, and nothing above that. Is there a way to do this?

Related posts

Leave a Reply

2 comments

  1. This first step to making this happen is add the capability to create_users to a given role. You do this be calling get_role, then using the add_cap method. This only needs to be done once. Here’s an example that does it on plugin activation.

    <?php
    register_activation_hook( __FILE__, 'wpse42003_activation' );
    function wpse42003_activation()
    {
        foreach( array( 'editor', 'your_custome_role' ) as $r )
        {
            $role = get_role( $r );
            if( $role )
                $role->add_cap( 'create_users' );
        }
    }
    

    If you do that, you probably want to make sure to undo it on plugin deactivation with remove_cap.

    <?php
    register_deactivation_hook( __FILE__, 'wpse42003_deactivation' );
    function wpse42003_deactivation()
    {
        foreach( array( 'editor', 'your_custome_role' ) as $r )
        {
            $role = get_role( $r );
            if( $role )
                $role->remove_cap( 'create_users' );
        }
    }
    

    Now the problem of making sure those users can only register subscribers. On the user-new.php page, the roles drop down get generated by a function called wp_dropdown_roles, which in turn calls the function get_editable_roles to fetch the roles the current user can edit/create.

    Fortunately for you, there’s a filter in there that will allow us to modify this bit. First we’ll copy all the $roles array keys, then loop through and unset any role other than subscriber from $roles — only if the current user has the role editor or your custom role.

    <?php
    add_filter( 'editable_roles', 'wpse42003_filter_roles' );
    function wpse42003_filter_roles( $roles )
    {
        $user = wp_get_current_user();
        if( in_array( 'editor', $user->roles ) || in_array( 'your_custom_role', $user->roles ) )
        {
            $tmp = array_keys( $roles );
            foreach( $tmp as $r )
            {
                if( 'subscriber' == $r ) continue;
                unset( $roles[$r] );
            }
        }
        return $roles;
    }
    

    The bonus part of this is that get_editable_roles is called before a user is added or updated — your editors won’t be able to add users by insert extra options in the form with JS or something similar.

    note: change your_custom_role in the examples above to your role’s name.

    All that as a plugin.

  2. The answer of @chrisguitarguy is good. I’ve made a small modification to the code to have it work from a development bureau serving customers on a multi-site install. We were in need to create a ‘customer’ user role, but of course a customer should not be allowed to add another customer to its domain. Modified from the accepted answer I’ve come to this:

    /**
     * Add filter to ensure a Customer type can NOT create another Customer user
     */
    add_filter( 'editable_roles', 'limit_create_user' );
    function limit_create_user( $roles ){
        $user = wp_get_current_user();
        if( in_array( 'customer', $user->roles )){
            unset( $roles[ 'customer' ]);
        }
        return $roles;
    }
    

    Hoping someone might find some use for this in the future. This was tested and applied in WP3.9.1.