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?

1 Answer 1

3

#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 ); } 
6
  • 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') Commented Mar 15, 2018 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 Commented Mar 15, 2018 at 16:19
  • cool, thanks! Now I feel lazy for not having checked the API reference doc... 😉 Commented Mar 18, 2018 at 20:34
  • if( $role_object = get_role( $role ) ) is nonsense. using an assignment as the expression of an if is bad style Commented Jun 21, 2023 at 13:35
  • @jjs, feel free to edit as you see fit. Expand it or remove the succinctness. For the illustrated purpose of a one & done, "needs to be truthy, then do things once, then forgotten about", I don't really believe it warrants an extra line for just declarative purposes. $role_object = get_role( $role ); if( $role_object ){ … } doesn't add a whole lot more clarity. If it was used more &, I stress, not an illustrative answer - I'd be inclined to agree. Feel free to use it to inspire your own answer, edit this one, or tweak the code as you see fit. It's intended to be a starting point, after all. Commented Jun 25, 2023 at 21:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.