Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I wish to create a custom capability for accessing the interface of my plugin.

  • Should the plugin manage adding this capability to all the administrator accounts on activation?
  • If so: Does WordPress manage adding the capability to all administrators of sub blogs and super administrators in multisite installations, or does that function need to be handled by the plugin?
share|improve this question

2 Answers 2

up vote 5 down vote accepted

Remove what you add

First, please make sure that everything you add on activation also gets removed on uninstall. I got a short tutorial including example code for you.

Test with a small plugin:

I really don't know much about MU, but as far as I can tell, the roles object is global across all blogs. Just try this little plugin and see what you can get:

<?php
/*
Plugin Name:    MU Roles check
Plugin URI:     https://github.com/franz-josef-kaiser/
Description:    Check roles during viewing a blog
Author:     Franz Josef Kaiser
Author URI:     https://plus.google.com/u/0/107110219316412982437
Version:        0.1
Text Domain:    murc
License:        GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/

/**
 * Show the blog data and the role names in this blog
 * Also shows if the custom capability was successfully added, or displays n/a for the role
 * 
 * @return void
 */
function wpse35165_role_check()
{
    $blog = get_current_site();
    $custom_cap = 'name_of_your_custom_capability';

    $html = "<hr /><table>";
    $html .= "<caption>List roles in (Blog) {$blog->site_name} / ID#{$blog->id}</caption>"
    $html .= "<thead><tr><th>Role Name</th><th>Capabilties</th></tr></thead><tbody>";
    foreach ( $GLOBALS['wp_roles'] as $name => $role_obj )
    {
        $cap = in_array( $custom_cap, $role_obj->caps ) ? $custom_cap : 'n/a';
        $cap = $cap OR in_array( $custom_cap, $role_obj->allcaps ) ? $custom_cap : 'n/a';
        $html .= "<tr><td>{$name}</td><td>{$cap}</td></tr>";
    }
    $html .= '</tbody></table>';

    print $html;
}
add_action( 'shutdown', 'wpse35165_role_check' );

Adding Capabilities

/**
 * Add the capability to the role objects
 * Should be in your activation function and done before you inspect with your plugin
 * 
 * @return void
 */
function wpse35165_add_cap()
{
    $custom_cap = 'name_of_your_custom_capability';
    $min_cap    = 'the_minimum_required_built_in_cap'; // Check "Roles and objects table in codex!
    $grant      = true; 

    foreach ( $GLOBALS['wp_roles'] as $role_obj )
    {
        if ( 
            ! $role_obj->has_cap( $custom_cap ) 
            AND $role_obj->has_cap( $min_cap )
        )
            $role_obj->add_cap( $custom_cap, $grant );
    }
}

Note: You can add the capability to the role without granting access to it - just set the second argument $grant = false;. This allows whitelisting single users with simply adding the cap including the last argument as true.

share|improve this answer

For a plugin I'm currently working on, I wanted to grant/restrict access to the plugin settings (i.e., the according admin menu pages) on a per role base.
Therefore, I had to add a new plugin-specific capability to the user roles.

Unfortunately, kaiser's answer seems to be not working anymore, so I spent some time trying to figure out how to allow for the above mentioned functionality.


The Schedule

Before I share my code with you, here is what it's all about, in plain text:

  1. On plugin activation, add the new capability THE_NEW_CAP to roles having a certain built-in capability BUILT_IN_CAP (in my case: edit_pages).
  2. On each page load, do 1. (i.e., add the capability, again). This is only necessary if you want to account for possible new roles that have been created after the activation of the plugin. Hence, these new roles don't have the plugin-specific capability, even if they have the required built-in capability.
  3. Use the new capability for whatever you want. As explained before, I use it for granting/restricting access to the plugin's admin menu pages, so that is how it is done in the following code example.
  4. On plugin deactivation, remove the capability. Of course, you could also do this when the plugin is being uninstalled. Either way, do it eventually.

The Code

And here is the above list converted into code:

» Setting It Up

class WPSE35165Plugin {

    function __construct() {
        // Register hooks
        register_activation_hook(__FILE__, array(__CLASS__, 'activation'));
        register_deactivation_hook(__FILE__, array(__CLASS__, 'deactivation'));

        // Add actions
        add_action('admin_menu', array(__CLASS__, 'admin_menu'));
    } // function __construct

    function activation() {
        self::add_cap();
    } // function activation

    // Add the new capability to all roles having a certain built-in capability
    private function add_cap() {
        $roles = get_editable_roles();
        foreach ($GLOBALS['wp_roles']->role_objects as $key => $role)
            if (isset($roles[$key]) && $role->has_cap('BUILT_IN_CAP'))
                $role->add_cap('THE_NEW_CAP');
    } // private function add_cap

» Using It

    // Add plugin menu pages to admin menu
    function admin_menu() {
        // Remove the following line if you don't care about new roles
        // that have been created after plugin activation
        self::add_cap();

        // Set up the plugin admin menu
        add_menu_page('Menu', 'Menu', 'THE_NEW_CAP', ...);
        add_submenu_page('wpse35165', 'Submenu', 'Submenu', 'THE_NEW_CAP', ...);
    } // function admin_menu

» Cleaning It Up

    function deactivation() {
        self::remove_cap();
    } // function deactivation

    // Remove the plugin-specific custom capability
    private function remove_cap() {
        $roles = get_editable_roles();
        foreach ($GLOBALS['wp_roles']->role_objects as $key => $role)
            if (isset($roles[$key]) && $role->has_cap('THE_NEW_CAP'))
                $role->remove_cap('THE_NEW_CAP');
    } // private function remove_cap

} // class WPSE35165Plugin
share|improve this answer
    
Always use get_editable_roles() to fetch roles you want to edit. You will break plugins otherwise. –  toscho Apr 28 '13 at 17:38
    
@toscho Well, okay, I suppose that's one of these functions even the Codex doesn't know about... ;) Of course, this function has its right to exist, however, I don't see using the global WP_Roles array breaking any plugins in my case. –  t f Apr 28 '13 at 17:44
    
Some plugins create specialized user roles and rely on the exact set of capabilities. In some cases one capability excludes the usage of another in the program logic. You cannot know when that’s the case. –  toscho Apr 28 '13 at 17:54
1  
This was really useful, thanks a lot :) –  EJEHardenberg Apr 9 at 3:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.