The documentation unfortunately not very clear on what “explicitly deny” actually entails. While setting a capability to false
will normally explicitly deny the capability, that check is performed after super admins have been waved through. So even though the documentation says “unless explicitly denied”, denying it this way doesn’t work for super admins. Only the other roles.
The only way to explicitly deny a capability for a super admin is to use the map_meta_cap
filter to return do_not_allow
when the custom capability is checked.
The map_meta_cap()
function, which the filter applies to, is quite complicated, but its basic purpose is to do things like translate current_user_can( 'edit_post', 2 )
into either the edit_posts
or edit_others_posts
capability based on who the user is. Because map_meta_cap()
is run before the super admin check, we can use this filter to explicitly return do_not_allow
when checks for current_user_can( 'custom_capability' )
are made for a super admin that doesn’t have the capability. Here’s some code to do that:
add_filter(
'map_meta_cap',
function( $caps, $cap, $user_id ) {
/**
* Only filter checks for custom_capability.
*/
if ( 'custom_capability' === $cap ) {
$user = get_userdata( $user_id );
$user_caps = $user->get_role_caps();
/**
* If the user does not have the capability, or it's denied, then
* add do_not_allow.
*/
if ( empty( $user_caps[$cap] ) ) {
$caps[] = 'do_not_allow';
}
}
return $caps;
},
10,
3
);