Ultimate Guide to Roles and Capabilities

Since Roles and Capabilities are introduced in WordPress 2.0, the User Level approach has been declared deprecated. However, it’s disappointing that most plugins and themes out there still use user levels to control access to admin option pages and other functionalities. This guide shows you how to properly use Roles and Capabilities in your plugins and themes.

Note: This article is a long one, therefore you should probably bookmark it so that you can always come back later for reference.

Table of Contents

  1. What are Roles and Capabilities?
  2. Capabilities and administration menus
  3. Checking a user’s capability
  4. Adding custom user roles
  5. Adding custom user capabilities
  6. WordPress Capability Classes

What are Roles and Capabilities?

As in other CMS and web applications, WordPress has a built-in system to verify whether a particular user has enough privilege to take a certain action. Users are divided into Roles, and each Role is assigned certain capabilities (or permissions). Here is a summary of WordPress default roles:

Administrator – Somebody who has access to all the administration features

Editor – Somebody who can publish posts, manage posts as well as manage other people’s posts, etc.

Author – Somebody who can publish and manage their own posts

Contributor – Somebody who can write and manage their posts but not publish posts

Subscriber – Somebody who can read comments/comment/receive news letters, etc.

This system of Roles and Capabilities is much more flexible than User Level, since it enables you to add, remove or reassign capabilities among roles. You can even add more roles to the system without destroying the default setup.

Capabilities and administration menus

Almost every plugin needs to have at least one page in the admin area to let users customize how the plugin is used. In order to do this, you need to add your own administration menu items. There are a bunch of WordPress functions which let you do this:

// add top level menu
add_menu_page(page_title, menu_title, capability, handle, [function], [icon_url]);

// add sub-menu pages
add_submenu_page(parent, page_title, menu_title, capability, file/handle, [function]);

// add Options sub-menu
add_options_page(page_title, menu_title, capability, handle, [function]);

// add Management sub-menu
add_management_page(page_title, menu_title, capability, handle, [function]);

// add Pages sub-menu
add_pages_page( page_title, menu_title, capability, handle, [function]);

// add Posts sub-menu
add_posts_page( page_title, menu_title, capability, handle, [function]);

// add Appearances sub-menu
add_theme_page( page_title, menu_title, capability, handle, [function]);

As you can see, there’s always a required parameter called capability for each of those functions. This essentially means the user who logs in to the administration area needs to have a certain capability to see the menu item. You can either use a user level (which is deprecated and not recommended), or a string representing a certain capability (for example, edit_posts).

Many plugins still use user levels (numeric representation of a user’s privilege, from 0 to 10). However, this is deprecated and should not be used anymore. By using capabilities, you won’t have to worry when user levels are not supported by WordPress, and if you want to add and use your custom capabilities, this is the way to go.

If you use the functions above to add menu items to the admin area, only the users who have the specified capability can see the menu items and access the pages associated with those items. If your theme or plugin has an option page, it’s important that you restrict access to that page properly. For example, if it’s a theme option page, you should use edit_themes capability, while if it’s a plugin option, edit_plugins. Another way is to use manage_options for both plugin and theme option pages.

Remember, sometimes the blog administrator wants to share and divide responsibilities among several other users. As a result, using capabilities make your themes and plugins much more customizable.

Checking a user’s capability

If your plugin or theme involves the user making changes to the blog’s data (adding new or editing existing content etc.), it’s very important that you check whether the current user has enough capability to make a certain action. The current_user_can() function lets you do this:

if ( current_user_can( $capability ) ) {
    // do something if the current user has $capability
}

This function also accepts an optional argument for a certain post ID, in case you want to check whether the current user can do something to that post:

// check whether the current can edit a post with the ID $post_id
current_user_can( 'edit_post', $post_id );

There’s another function you can use to check whether the author of a certain post has a certain capability:

if ( author_can( $post, $capability ) ) {
    // do something if the author of the post $post has $capability
}

The first argument can be either a post object, or a post ID. Although this function is rarely used, it’s helpful to know it’s there. I personally never had to use that function, but if you have an interesting example, let me know in the comment!

Adding custom user roles

Sometimes it’s necessary for your plugin to add new roles to the system. Let’s say you’re coding a new gallery plugin where users can register to upload photos to your site, but that’s it – these registered users can’t add or modify any other type of content to your blog (such as posts or pages). The best way to do this, is to add a new custom role:

add_role( $role_name, $display_name, $capabilities );

// for example:

add_role( 'photo_uploader', 'Photo Uploader', array( 'organize_gallery' ) );

What this function does is add a new role to the system with a set of capabilities. The example aboves add a role called “photo_uploader”, with a display name and an array containing a list of default capabilities for that role (in this case, organize_gallery ).

When you process a request to create, edit or upload galleries, you should use current_user_can() to check whether the current user are permitted to take these actions.

if ( current_user_can( 'organize_gallery' ) ) {
    // do something
}

The users who are assigned this role can only organize_gallery, but cannot edit_posts or publish_posts.

To remove a role, you can use remove_role():

remove_role( 'photo_uploader' );

You should have an option somewhere for your plugin users to remove this custom role when they decide to uninstall your plugin.

But what if you want to add capabilities to existing users?

Adding custom user capabilities

This is useful when you develop a plugin that allows users to take actions other than manipulating post contents. Let’s come back to our gallery plugin example above. Say, if you also want to assign organize_gallery capability to existing roles (administrator, editor, author, contributor etc. ), what would you do?

// get the "author" role object
$role = get_role( 'author' );

// add "organize_gallery" to this role object
$role->add_cap( 'organize_gallery' );

WordPress Capability Classes

We’ve covered checking and adding capabilities, as well as adding roles. These are the most frequent used functions for managing user permissions in WordPress. However, as the title of this post contains the word “ultimate”, I’d like to also cover the three WordPress classes that work behind the scene and the API these classes provide, which you can use for advanced permission management in your plugin. These three classes are:

  • WP_Roles
  • WP_Role
  • WP_User

The source code of these three classes can be found in wp-includes/capabilities.php. The source code is documented in great details and I’m sure you can understand it easily, but I’d like to sum up what you can do with these classes.

The WP_Roles Class

This class, as its name suggests, is for managing roles in general. When you use it in your plugin, you actually don’t have to initiate a new object, but use a global object which has been created by WordPress:

global $wp_roles;

The $wp_roles is available as a global object, and can be used anywhere in your functions, as long as it’s declared beforehand in your functions with the global keyword.

As covered before, you can add and remove roles using add_role() and remove_role(). These functions are actually wrappers for $wp_roles->add_role(), and $wp_roles->remove_role. Therefore you can add and remove roles using the $wp_roles object as well:

global $wp_roles;

// add a new role, same arguments as add_role()
$wp_roles->add_role( $role, $display_name, $capabilities )

// remove a role, same arguments as remove_role()
$wp_roles->remove_role( $role );

Likewise, you can also get a role using this method:

global $wp_roles;

// get a role based on role name, does the same thing as get_role()
$wp_roles->get_role( $role );

You can also get a list of available roles, containing pair of role names and role display names. This is useful when you want to provide an interface for the user to change capability assignment.

global $wp_roles;

// get a list of values, containing pairs of: $role_name => $display_name
$roles = $wp_roles->get_names();

Finally, you can add and remove capabilities using $wp_roles too, making this object versatile for almost all roles and capabilities operations.

global $wp_roles;

// add capability $cap to role $role
$wp_roles->add_cap( $role, $cap );

// remove capability $cap from role $role
$wp_roles->remove_cap( $role, $cap );

// for example
$wp_roles->add_cap( 'administrator', 'manage_galleries' );
$wp_roles->remove_cap( 'subscriber', 'view_galleries' );

WP_Role Class

This is a very simple class. All it does is adding and removing capabilities.

// get the the role object
$role_object = get_role( $role_name );

// add $cap capability to this role object
$role_object->add_cap( $capability_name );

// remove $cap capability from this role object
$role_object->remove_cap( $capability_name );

WP_User class

This class lets you manage roles and capabilities per user, which means you can assign multiple roles to a particular user, or add a capability to a certain user regardless of his current role.

First of all, you need to get the user object before manipulating its roles and capabilities:

// get user by user ID
$user = new WP_User( $id );

// or get user by username
$user = new WP_User( null, $name );

As you can see, you can get a user object based on either his user ID or username. With the latter, the first parameter must be empty (either null or an empty string). Examples:

// get the administrator by ID
$admin = new WP_User( 1 );

// get the administrator by username
$admin = new WP_User( null, 'admin' );

Once you have the user object, you can add another role to this user without modifying his current role (which means the user can have as many roles as you want):

$user->add_role( $role_name );

Or you can remove a role from this user, using remove_role():

$user->remove_role( $role_name );

You can also set a role to this user, which means removing all the current roles of this user and assign a new one:

$user->set_role( $role_name );

For manipulating capabilities, you have a bunch of methods that allow you to do various things:

// check whether the user has a certain capability or role name
if ( $user->has_cap( $cap_name ) ) {
    // do something
}

// add a capability to the user and grant access to that capability
$user->add_cap( $cap_name );

// remove a capability from the user
$user->remove_cap( $cap_name );

// remove all capabilities from the user
$user->remove_all_caps();

Conclusion

There, that’s all there is to know about Roles and Capabilities. You might not need to grasp all of this, but it’s definitely helpful to know WordPress has a full-fledged user and role management system, which you can always use for complicated projects. This post has been all theory so far, but in the next tutorial, I’ll show you how to use this knowledge to build a “client login” area for your WordPress portfolio site.

If you have any comment or suggestion, please leave it below!

This entry was posted in Tutorials. Bookmark the permalink.

46 Responses to Ultimate Guide to Roles and Capabilities

  1. Luke Weese says:

    Thanks for another brilliant hardcore article, Gary. I’m really looking forward to the next one. It’s almost like you knew exactly what I wanted to build next, but had no idea where to start. Cheers!

  2. Rilwis says:

    Awesome. This post is very useful for plugin developers, who want to makes some functionalities related with roles and capabilities. And this will be a greater post if you introduce some plugins dealing with WP roles and capabilities. Anyway, it’s really nice, and thank you very much.

  3. Pingback: wp-popular.com » Blog Archive » Ultimate Guide to Roles and Capabilities – WordPress Hardcore

  4. Pingback: Tweets that mention Ultimate Guide to Roles and Capabilities - WordPress Hardcore -- Topsy.com

  5. ZigPress says:

    At last, a WordPress site that goes way beyond the basics, but still uses clear language and good examples when illustrating techniques.

    Bookmarked, followed, etc.

  6. Brian says:

    Can a single website offer multiple users (set up as Authors) to blog on specific pages? For my business, I thought it might be helpful to offer each of my service providers there own blog page to communicate to their clients – offer specials, etc.
    In other words – when you create a user (something I’ve not yet attempted), do you specify they are to be an Author role and then can you assign which pages they can edit/add to?
    I only have figured out how to make pages so far (using as traditional website) and I do not yet understand what exactly a post is and where it gets published in site – I prefer a specific tutorial versus the trial and find out method.
    Thanks (if you need to direct me to some helpful basics tutorial – that’s fine)

  7. I think you made a mistake with your definition of add_role (or I read over it in the article), the capabilities are supposed to be in the format array(‘capability’ => true) for my version of WordPress.

    “The capabilities are defined in the following format `array( ‘read’ => true );` To explicitly deny a role a capability you set the value for that capability to false.”
    Source: http://phpdoc.wordpress.org/trunk/WordPress/User/WP_Roles.html .

    For the rest a very nice article, explained it clearly for me.

  8. Grant Swaim says:

    Gary,

    Thanks for an informative article. Do you know if it is possible for a user to be assigned to more than one role. I know there was chatter about this the past.

    Thanks in advance for your help.

  9. tom hermans says:

    Great article. Gonna try this tomorrow for a project i’m working on. Tom.

  10. foxinni says:

    Amazing detail. Delicious’ed it right away!

  11. Nice article. I was wondering if there was an easy way to limit an “author” to posting only in certain categories. I am considering writing a simple forums plugin that actually just uses the post database and categories, but displays the index and pages more like a discussion forum layout. I’d need to be able to set all users as “authors”, but I’d only want them to be able to post in certain categories (categories under the top-level category of “forums”) and not in my “news” categories.

    Another use case might be a site that let’s “guests” post articles in certain categories but not the main news categories.

  12. Daio Ferrer says:

    Nice job Gary. Last night I stumbled with a couple of issues related to this part. Fortunately I found this post.

  13. Phil says:

    I’m new to roles and capabilities, but I’m trying to create a new role called “Manager” and I want it to be able to do everything an editor can do, plus a little more, but not quite as much as an Administrator.

    But here’s the problem. When I do that using something like this:

    add_role(‘manager’, ‘Manager’, …);
    $role = get_role(‘manager’);
    $role->add_cap(‘…’);
    $role->add_cap(‘…’);
    $role->add_cap(‘…’);

    It only seems to apply to the current site I’m working on. If I create a new site and a new user, I can’t seem to give that new user the ‘Manager’ role without running that code on the new site first.

    Is there a way to create a role that exists and can be accessed by new sites and users?

  14. anika says:

    Very nice post. Thanks for it.

  15. i always use feedburner to syndicate my blog posts to other subscribers.::`

  16. I would like to know: do the roles and capabilities apply to the *front end*? That is, if I write a theme or plugin that implements some sort of front end function (as opposed to something like an admin page), can this front-end function check the visitor’s (user’s) capabilities, that is call current_user_can()? It is not clear from the documentation, which all seems to be geared in terms of admin menus and pages.

  17. Ron Suarez says:

    Some of my WordPress sites get lots of people subscribing who do not seem to actually be interested in the content and thus are likely to be people attempting to hack the site.

    Is there any danger in having a site open to anyone who wants to subscribe? If there is no danger then why would these people subscribe? Are they just dumb bots subscribing everywhere they can and then hoping to discover a vulnerability to get more access?

  18. Tristan says:

    You seem like you know what you’re talking about. I’m having some trouble with roles.

    I want to display a different link depending on what role the logged in user is.

    I have created two roles with basically the same access as subscribers except they can both read private pages. I want to display different private page links to them, though.

    I’m not real hot with PHP code, but could I do something like:

    get role_name
    if role_name is AAAA then display
    if role_name is BBBB then display
    else
    display [default code]

    I can’t use the current_user_can function because both user roles will be able to read_private_pages

    Any thoughts?

  19. Tristan says:

    sorry, formatting got screwed up above. should be:

    get role_name
    if role_name is AAAA then (display code)
    if role_name is BBBB then (display code)
    else
    display (default code)
    
  20. Dave says:

    I have a need to set a users custom role in a custom register form. I am using WP 3.0

    What you describe here looks like what I need, but I can not get it to work without getting the error:
    Catchable fatal error:Object of class WP_Error could not be converted to string in /wp-includes/formatting.php on line 2772.

    My php code:
    require_once (ABSPATH.’/wp-includes/capabilities.php’);
    global $wp_roles;
    $user = new WP_User( $user_id );
    $role=$wp_roles->get_names();
    $user->add_role( ‘reviewer’ );

    I would love to get this to work any ideas on what I am doing wrong?

    • Dave says:

      No errors now with code below, but it does not set user level. Do I have to write something to the data base?

      Code:
      require_once (ABSPATH.’/wp-includes/capabilities.php’); global $wp_roles;
      if (!isset($wp_roles)) {$wp_roles = new WP_Roles();}
      if (!isset($newuser)) {$newuser = new WP_User($user_id);}
      $newuser->add_cap( ‘level_1′ );

      • Dave says:

        Never mind here is how I solved it.

        global $wpdb;
        $query=sprintf(‘UPDATE rrwp_usermeta SET meta_value=%s WHERE user_id=%s AND meta_key=”wp_capabilities” LIMIT 1′,
        ‘a:1:{s:9:”cust_role”;s:1:”1″;}’,$id);
        $record = $wpdb->query($query);

  21. Many thanks for this very nice guide. This should help me a lot …
    And examples are very nicely choosen

  22. Hello Gary,

    Great article…learned something. Keep up the good work. Are you familiar with the user meta table?

    There is an entry: ‘wp_capabilities’. I assume that’s how the roles are stored. Can you explain how to create an entry like this one?

    a:1:{s:10:”subscriber”;s:1:”1″;}

    Thank you!

    Thomas

  23. I have a question about this very nice article. How can you add a capability to the role ‘subscriber’ that he can only see and use the Custom Post Type ‘Podcast’?

    I added the code below in my function.php

    // Register custom post types
    register_post_type(‘podcast’, array(
    ‘label’ => __(‘Podcasts’),
    ‘singular_label’ => __(‘Podcast’),
    ‘public’ => true,
    ‘show_ui’ => true, // UI in admin panel
    ‘_builtin’ => false, // It’s a custom post type, not built in
    ‘_edit_link’ => ‘post.php?post=%d’,
    ‘capability_type’ => ‘podcast’,
    ‘hierarchical’ => false,
    ‘rewrite’ => array(“slug” => “podcast”), // Permalinks
    ‘query_var’ => “podcast”, // This goes to the WP_Query schema
    ‘supports’ => array(‘title’,'author’, ‘excerpt’, ‘editor’ /*,’custom-fields’*/) // Let’s use custom fields for debugging purposes only
    ));

    // get the “author” role object
    $role = get_role( ‘subscriber’ );

    // add “organize_gallery” to this role object
    $role->add_cap( ‘podcast’ );

    But if I login with a user that has the subscriber type I dont see my “Podcast” menu.

    Hope you can help me out with this one?

  24. the_guv says:

    really nice, gutsy article .. Gary, you are hardcore :P

  25. fdanialex says:

    Good job Gary, this is very helpful.

    I used this info and implemented capabilities to my plugin.

    Cheers!

  26. Ray says:

    The instructions above do not make any sense, as there is no clear indication where they should take place. The WP-codex is even worse.

  27. Nicolas says:

    Hi.
    Thanks for this post !
    I’m trying to add a new capability with a hook in my function.php file.I’m not sure of the code i have written because it don’ work.i’m sure you can help my.

    Her’s my code:
    function custom() {
    global $wp_roles;
    $wp_roles->add_cap( ‘editor’, ‘edit_videos’ );

    }
    add_action(‘admin_head’,'custom’);
    thanks

  28. Nicolas says:

    Hi one of the solution directly in the function.php file

    $role =& get_role(‘editor’);
    $role->add_cap(‘edit_videos’);

  29. Nicolas says:

    And simply with a function:
    // functions.php

    function modify_capabilities()
    {
    // get the role you want to change: editor, author, contributor, subscriber
    $editor_role = get_role(‘editor’);
    $editor_role->remove_cap(‘publish_pages’);

    // for posts it should be:
    // $editor_role->remove_cap(‘publish_posts’);

    // to add capabilities use add_cap()
    }

    add_action(‘admin_init’,'modify_capabilities’);

  30. andrei gheorghiu says:

    Is there a way to delete custom created capabilities?
    I mean other than re-install WordPress altogether?

  31. Prabhjot says:

    Cool Dude……..

  32. Matt says:

    Something that tripped me up a bit when using this guide: when adding a role, the capabilities array should have the capabilities as the keys, not the values. So like this:

    add_role(‘photo_uploader’, ‘Photo Uploader’, array(‘read’=> true, ‘organize_gallery’ => true));

    rather than:

    add_role(‘photo_uploader’, ‘Photo Uploader’, array(‘read’, ‘organize_gallery’));

    At least, that’s how it works in 2.9. Not sure about any other versions. Hope this helps somebody else who gets stuck on it.

    Otherwise, great article! Really handy resource.

  33. Nabha says:

    This is a great article — well thought out, to the point, and very clear and easy to understand. Most importantly, it gave me a good idea of what the most important things are, which is something straight documentation can’t do.

    Thanks for the tip on

  34. Nabha says:

    Whoops, I meant to say, thanks for the tip on where to look in the WordPress source files to learn more. That is really “teaching people to fish”!

  35. Alex says:

    This guide has really helped me in a big way! Thanks for really going in deep on this!

  36. techie talks says:

    Thanks for sharing. The snippets are so useful, I am developing a free wordpress codex and I am hoping that everyone will make use of this after. :)

  37. Viviana says:

    Yourr site looks great! Love tbe blog.. If you are interested in any web design feel free to contact me at http://vadoz.ru

  38. Roy says:

    Hi Gary! Nice post and well explained. I have came across a problem and wanted to see if you have encountered the same thing. If I add custom role with capabilities, the function current_user_can() does not work. However if I switch it to check for the role instead, it works. According to the codex, current_user_can function() will accept both the role or the capabilities. So I am not sure what went wrong there. Below is the code in question.

    add_role(‘member’,'Member’,array(‘read’ => true, ‘panels’ => true));

    current_user_can(‘panels’); <—– doesn't work…
    current_user_can('member'); <—–works…..

    • Gary Cao says:

      This is strange. For me both of these current_user_can() check out.

      function test_caps() {
      	add_role( 'testrole', array( 'read' => true, 'panels' => true ) );
      	var_dump(current_user_can('panels')); // outputs true
      	var_dump(current_user_can('member')); // outputs true
      }
      add_action('init', 'test_caps');
      

      Note that I’m testing using an admin account.

      • Roy says:

        Ok but did you try adding a new test user, then setting that user to the ‘testrole’ and then login as the test user and then do a current_user_can var dump?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>