2

In a plugin, i create a dedicated user role along with some capabilities. These capabilities also need to be assigned to other roles, such as editor and admin.

As the addition of roles and capabilities involves database writes, these operations are commonly considered "expensive" and recommended to be performed only in the plugin activation hook. In my case, there is no activation hook, as the plugin needs to be loaded as mu-plugin. Therefore, i want to check if the admin and editor roles already have my custom capabilities, before attempting to add them.

How can i check if a specific role has a specific capability? Or, alternatively: Is it even less "expensive" to make the check? Or should i just make the call to add_cap() from the init hook without prior checks?

2

Update:

Wow, I feel like such a buffoon... haha. WP_Role::has_cap

I can't (role) my eyes hard enough.

$caps  = array( 'cap_1', 'cap_2', 'cap_3' );
$roles = array( 'administrator', 'editor' );

foreach( $roles as $role ){
    if( $role_object = get_role( $role ){
        foreach( $caps as $cap ){
            if( !$role_object->has_cap( $cap ){
                $role_object->add_cap( $cap );
            }
        }
    }
}

Disregard this nonesense:

I apologize, my other answer was per user not per role.

What you can do is check to see if the role has the capability using get_role()

You can see that get_role( 'administrator' ) will return an Object that has an array of capabilities in it.

$administrator = get_role( 'administrator' );

// Make sure role object was retrieved
if( $administrator ){
    //See if it's got our capability or not
    if( !in_array( 'my-custom-cap', $administrator->capabilities ) ){
        // Wasn't there, so add it here
        $administrator->add_cap( 'my-custom-cap' );
    }
}

If for some reason you don't want to run the $role object comparison each time, you can define it once and then set a flag in the database with update_option() and check it with get_option()

if( get_option( 'manually_set_add_cap_admin' ) != true ){
    $administrator = get_role( 'administrator' );

    // Make sure role object was retrieved
    if( $administrator ){
        //See if it's got our capability or not
        if( !in_array( 'my-custom-cap', $administrator->capabilities ) ){
            // Wasn't there, so add it here
            $administrator->add_cap( 'my-custom-cap' );
            update_option( 'manually_set_add_cap_admin', true );
        }
    }
}

Here's a bit more lengthy solution that will loop through any roles you add, and give them all the appropriate capabilities. After the loops are completed, it will set a flag that's checked, so there won't be any WP_Role object fetching after it's ran the first time.

// Define flag as a variable to prevent typos, in update/get_option
// or it will constantly run (I know from experience...)
$flag = 'manually_added_my_custom_caps';

if( !get_option( $flag ) ){
    // Our flag option wasn't set, that means this code hasn't run yet.

    $roles        = array( 'administrator', 'editor' );
    $capabilities = array( 'custom-cap-1', 'custom-cap-2' );

    // Loop through each role
    foreach( $roles as $role ){
        // Make sure we got a WP_Role object back
        if( $role_object = get_role( $role ) ){
            // Loop through our custom capabilities
            foreach( $capabilities as $cap ){
                // Our option flag wasn't set, but let's confirm
                // that the role doesn't have the cap
                if( !in_array( $cap, $role_object->capabilities ) ){
                    // Confirmed not there, add it here
                    $role_object->add_cap( $cap );
                }
            }
        }
    }

    // Our function ran, it should have set all caps to all the roles
    // so now our code will skip this entirely next time
    update_option( $flag, true );
}

  • Thanks for your answer, @Xhynk! One note: in_array( 'cap', $role->capabilities ) should be array_key_exists( 'cap', $role->capabilities ), because the capabilities array is associative name => grant. But even that does not cover the case when our capability is assigned to the role with grant=false. In order to check that too, we would need to write array_key_exists('cap', $role->capabilities) and $role->capabilities['cap'] === true, which is incredibly verbose and ugly, compared to, say $role->hasCapability('cap') – jsphpl Mar 15 '18 at 7:08
  • Lord almighty I feel like an idiot - Since 2.0 WP_Role has had the method has_cap... 🙄🙄... Relevant Doc . Answer updated, but leaving the original for shameful posterity – Xhynk Mar 15 '18 at 16:19
  • cool, thanks! Now I feel lazy for not having checked the API reference doc... 😉 – jsphpl Mar 18 '18 at 20:34

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.