Building WordPress Membership Feature, Part 2: User Registration



In our previous tutorial, we showed how it was possible to make certain components of your site members-only, restricting access to whatever you dictate. Before we get carried away with collecting payment from our members, let’s go over how we might add a registration form.


As before, prerequisites for this tutorial include an intimate working knowledge of PHP and WordPress development, WordPress action and filter hooks, and HTML form building and processing.

The Form

First you need a form. At minimum, the form should collect the prospective member’s email address, first and last names, and maybe a profile description or bio. For expediency, we will auto-create the user’s login based on the email address, as well as generate a random password.

Consider the following form:

<form method="post" action="" id="form-application" name="form-application">
    <h3>Basic Information</h3>
    <table id="section-basic">
                <th><label for="first_name">First Name<span>*</span></label></th>
                <td><input type="text" value="" name="basic[first_name]"><br></td>
                <th><label for="last_name">Last Name<span>*</span></label></th>
                <td><input type="text" value="" name="basic[last_name]"></td>
                <th><label for="url">Website</label></th>
                <td><input type="text" value="" name="basic[url]"></td>
                <th><label for="description">Profile</label></th>
                <td><textarea id="description" name="basic[description]"></textarea></td>
                <th><label for="phone_mobile">Mobile Phone</label></th>
                <td><input type="text" value="" name="basic[phone_mobile]"></td>
                <th><label for="email">Email Address<span>*</span></label></th>
                <td><input type="text" value="" name="basic[email]"></td>

The above form includes the most basic fields. Note that the names of each form element are in array-notation so our form receiver will be looking for an array of fields. Put this form on a page template—let’s call it the “Register” page—where the form should submit to itself. You can then put your logic for submitting the form data in the same template. Now we need to process this data and actually create the user.

        static function add_pending_user($input = null) {
            // return false if is not a valid post array or is null
            if ( is_null($input) || !is_array($input) ) return false;

            // start with email
            $email = sanitize_email( $input[basic]['email'] );
            $username = self::get_username_from_email( $email );
            $first_name = sanitize_text_field($input['basic']['first_name']);
            $last_name = sanitize_text_field($input['basic']['last_name']);
            $description = sanitize_text_field($input['basic']['description']);
            $registered = date('Y-m-d H:i:s');

            // check if email and/or username already occupied
            if (!username_exists( $username ) && !email_exists($email)){
                // generate random password
                $random_password = wp_generate_password( $length=12, $include_standard_special_chars=false );

                // create user with pending permissions
                $new_user_id = wp_insert_user( array (
                    'user_pass' => $random_password,
                    'user_login' => $username,
                    'user_nicename' => $username,
                    'user_url' => esc_url( @$input['basic']['user_url'] ),
                    'user_email' => $email,
                    'first_name' => $first_name,
                    'last_name' => $last_name,
                    'description' => $description,
                    'user_registered' => $registered,
                    'role' => 'pending',
                ) );

                // add all the meta data
                if (! is_wp_error($new_user_id) && $new_user_id > 0) {
                    // unset previously registered fields
                    unset($input['basic']['user_email'], $input['basic']['user_url'], $input['basic']['first_name'], $input['basic']['last_name'], $input['basic']['description']);
                    $total = $count = 0;
                    foreach( $input as $key => $array ) {
                        if ( is_array($array) ) {
                            foreach( $array as $meta_key => $meta_value ) {
                                if ( $meta_key == "payment_code" ) continue;
                                if ( !is_array($meta_value) ) $meta_value = sanitize_text_field($meta_value);
                                else array_walk_recursive($meta_value, 'sanitize_text_field');
                                $success = add_user_meta( $new_user_id, $meta_key, $meta_value, true );
                                if ( $success ) $total++;
                        } else {
                            if ($key == self::$member_type_meta) {
                                $success = add_user_meta( $new_user_id, $key, $array, true );
                                if ( $success ) $total++;

                    return $new_user_id;                    
            return false;

The above code is a static function in our WP_Membership class, which we concluded with in the previous tutorial. The function accepts a single parameter, the full input array. The first part of the function checks that we have valid data and maps out the variables we want to specifically include. The wp_insert_user() method is a native WordPress function to add users programmatically. It accepts an associative array as its parameter, which we retrieve from our input array, and it returns a number corresponding to the newly-created user’s ID.

For any remaining fields in our form, we loop through them and add them to the user’s meta table using the native WordPress function, add_user_meta(). If all is well, the user is added and the method returns a new user ID. You’ll notice we also use a static helper function from the WP_Membership class, get_username_from_email(), in order to sanitize the user’s email address, which will be used as the user’s login. If you remember from the last tutorial, we want our users to login via email address, so the login gets stored as this sanitized value. You must ensure that whatever names you give your form fields, you patch them to the appropriate places in this function.

Conceivably you can simply pass all the input to this function:

$submitted = WP_Membership::add_pending_user($_POST);

After you have received a valid user ID from the above call, you can then proceed to a thank you page or payment page.

Member Role

If you are following along using the WP_Membership class, you’ll notice two other functions that pertain to the user’s role data.


    if ( is_admin() ) {
          add_action( 'set_user_role', array(&$this, 'update_member_role_meta'), 10, 2 );


       function update_member_role_meta( $user_id, $role ) {
           $type = self::$member_type_meta;
           $prev_value = get_user_meta($user_id, $type, true);
           $role = strtolower($role);
           $update = ($role != "pending") ? update_user_meta($user_id, $type, $role, $prev_value) : true;
           $role_changed = self::change_member_type( $user_id, $role );
           return $update&&$role_changed;

In this function, we simply want to update the member’s role information. This is attached to the set_user_role action hook, which activates should the role be changed using the user management page in wp admin. We then call a private method to handle the modification of the role and capabilities in case something gets lost.

        private function change_member_type( $user_id, $role = null ) {
            $roles = array( 'standard', 'premium' );
            $user = new WP_User($user_id);
            $new_role = is_null($role)?$user->get(self::$member_type_meta):$role;
            if ( in_array($new_role, $roles) ) {
                $target_role = get_role($new_role);
                foreach($target_role->capabilities as $cap => $grant){
                    $user->add_cap($cap, $grant);
                return $user->has_cap($new_role);
            return false;

The above function returns a boolean value based on whether the user now has the correct capability. We do this to ensure that the target role is a valid role. We will need this in the next tutorial when we begin handling payments.

Finally, we need to know what type of user the member is applying for. We add an input to the end of the registration form to determine the member type.

<input type="hidden" value="<?php echo $member_type; ?>" name="member_type" />

This can be populated by a $_GET variable passed via the query string like /register?type=premium which could be retrieved by:

$member_type = $_GET[‘type’];

As long as you keep track of this variable, your member will retain the correct membership role that you created before. You can make buttons for each of your types or you can hard-code these values.


We should now have a few things in our arsenal of members-only registration. We have the form, which collects our user’s info; we have the form processor, which takes the user data and creates a user; we have roles and capabilities to prevent unauthorized access to members-only sections; and we have template tags to structure our templates so that certain portions can be members-only. All that remains is a way to collect payments from your users.

If you found this post useful or want to learn more about creating a membership site, be sure to check out Part 3 of this series on Creating the Paywall, or refer back to Part 1.

Illustrations by Cindy Leong

Popular This Week
25 Must-Have Pages for Your E-commerce Website
January 30, 2015

25 Must-Have Pages for Your E-commerce Website

By Yvonne Weng
Building a Responsive jQuery Carousel Plugin from Scratch
November 26, 2014

Building a Responsive jQuery Carousel Plugin from Scratch

By Max Rolon
Taking Control of Image Loading
July 29, 2013

Taking Control of Image Loading

By Patrick Kunka
Text-align: Justify and RWD
March 12, 2013

Text-align: Justify and RWD

By Patrick Kunka

Like what you’re reading? Sign up for the Barrel newsletter and receive updates.