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

The Power of WordPress' Roles and Capabilities

Erick Hitter

Design Engineer @ Automattic

@ethitter

About Me

Myth I Hope To Dispell

 

WordPress, as a CMS, lacks adequate controls over user actions, making CMS ____?____ a better choice.

 

 

By show of hands, who has heard this refrain?

Roles and Capabilities

http://codex.wordpress.org/Roles_and_Capabilities

 

This Codex article is your friend!

Default Roles

Default Roles: Subscriber

Default Roles: Contributor

Default Roles: Author

Default Roles: Editor

Default Roles: Administrator

Native Capabilities

 

This list is far from complete; see http://codex.wordpress.org/Roles_and_Capabilities#Capabilities

Key Functions

get_role( $role )

add_role( $role, $display_name, $capabilities )

Checking capabilities

Both return a boolean indicating whether or not the user has the specified capability.

Checking user roles

Don't

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.

Modify an existing role

<?php
/**
 * It's bad to edit plugins from the Dashboard, so let's stop that.
 *
 * @uses get_role
 * @action init
 * @return null
 */
function eth_dont_edit_plugins() {
	$administrator = get_role( 'administrator' );

	$administrator->remove_cap( 'edit_plugins' );
}
add_action( 'init', 'eth_dont_edit_plugins' );
?>

Add a new role

<?php
/**
 * Add a role that can only interact with pages
 *
 * @uses get_role, add_role
 * @action init
 * @return null
 */
function eth_page_manager_role() {
	$page_manager = get_role( 'eth_page_manager' );

	if ( null === $page_manager )
		$page_manager = add_role( 'eth_page_manager' );

	$page_manager->add_cap( 'read' );
	$page_manager->add_cap( 'read_private_pages' );
	$page_manager->add_cap( 'edit_pages' );
	$page_manager->add_cap( 'edit_others_pages' );
	$page_manager->add_cap( 'edit_published_pages' );
	$page_manager->add_cap( 'edit_private_pages' );
	$page_manager->add_cap( 'publish_pages' );
	$page_manager->add_cap( 'delete_pages' );
	$page_manager->add_cap( 'delete_others_pages' );
	$page_manager->add_cap( 'delete_published_pages' );
	$page_manager->add_cap( 'delete_private_pages' );
	$page_manager->add_cap( 'upload_files' );
}
add_action( 'init', 'eth_page_manager_role' );
?>

How does WordPress leverages roles?

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?' ) );
?>

How can you leverage roles?

Registering a meta box:

<?php
/**
 * Register custom metabox
 *
 * @uses current_user_can, add_meta_box
 * @action add_meta_boxes
 * @return null
 */
function eth_register_custom_metabox() {
	if ( current_user_can( 'edit_others_posts' ) )
		add_meta_box( 'eth-meta-box', 'WCTO Metabox', 'eth_custom_metabox',
			'post', 'normal', 'default' );
}
add_action( 'add_meta_boxes', 'eth_register_custom_metabox' );

/**
 * Render custom metabox
 *
 * @uses current_user_can
 * @return string or null
 */
function eth_custom_metabox() {
	if ( ! current_user_can( 'edit_others_posts' ) )
		return;

	echo 'Hello world!';
}
?>

How can you leverage roles?

Creating a custom admin page:

<?php
/**
 * Register a custom admin page
 *
 * @uses add_options_page
 * @action admin_menu
 * @return null
 */
function eth_register_custom_admin_page() {
	add_options_page( 'WCTO Options', 'WCTO Options', 'manage_options',
		'eth-options', 'eth_custom_admin_page' );
}
add_action( 'admin_menu', 'eth_register_custom_admin_page' );

/**
 * Render custom admin page contents
 *
 * @return string
 */
function eth_custom_admin_page() {
	echo 'Hello world!';
}
?>

Custom capabilities

WordPress has default capabilities, but nothing's stopping you from adding your own.

<?php
/**
 * Add a role that can only interact with pages
 *
 * @uses get_role, add_role
 * @action init
 * @return null
 */
function eth_page_manager_role() {
	$page_manager = get_role( 'eth_page_manager' );

	if ( null === $page_manager )
		$page_manager = add_role( 'eth_page_manager' );

	$page_manager->add_cap( 'read' );
	…
	$page_manager->add_cap( 'upload_files' );
	$page_manager->add_cap( 'eth_manage_options' );
}
add_action( 'init', 'eth_page_manager_role' );
?>

Custom capabilities

WordPress has default capabilities, but nothing's stopping you from adding your own.

<?php
/**
 * Let Administrators and Editors access the custom admin page
 *
 * @uses get_role
 * @action init
 * @return null
 */
function eth_modify_roles() {
	$administrator = get_role( 'administrator' );
	$administrator->add_cap( 'eth_manage_options' );

	$editor = get_role( 'editor' );
	$editor->add_cap( 'eth_manage_options' );
}
add_action( 'init', 'eth_modify_roles' );
?>

Want more granular control?

 

map_meta_cap is your friend

map_meta_cap

map_meta_cap() is in wp-includes/capabilities.php.

Within that function is the map_meta_cap filter.

apply_filters('map_meta_cap', $caps, $cap, $user_id, $args)

map_meta_cap

Okay, how is this useful?

In short, this provides a level of control beyond just the roles themselves.

map_meta_cap example

<?php
/**
 * Prevent certain posts from being modified under certain conditions
 *
 * @global $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_filter_map_meta_cap( $caps, $cap, $user_id, $args ) {
	//Block deletion of posts with a certain meta key
	if ( 'delete_post' == $cap && get_post_meta( (int) $args[ 0 ],
		'eth_block_deletion', true ) )
		$caps[] = 'do_not_allow';

	//Block publication of posts with a certain meta key
	global $post;
	if ( is_object( $post ) && in_array( 'publish_posts', $caps )
		&& get_post_meta( $post->ID, 'eth_block_publication', true ) )
		$caps[] = 'do_not_allow';

	return $caps;
}
add_filter( 'map_meta_cap', 'eth_filter_map_meta_cap', 10, 4 );
?>

Questions?

Slides are available at http://www.ethitter.com/blog/.

Check Twitter for a link as well: @ethitter.