In this section, we’ll go over how to instantiate a WordPress user object in code and how to get basic user information, like login and email address, and user metadata out of that object.
The workhorse for managing WordPress users in code is the
WP_User class. Just like anything else in WordPress and PHP, there are a few different ways to get a WP_User object to work with. Here are some of the most popular methods:
Once you have a WP_User object, you can get any piece of user data you want:
Data stored in the
wp_users table (
display_name) can be accessed using the arrow operator, for example,
Any value in the
wp_usermeta table can also be accessed by using the arrow operator, for example,
$user->meta_key, or by using the
get_user_meta() function. These two lines of code produce the same result:
It’s useful to understand the trick WordPress is using to allow you to access user meta on demand as if each meta field was a property of the WP_User class. The WP_User class is using overloaded properties or the
__get() “magic method.”
With magic methods, any property of the WP_User object that you try to get that isn’t an actual property of the object will be passed to the
_get() method of the class.
Let’s analyze this. The method first checks if a value exists in the
$data property of the WP_User object. If so, that value is used. If not, the method uses the
get_user_meta() function to see if any meta value exists using the key passed in.
Because we’re loading meta values on demand this way, there is less memory overhead when instantiating a new WP_User object. On the other hand, because meta values aren’t available until you specifically ask for them, you can’t dump all metadata on a user using code like
print_r( $user ) or
print_r( $user->data ).
To loop through all the metadata for a user, use the
get_user_meta() function with no
$key parameter passed in:
Knowing how WordPress uses the
__get() function is interesting, but also important so you avoid a couple of the limitations of the
__get() magic method.
__set() methods are not called when assignments are chained together. For example, the code
$year = $user->graduation_year = '2012' would produce inconsistent results.
__get() is not called when coded within an
isset() function call. So
if(empty($user->graduation_year)) will also be false, even if there exists some user meta with the key
The solution to these two issues is to get a little more verbose with your code:
We touched on some basic functions for adding, updating, and deleting users in Chapter 2, but since working with user data is such an important part of any web application, we will do a brief overview with some additional examples and different use case scenarios here.
Occasionally, you will need to add users through code instead of using the WordPress dashboard. In our SchoolPress app, we might want to allow teachers to enter a list of email addresses and generate a user for each email entered.
Or maybe you want to customize the registration process. The built-in WordPress registration form is difficult to customize. It’s often easier to build your own form and use WordPress functions to add the user yourself on the backend.
As you should already know, the function for adding a user to WordPress is
wp_insert_user(), which takes an array of user data and inserts it into the
The following code will automatically log someone in after adding that person’s user. The
wp_signon() function authenticates the user and sets up the secure cookies to log the user in:
Updating users is as easy as adding them with the
wp_update_user() function. You pass in an array of user data and metadata. As long as there is an ID key in the array with a valid user ID as the value, WordPress will set any specified user values:
user_login cannot be updated through
wp_update_user. Also, if a user’s
user_pass is updated, the user will be logged out. You can use the preceding auto-login code above to log the user back in using the new password.
You can also update one user meta value at a time using the
update_user_meta($user_id, $meta_key, $meta_value, $prev_value) function.
The following code segments illustrate some more features:
Note that in the code, I show two different ways to store arrays in user meta. This is similar to storing options via
update_option() or post meta via
update_post_meta(). The first method (one serialized value per key) keeps row count down on the
wp_usermeta table, which can make queries by
meta_key faster. The second method (multiple values per key) allows you to query by
meta_value. For example, storing child names as separate user meta entries lets you do queries like this:
While it’s possible to query the
wp_postmeta tables by
meta_value, be careful about query times. The
meta_value column is not indexed, and so queries against large datasets may be slow. Many-to-one relationships like this can also be stored in custom taxonomies, which can show better performance.
Deleting a user, while dangerous, is incredibly easy to do in code:
For network site setups, you will need to use the
wpmu_delete_user() function to delete the user from the entire network. Otherwise
wp_delete_user() just deletes the user from the current blog. You can use the
is_multisite() function to detect which function should be used:
Perhaps more common than adding and updating user data yourself are scenarios where you want to do some other bit code when new users are added or deleted. For example, you may want to create and link a new CPT post to a user when she registers. Or maybe you want to clean up connections and data stored in custom tables when a user is deleted. This can be done through some user-related hooks and filters.
The hook to run code after a user is registered is
user_register. The hook passes in the user ID of the newly created user:
The hook to run code just before deleting a user is
delete_user. A similar hook
deleted_user (note the past tense) runs just after a user has been deleted.
These hooks are mostly interchangeable, but there are a couple things to note:
- If you hook on
delete_userearly enough, you might be able to abort the user delete.
- If you hook on
deleted_user, some user data and connections may already be gone and unavailable:
Roles and capabilities are how WordPress controls what users have access to view and do on your site. Each user may have one role, and each role will have one or many capabilities. Each capability will determine if a user can or can’t view a certain type of content or perform a certain action.
There are five default roles in every WordPress install: Admin, Editor, Author, Contributor, and Subscriber. If you are running a network site, you’ll have a sixth role, Super Admin, which has admin access to all sites on the network.
A full list of capabilities and how they map to the default WordPress roles can be found on the WordPress Codex Roles and Capabilities page.
In a little bit, we’ll go over how to create new roles outside of the WordPress defaults. However, for most apps it makes sense to stick to the default roles: have your app administrators use the Admin role and have all of your users/customers use the Subscriber role.
If your app users will be creating content, consider making them Authors (can create and publish posts) or Contributors (can create, but not publish posts). If your app has moderators, consider making them Editors.
Using the default roles is a good idea because certain plugins will expect your users to have one of these roles. If your admins are really users with an office manager role, you may have a bit of extra work to get a third-party plugin to work with those users. The opposite is sometimes true as well. You might have to hide functionality made available to your users based on the roles they have, especially if you are using roles outside of Admin (access to everything) and Subscribers (can just view stuff).
Sometimes you’ll need to check if a user is able to do something before you let her do it. You do this with the
current_user_can() function. This function takes one parameter, which is a string value for the
$capability to check. The following code illustrates the usage of this function:
You can also use the function
user_can() to check if someone other than the current user has a capability. Pass in the
$user_id of the user you want to check, the capability, and any other arguments needed:
While it is possible to check for a user’s role using
current_user_can(), it is better practice to test a user’s capabilities instead of her role. This will allow your code to continue to work even if users are given different roles or roles are assigned different capabilities. For example, checking for
manage_options will work how you intend whether the user is an Admin or a custom role with the
manage_options capability added.
Testing a user’s role should be limited to cases where you really need to know her role instead of her capability. If you find yourself checking for someone’s role before performing certain actions, you should take it as a hint that you need to add a new capability.
The following is a function to upgrade any Subscriber whose ID is passed in to the Author role. To be extra sure, we check the roles array of the user object instead of using the
user_can() function. We use the
set_role() method of the user class to set the new role:
As we said earlier, it’s a good idea to stick with the default WordPress roles if possible. However, if you have different classes of users and need to restrict what they are doing in new ways, adding custom roles and capabilities is the way to do it.
In our SchoolPress app, teachers are just Authors and students are just Subscribers. However, we do need a custom role for office managers who can manage users but cannot edit content, themes, options, plugins, or the general WordPress settings. We can setup the Office Manager role like so:
add_role() function is run, it updates the
wp_user_roles option in the
wp_options table, where WordPress looks to get information on roles and capabilities. So you only want to run this function once upon activation instead of every time at runtime. That’s why we register this function using
We also run
remove_role('office') at the start there, which is useful if you want to delete a role completely, but is also useful to clear out the “office” role before adding it again in case you edited the capabilities or other settings for the role. Without the
remove_role() line, the
add_role() line will not run since the role already exists.
add_role() function takes three parameters: a role name, a display name, and an array of capabilities. Use the reference in the Codex to find the names of the default capabilities or look them up in the /wp-admin/includes/schema.php file of your WordPress install.
Adding new capabilities is as simple as including a new capability name in the
add_role() call or using the
add_cap() method on an existing role. Here is an example showing how to get an instance of the role class and add a capability to it:
Again, this code only needs to run once, which will save it in the database. Put code like this inside of a function registered via
register_activation_hook() just like the last example.
You can also use the
remove_cap() method of the role class, which is useful if you want to remove some functionality from the default roles. For example, the following code will remove the
edit_pages capabilities from Editors so they can edit any blog post, but no pages (post of type “page”):
You can do some powerful things by adding and editing roles and capabilities. Defining what users have access to view and do is an important part of building an app. Different roles can be built for different membership levels or upgrades associated with your product.
We can extend the WP_User class to create useful classes that will help us organize our code related to different types of users.
And here is how that code would look in a less object-oriented way:
Both blocks of code are functionally equivalent, but the first example is easier to read and work with. Perhaps more importantly, having all of your student-related functions coded as methods on the Student class will help keep things organized.
Here are the initialization and
getAssignments() method for the Student class:
Above we define the Student class to extend the WP_User class by just adding
extends WP_User to the class definition.
We don’t write our own constructor function because we want to use the same one as the WP_User class. Namely, we want to be able to write
$student = new Student($user_ID); to get a Student/User by ID.
getAssignments() method uses the
get_posts() function to get all posts of type “assignment” that are authored by the user associated with this Student. We store the array of assignment posts in the
$data property, which is defined in the WP_User class and stores all of the base user data and metadata. This allows us to use code like
$student->assignments to get the assignments later.
$student->assignments is a defined property of $student, the value of that property will be returned. But if there is no “assignments” property, PHP will send “assignments” as the
$key parameter to your
__get method. Here we check that
$key == "assignments" and then return the value of the
getAssignments() method defined later. If
$key is something other than
"assignments” we pass it to the
__get() method of the parent WP_User class, which checks for the value in the
$data property of the class instance or failing that sends the key to the
At first blush, all this does is allow you to type
$student->assignments instead of
$student->getAssignments(), which I suppose is true. However, coding things this way allows us to cache the assignments in the
$data property of the object so we don’t have to query for it again if it’s accessed more than once. It will also make your code more consistent with other WordPress code: If you want the student’s email, it’s
$student->user_email; if you want student’s first_name, it’s
$student->first_name; if you want the student’s assignments, it’s
$student->assignments. The person using the code doesn’t have to know that one of them is stored in the
wp_users table, one is stored in
wp_usermeta, and one is the result of a post query.
It’s very common to need to add additional profile fields for users in your app. In the previous section, we discussed how to use the
update_user_meta() functions to manage those values. In this section, we’ll go over how to add editable fields for our user meta to the registration and profile pages.
In our SchoolPress app, we need to capture some data about our users. For students, we want to capture their graduation year, major, minor, and advisor’s name. For teachers, we want to capture their department and office location. For both types of users, we want to capture their gender, age, and phone number.
There are a few different plugins out there that will help you do this more quickly.
Full instructions on how to use PMPro Register Helper and the syntax for defining fields can be found in the plugin’s readme file. Instead of covering that here, let’s go through adding one field to the register and profile pages by hand using the same hooks and filters PMPro Register Helper uses.
if ( ! empty( $_REQUEST['age'] ) ) to avoid a PHP warning when users first visit the registration page and there isn’t any form data in $_REQUEST yet.
We need to hook into both show_user_profile and edit_user_profile to show our custom field both when users are viewing their own profile and when admins are editing other users’ profiles:
Note how the default WordPress registration page HTML uses
<p> tags to separate fields, while the default profile HTML in the dashboard uses table rows.
Again, we’re hooking into two separate hooks. One for when users are viewing their own profile, and one for when admins are editing other users’ profiles.
So that’s how you add a field to the registration and profile pages. Just iterate through that for each field you want to add (or piggyback on plugins like PMPro Register Helper to do it for you), and you’re good to go.
With all of this extra metadata for our users, it is sometimes necessary to extend the basic users list table in the WordPress dashboard.
You can create your own admin page, with custom queries, and a report that mimics the style of the dashboard list tables (that’s what we did for the “Members List” in Paid Memberships Pro). Or you can use hooks and filters provided by WordPress to add columns and filters to the standard user list, which is what we will cover here.
To do this, we use the
manage_users_custom_column filters. Let’s add our age field to the user’s list:
manage_users_columns filter passes in an array containing all of the default WordPress columns (and any added by other plugins). You can add columns, remove them (using
unset( $columns['column_name' ])), and reorder them. The keys in the
$columns array are unique strings to identify them. The values in the
$columns array are the headings for each column.
manage_users_custom_column filter is applied to each column in the
manage_users_columns array that isn’t a default WordPress column (i.e., any custom column you add). In the
sp_manage_users_custom_column() callback, you can do any calculations needed to get the values for each custom column. Typically the function contains a large if/then/else block or a switch statement checking the value of
$column_name and returning the correct value for each column.
If you use the preceding code, you will get an
Age column added to your users page, but by default you won’t be able to click on it to sort the users list by age like you can with some of the default users list columns. Here’s the code for that:
Above we define
Age as a sortable column with the
manage_users_sortable_columns filter. We use the
pre_user_query filter to detect the
&sortby=Age parameter on the users list page and update the
$user_query object to join on the
wp_usermeta table and order by age. Notice how we use the
$current_screen global, which is set in the admin, to make sure we are on the users list page before editing the query.
Now that you’ve seen how to customize various aspects of the WordPress user management system, let’s go over a few user-related plugins that will make your life building web apps a little easier.
Your members don’t have to know that your site is built on WordPress. Part of that is using a login form that is integrated seamlessly with your site design rather than the default WordPress login. The Theme My Login plugin does this perfectly. Traffic to wp-login.php is redirected to a login page that looks like the rest of your site instead of the WordPress backend.
Theme My Login also has useful modules for theming user profiles, hiding the dashboard from non-admins, and controlling where users are redirected on login and logout.
This plugin does exactly what the title states. Only administrators will see the WordPress admin bar when browsing the frontend of your site. The plugin is just a few lines of code and can be edited to your needs, for example, to let editors and authors view the admin bar.
Paid Memberships Pro is brought to you by Stanger Studios and allows you to monetize the content on your site by creating a membership community. This is ideal for any business or blogger looking to lock down some or all of the content or collect fees for services provided. This plugin easily integrates with payment gateways such as Stripe, Paypal, and Authorize.net. Settings for recurring or one-time payments are included. Paid Memberships Pro allows for the creation of different membership levels within your site.
The Register Helper plugin was initially programmed to work with Paid Memberships Pro, but can be used without it as well. This plugin simplifies the process of adding extra fields to the registration and profile fields. Instead of a set of three hooks and functions for each field, fields can be added in a couple lines of code like:
The Register Helper plugin also has shortcodes to insert signup forms into your pages and sidebars and modules to act as starting points for your own registration, profile, and members directory pages.
The Members plugin extends the control that you have over user roles and capabilities in your site. It enables you to edit as well as create and delete user roles and capabilities. This plugin also allows you to set permissions for different user roles to determine which roles have the ability to add, edit, and/or delete various pieces of content.
You could always write your own code to add roles and capabilities, but Members adds a nice GUI on top of that functionality that is often useful.