This is a four-part series tutorial covering the WordPress users, roles and capabilities topic. The series will cover the architecture and design of user roles in WordPress; highlight the most important functions for interacting with users and managing roles and capabilities; and in the last two articles, we are going to build a real-life example that demonstrates the usefulness of this API.
Introduction
In the last tutorial, we built a real-life example using the WordPress roles and capabilities system. The system is encapsulated in a single class; and can be used by initializing the class and passing parameters to it. The parameters are the array of users' IDs, another array of roles' names; and also a switch for allowing access to all users. In practice, you want the WordPress Administrator to be able to change those parameters; and thus control which users have a "client_dashboard
" access.
In this tutorial, we'll build the interface which will give the Administrator the ability to automatically initialize our class and feed it with the adequate data. The interface will allow the admin to select roles, users; or opt in for full access.
The code for this new tutorial is available on the same Github repository. To access the previous code, navigate to the first commit of the repository. I've decided the keep the code unlicensed, so you are free to use it and license it as you see fit.
Why Do We Need an Interface?
Unlike users, WordPress provides no interface for roles. You can't add, remove or edit existing roles or capabilities without the help of a third-party plugin. You can, however, have a list of the existing roles in your blog from the dropdown list of role selection when editing an existing user profile. The interface limits you to selecting only one role for a particular user. Also, you can't assign capabilities to users with the default interface WordPress comes with.
For that reason, it's important that your plugin provides the required interface to configure its user access capabilities. Your plugin users should not rely on an external third-party plugin. Depending on the sophistication of your users, and their knowledge of the WordPress platform, they may want to:
- Permit access to all users.
- Limit access to some users.
- Limit access to one or more roles.
- A combination of users, and roles.
If you are a bit confused, here we are talking about a plugin which has two dashboards: One for the blog administrator, which has admin specific features and settings; and another one for select users, which has limited features and settings. So this example doesn't apply to all plugins out there; but only ones that requires admin and client access.
For that, we'll have two different interfaces: One for selecting roles, and another for selecting users. For role selection, we need to build a custom interface because WordPress has no visual interface for them. For user selection, we can leverage the already existing user profile page by adding additional custom fields.
Building the Role Selection Panel
WordPress comes with a small number of pre-defined roles: Administrator, Author, Contributor, Editor, and Subscriber. Knowledgeable WordPress users may add their own roles to categorize and manage their users. Because of that, our interface should fetch all the roles in the site, and offer the option to pick which ones to authorize client access. I also took the opportunity to stick the "all" switch to the same interface. Checking "all" will override your other settings.
Using the WordPress Settings API
To build the interface, we'll use the WordPress Settings API and create a custom function which will display the checkboxes. The following code is used to register the "wptuts_settings
" settings form. We also register a section inside that form; and a field inside the section.
// Registers a new settings form add_action('admin_init', 'wptuts_settings_form'); function wptuts_settings_form() { // Register a new settings form register_setting('wptuts_settings', 'wptuts_settings'); // Register a new section add_settings_section('wptuts_settings', 'General Settings', 'wptuts_section', 'general_settings_form', 'Client Access'); // Register a new field add_settings_field('client_roles', 'Client Roles', 'wptuts_roles_check', 'general_settings_form', 'wptuts_settings', array('client_roles', 'wptuts_settings')); } function wptuts_section() { return null; }
The function add_settings_section()
requires a function as its third parameter which returns the section description. To keep things simple, I passed a function that returns null (or nothing).
The function add_settings_field()
accepts a field ID, a label, a function, the section and form to hook the field to; and the argument to pass to the field function. The field function will output the HTML code of the field.
The WordPress settings API is used to create forms that auto-magically save their content into a WordPress option. The option is "wptuts_settings
", and is an array which has the different settings of our plugin. To make WordPress recognize our form fields, we need first to register them using the functions stated above; and also to assign the right name for each field. So each field will have a name in the form wptuts[field_name]
.
In our case, we have an unpredictable number of roles; and thus an unpredictable number of checkboxes. It doesn't make sense to create and register a field for each role. Luckily, HTML supports array elements; so we name our checkboxes wptuts[field_name][role_1]
, wptuts[field_name][role_2]
, wptuts[field_name][role_n]
... WordPress will recognize this HTML array element and save it as a PHP array.
Below is the content of the "wptuts_settings
" array when the "all
", "author
", and "subscriber
" checkboxes are selected.
'wptuts_settings' => array 'client_roles' => array 'all' => string 'on' (length=2) 'author' => string 'on' (length=2) 'subscriber' => string 'on' (length=2)
Outputting the Field HTML Code
The function linked to the field is "wptuts_roles_check
". It accepts an array which has the settings ID, and the field name; this makes our function reusable in other fields. You can overlook this parameter and hardcode the settings ID and field name into your function.
The function will loop through an array of roles' names returned by "$wp_roles->get_names()
". It'll also unset the administrator role, and add an additional checkbox "all".
/** * Generates the roles checkboxes form * * @param array $param */ function wptuts_roles_check($param) { // Roles list $settings = get_option($param[1]); if (isset($settings[$param[0]])) { $val = $settings[$param[0]]; } else { $val = ''; } // Generate HTML Code // Get WP Roles global $wp_roles; $roles = $wp_roles->get_names(); unset($roles['administrator']); // Generate HTML code if ($val['all'] === 'on') { echo '<input type="checkbox" name="' . $param[1] . '[' . $param[0] . '][all]" id="' . $param[0] . '[all]" checked/> All<br />'; } else { echo '<input type="checkbox" name="' . $param[1] . '[' . $param[0] . '][all]" id="' . $param[0] . '[all]" /> All<br />'; } foreach ($roles as $key => $value) { if ($val[$key] === 'on') { echo '<input type="checkbox" name="' . $param[1] . '[' . $param[0] . '][' . $key . ']" id="' . $param[0] . '[' . $key . ']" checked /> ' . $value . '<br />'; } else { echo '<input type="checkbox" name="' . $param[1] . '[' . $param[0] . '][' . $key . ']" id="' . $param[0] . '[' . $key . ']" /> ' . $value . '<br />'; } } }
Adding Custom User Profile Fields
As covered in the first tutorial of this series, users can have additional data associated with them in the form of key/value pairs. We covered the functions to add, update and remove users' metadata in the second tutorial. In this part, we'll see how to add a section to each user profile page, and update the user metadata accordingly.
Step 1 Hooking to the User Profile
WordPress provides four actions to hook to the user profile page. Two actions to add new fields to the edit page; and two other actions to handle the HTTP POST request. The difference between the "show_user_profile
" action and "edit_user_profile
" action is that the latter passes a WP_User
object for the user being edited. However, the difference between the two other actions is not clear.
/** * User Metabox hooks */ private function metabox_user() { // Display the metabox add_action('show_user_profile', array(&$this, 'display_metabox')); add_action('edit_user_profile', array(&$this, 'display_metabox')); // Save update add_action('personal_options_update', array(&$this, 'update_metabox')); add_action('edit_user_profile_update', array(&$this, 'update_metabox')); }
Step 2 Displaying the Custom Field
Unlike the Settings API, there are no restrictions or requirements to the HTML code the function outputs. WordPress doesn't do the saving of the metadata, so you are free to handle it as you wish.
/** * Display the custom field * * @param object $user */ public function display_metabox($user) { $user_meta = get_user_meta($user->ID, 'wptuts_client', true); if ($user_meta) { $checked = 'checked'; } else { $checked = ''; } print <<<form <h3>Wptuts+ Client</h3> <table class="form-table"> <tr> <th><label for="wptuts_client">Enable Client Access</label></th> <td><input type="checkbox" name="wptuts_client" id="wptuts_client" $checked/> Enable Access to the Wptuts+ Plugin Client Dashboard</td> </tr> </table> form; }
Step 3 Saving the Custom User Fields
As mentioned earlier, we need to handle the saving on a different function. This function is called when the user presses the "Update Profile" button and the HTML form is submitted in a POST request.
/** * Update the user Meta-data * * @param integer $user_id */ public function update_metabox($user_id) { if (isset($_POST['wptuts_client']) && $_POST['wptuts_client'] === 'on') { $checked = true; } else { $checked = false; } update_user_meta($user_id, 'wptuts_client', $checked); }
Updating the Class Initialization
Finally, we need to update our class. In the previous tutorial, our class is constructed with three parameters. We don't need these parameters now; and our function should fetch them itself from the data saved by the interfaces.
We have two sources of data to fetch: the "wptuts_settings
" option and the user metadata. Hopefully, fetching the metadata was made pretty easy with the function "get_users()
" which returns exactly what we need (an array of user IDs) by simply specifying the meta key and value that the user should have.
/** * Set the permission entities * * @param boolean $all * @param array $roles * @param array $users */ private function set_entities() { $settings = get_option('wptuts_settings'); $roles = $settings['client_roles']; // ALL rule if (isset($roles['all']) && $roles['all'] === 'on') { $this->all = true; } else { $this->all = false; } // Roles rule $this->roles = $roles; unset($this->roles['all']); // Users rule $this->users = get_users(array('meta_key' => 'wptuts_client', 'meta_value' => true, 'fields' => 'ID')); }
Conclusion
That's it! Now we have an interface in the WordPress admin for roles and capabilities. Let us know in the comments below what your thoughts are on roles and capabilities, and what features you might add to the class and interface we've created in this series.
Comments