Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.
For the best experience please use the latest Chrome, Safari or Firefox browser.
Use a spacebar or arrow keys to navigate
read
edit_posts
edit_others_posts
publish_posts
switch_themes
edit_themes
manage_options
get_role()
add_role()
current_user_can()
user_can()
current_user_can( $capability )
user_can( $user, $capability )
Both return a boolean indicating whether or not the user has the specified capability.
current_user_can()
and user_can()
will accept a role in place of the capability, but it's unsafe to do so.
A user could have the role specified, but a critical capability could be removed.
Also, this breaks much of what I'll cover today.
In Core, when creating a new post or page:
<?php // wp-admin/post-new.php, line 39-40 if ( ! current_user_can( $post_type_object->cap->edit_posts ) ) wp_die( __( 'Cheatin’ uh?' ) ); ?>
In Core, deterining if the current user can manage widgets:
<?php // wp-admin/widgets.php, line 15-16 if ( ! current_user_can('edit_theme_options') ) wp_die( __( 'Cheatin’ uh?' ) ); ?>
map_meta_cap
is your friendWith map_meta_cap
, you can:
In short, this provides a level of control beyond just the roles themselves.
There are really two types of capabilities in WordPress:
map_meta_cap
translates a user's primitive capabilities to his/her meta capabilities.
edit_posts
edit_post
Intent: to publish a post you wrote
Need: publish_posts
, edit_posts
Intent: to publish a post someone else wrote
Need: publish_posts
, edit_posts
, edit_others_posts
Intent: to moderate a comment
Need: moderate_comments
, edit_posts
map_meta_cap
introduces dependencies within WordPress' capabilities system.map_meta_cap
map_meta_cap()
is in wp-includes/capabilities.php
.
Within that function is the map_meta_cap
filter.
WordPress handles the function, we really care about the filter.
map_meta_cap
apply_filters('map_meta_cap', $caps, $cap, $user_id, $args)
'map_meta_cap'
: filter name$caps
: all of the primitive capabilities already determined by WordPress$cap
: the meta capability that triggered this filter call$user_id
: user ID either for the current user or a specific user when using user_can()
$args
: optional additional information relevant to current capability check$args
This is important!
The $args
parameter is both incredibly useful, and annoyingly vague.
$args
is a numerically-indexed array whose values contain data relevant to the current capabilities check.
Unfortunately, isn't always populated, forcing one to use globals in some cases.
Clear as mud, right?
<?php /** * Prevent a post from being deleted if a meta key is present * * @param array $caps * @param string $cap * @param int $user_id * @param array $args * @uses get_post_meta * @filter map_meta_cap * @return array */ function eth_block_post_deletion( $caps, $cap, $user_id, $args ) { if ( 'delete_post' == $cap && get_post_meta( (int) $args[0], '_block_deletion', true ) ) $caps[] = 'do_not_allow'; return $caps; } add_filter( 'map_meta_cap', 'eth_block_post_deletion', 10, 4 ); ?>
<?php /** * Prevent specific users from uploading files * * @param array $caps * @param string $cap * @param int $user_id * @param array $args * @uses get_user_meta * @filter map_meta_cap * @return array */ function eth_limit_uploads( $caps, $cap, $user_id, $args ) { if ( 'upload_files' == $cap && (bool) get_user_meta( $user_id, 'disallow_uploads', true ) ) $caps[] = 'do_not_allow'; return $caps; } add_filter( 'map_meta_cap', 'eth_limit_uploads', 10, 4 ); ?>
do_not_allow
When preventing something, you don't need to remove the capabilities that let a user perform an action.
unset( $caps['edit_posts'] );
Instead, add do_not_allow
to the $caps
array and WP ignores the other meta capabilities it determined.
It's worth noting that you don't have to use
do_not_allow
, but Core does and so should you; that said, you can use any string that isn't a capability used by WordPress.
<?php /** * Allow a contributor to edit a particular published post * * @param array $caps * @param string $cap * @param int $user_id * @param array $args * @uses get_post_meta * @filter map_meta_cap * @return array */ function eth_allow_contrib_edit_post( $caps, $cap, $user_id, $args ) { if ( 'edit_post' == $cap && isset( $args[0] ) && (bool) get_post_meta( (int) $args[0], '_allow_contribs_to_edit', true ) && get_post_field( 'post_author', (int) $args[0] ) == $user_id ) $caps = array( 'edit_posts' ); return $caps; } add_filter( 'map_meta_cap', 'eth_allow_contrib_edit_post', 10, 4 ); ?>
When overriding to grant a capability, you often must clear the $caps
array of the capabilities you're overridding.
In other words, there is no allow
cap that has the opposite effect as do_not_allow
.