I recently noticed that almost every WordPress plugin I have ever used does not restrict user access based on their role. Due to the increasing popularity of multiple authors and guest posting, there is a necessity for plugin authors to implement methods of restricing plugin access based on user roles. The primary goal of this tutorial is to add a multi-select dropdown of all user roles to your plugin’s administrative options page. This dropdown will be used to select only those user roles you wish to give access to your plugin. We will be demonstrating with a real WordPress plugin, JinX the Javascript Includer. It is a prime example of a plugin that you may wish to disallow lower level users from accessing due to it’s lack of escaping and filtering of data. You can download the sourcecode if you wish to skip the details.
Create the Class
The first thing we need to do is create the scaffolding for a plugin. Let’s begin by creating the class, the construtor, and an init method:
class jinx {
// stores the path to our plugin
protected $pluginurl;
// stores the ACL roles
protected $defaultOptionVals;
/**
* The default constructor.
*/
function __construct()
{
$this->pluginurl = WP_PLUGIN_URL . '/jinx/';
}
/**
* The init method.
*/
public function init()
{
// restrict access to admin section and selected user roles
if (is_admin() && $this->hasPluginAccess()) {
// add an admin options menu
add_action('admin_menu', array(&$this, 'admin_menu'));
// register markitup
add_action('admin_init', array(&$this, 'jinx_admin_init'));
// add javascript to admin
add_action('admin_head', array(&$this, 'load_headers'), 1000);
// add custom box to admin
add_action('admin_menu', array(&$this, 'add_custom_box'), 1000);
// watch for post submisions
add_action('edit_post', array(&$this, 'submit_meta_tag'));
add_action('publish_post', array(&$this, 'submit_meta_tag'));
add_action('save_post', array(&$this, 'submit_meta_tag'));
add_action('edit_page_form', array(&$this, 'submit_meta_tag'));
}
// add javascript to page and blog posts
add_filter('the_content', array(&$this, 'add_javascript_to_post'), 9999);
}
}
// load the class
$jinx = new jinx();
// load the initializer method following WordPress initialization
add_action('init', array(&$jinx, 'init'));
There are actually very few lines of code here applicable to access control. The first highlighted line is the protected class variable $defaultOptionVals. This variable initially holds the default user roles which have access to the plugin and the plugin configuration options page.
The second highlighted line of code above does a quick check for is_admin() to ensure that the user is actually logged in to the admin. It then makes a call to $this->hasPluginAccess(). The hasPluginAccess method is a very important piece to the puzzle; restricting the access to the admin backend.
Creating the Role Based Restriction Method
The actions performed by the method are:
- merge the default allowable administrator role with any selected roles from the plugin options page
- grab the currently logged in user’s role(s)
- compare the user-defined access control list (ACL) against the currently logged in user’s role
- return a boolean value based on the comparison
Let’s take a look at that function now:
/**
* Checks that the logged in user's role is contained within the
* selected (or default) plugin roles.
*/
public function hasPluginAccess()
{
global $user_ID;
// specify the default roles which have access to the plugin
$this->defaultOptionVals = array(
'roles' => array('administrator', 'editor', 'author')
);
// get all current option values and override defaults
$options = get_option('jinx_roles');
if (!empty($options)) {
$this->defaultOptionVals = array_merge($this->defaultOptionVals, $options, array('administrator'));
}
// ensure we have a logged in user
if (!empty($user_ID)) {
$user = new WP_User($user_ID);
if (!is_array($user->roles)) $user->roles = array($user->roles);
foreach ($user->roles as $role) {
if (in_array($role, $this->defaultOptionVals)) {
return true;
}
}
}
return false;
}
The only remaining step is to create the plugin options page to allow for user restriction by selecting roles from a multi-select dropdown. We’ve already named our method admin_menu in the init() method above. Let’s create the page.
Create the Options Page
The options page must retrieve all available user roles from WordPress to populate the dropdown. It also compares these values against the currently selected options; falling back on the default administrator option. The method also handles creating the form, error handling, form submission, and storing the updated option values.
/**
* Admin menu entry.
*
* @access public
*/
public function admin_menu()
{
if (function_exists('add_options_page')) {
$id = add_options_page('JinX Options', 'JinX Options', 10, basename(__FILE__), array(&$this, 'admin_options'));
}
}
/**
* Options page.
*
* @access public
*/
public function admin_options()
{
// grab the array of all user roles
$roles = new WP_Roles();
$roles = array_keys($roles->role_names);
// watch for form submission
if (!empty($_POST['jinx_roles'])) {
// validate the referer
check_admin_referer('jinx_options_valid');
if (empty($_POST['jinx_roles'])) {
echo '<div id="message" class="updated fade"><p><strong>' . __('You must select at least one role for this application to be properly enabled.') . '</strong></p></div>';
return false;
}
// update the new value
$this->defaultOptionVals['roles'] = $_POST['jinx_roles'];
// update options settings
update_option('jinx_roles', $this->defaultOptionVals);
// show success
echo '<div id="message" class="updated fade"><p><strong>' . __('Your configuration settings have been saved.') . '</strong></p></div>';
}
// display the admin options page
?>
<div style="width: 620px; padding: 10px">
<h2><?php _e('Me Likey Options'); ?></h2>
<form action="" method="post" id="me_likey_form" accept-charset="utf-8" style="position:relative">
<?php wp_nonce_field('jinx_options_valid'); ?>
<input type="hidden" name="action" value="update" />
<table class="form-table">
<tr valign="top">
<th scope="row">User Role Restriction*</th>
<td>
<select name="jinx_roles[]" id="jinx_roles" multiple="multiple" size="10">
<?php
if (!empty($roles)):
foreach ($roles as $role):
echo '<option value="' . $role . '"' . (in_array($role, $this->defaultOptionVals['roles']) ? ' selected="selected"' : '') . '>' . $role . '</option>';
endforeach;
endif;
?>
</select>
</td>
</tr>
<tr valign="top">
<th scope="row"> </th>
<td>Please select all user roles from the multi-select that you wish to allow access to this plugin.</td>
</tr>
<tr valign="top">
<th scope="row"> </th>
<td>
<input type="submit" name="Submit" class="button-primary" value="<?php _e('Save Changes') ?>"/>
</td>
</tr>
</table>
</form>
</div>
<?php
}
?>
In Summary
Yup, you’re done already. We’ve covered all of the code necessary for you to implement a basic access control list for your plugin. This simple tutorial could easily be expanded to add multiple multi-select dropdowns to restrict role access to different parts of your plugin. The majority of the actual plugin code was left out as it would convolute the actual tutorial. You can download the JinX plugin with full sourcecode from it’s WordPress plugin page. Here’s a quick summary of what we have accomplished with the above code:
- We’ve added an options page allowing selection of user roles.
- We’ve added handling to retrieve the currently logged in user’s role.
- We’ve added handling to the init method to only call core plugin functions for display if the logged in user has one of the selected roles from the config page.

Well written and very useful. Great way to protect content, thank you fo rthe post.