map_meta_cap
Allows changing the primitive capabilities required when checking a user's permissions.
The hook fires at the end of map_meta_cap(), which determines whether the current user can perform a specified action; see current_user_can(). The hook can perform an additional permission check and allow or deny the current action.
To pass the check, the hook must return an array of capabilities, all of which the user must have. See the $caps parameter.
Usage
add_filter( 'map_meta_cap', 'wp_kama_map_meta_cap_filter', 10, 4 );
/**
* Function for `map_meta_cap` filter-hook.
*
* @param string[] $caps Primitive capabilities required of the user.
* @param string $cap Capability being checked.
* @param int $user_id The user ID.
* @param array $args Adds context to the capability check, typically starting with an object ID.
*
* @return string[]
*/
function wp_kama_map_meta_cap_filter( $caps, $cap, $user_id, $args ){
// filter...
return $caps;
}
- $caps(array)
An array of capabilities the user must have to pass the check. The user must have every capability in this array.
For example, suppose we need to check whether a user can edit someone else's published post:
The hook returns: Array ( [0] => edit_others_schools [1] => edit_published_schools ) The user has these primitive capabilities: Array ( [0] => edit_others_schools [1] => read [2] => edit_posts ) In this case, the user cannot edit the post being checked because they do not have the edit_published_schools capability.
- See the WP_User::has_cap() code for how the check works.
- See the user_has_cap hook, which allows capabilities to be added to a role dynamically.
- $cap(string)
- The capability currently being checked, such as
edit_post(a meta capability) oredit_posts(a primitive capability). - $user_id(int)
- ID of the user whose capability is being checked.
- $args(array)
Additional arguments passed to the capability-checking function. For example, this contains all parameters of
current_user_can()except the first one.Usually this array has one element: the ID of the object for which the capability is checked. For
current_user_can( 'edit_post', 123 ), for example, this parameter isarray( [0] => 123 ).
Examples
#1 Example of using the map_meta_cap filter
This example shows how to grant a user additional access to an action. Here, a subscriber is allowed to edit their post from the front end.
It assumes that the post can be edited on the front end and that the capability is checked in the standard way: current_user_can( 'edit_post', $post_id );
// Allow a subscriber to edit a post if they are its author and
// no more than X months have passed since it was published
! is_admin() && add_filter( 'map_meta_cap', 'allow_subscribers_edit_self_posts', 10, 4 );
function allow_subscribers_edit_self_posts( $caps, $cap, $user_id, $args ){
// print_r( $caps ); // [0] => edit_published_posts
// print_r( $cap ); // edit_post
// print_r( $user_id ); // 80
// print_r( $args ); // [0] => 913
if( $cap === 'edit_post' && $caps[0] === 'edit_published_posts' ){
$post = get_post( $args[0] );
// Allow editing if the user is the post author and no more
// than two months have passed since the post was published
if(
$post->post_author && $user_id == $post->post_author &&
get_userdata($user_id)->roles[0] === 'subscriber' &&
( time() < ( MONTH_IN_SECONDS * 2 + strtotime( $post->post_date_gmt ) ) )
){
$caps[0] = 'read';
}
}
return $caps;
}
#2 Allow particular users to edit other users' Posts
Suppose authors publish projects (Posts) and store the ID of a tracker (a custom role) in a metadata field. That tracker should then be able to edit their projects.
add_filter( 'map_meta_cap', 'allow_tracker_edit_posts', 10, 4 );
/**
* Allows Trackers to edit their assigned users' posts.
*
* @param array $caps
* @param string $cap
* @param int $user_id
* @param array $args
*
* @return array
*/
function allow_tracker_edit_posts( $caps, $cap, $user_id, $args ) {
if (
// Handle only the required meta capability
$cap === 'edit_post'
// The current user ID must match the value stored in the post metadata
&& (int) get_post( $args[0] )->project_tracker === $user_id
// The current user must have the role for which the capability is being added
&& get_userdata( $user_id )->has_cap('project_tracker')
) {
$caps[0] = 'edit_posts'; // Add the primitive capability
}
return $caps;
}
#3 Unconditionally deny something to absolutely everyone
To strictly deny a capability through this hook, return an array containing 'do_not_allow'.
If an empty capability array or an array containing nonexistent capabilities is returned instead, a super administrator on a Multisite network, for example, can still have any capability—even one that does not exist.
Therefore, when nobody, including a super administrator, should have the specified capability, add the 'do_not_allow' string to the returned capabilities array.
For example, remove permission to use the WordPress Customizer from everyone, including super administrators:
add_filter( 'map_meta_cap', 'remove_customize_capability', 10, 2 );
function remove_customize_capability( $caps, $cap ) {
return ( $cap === 'customize' ) ? [ 'do_not_allow' ] : $caps;
}Changelog
| Since 2.8.0 | Introduced. |
Where the hook is called
return apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
Where the hook is used in WordPress
add_filter( 'map_meta_cap', array( $this, 'grant_edit_post_capability_for_changeset' ), 10, 4 );
remove_filter( 'map_meta_cap', array( $this, 'grant_edit_post_capability_for_changeset' ), 10 );