Create a License Controlled Update System: The License Manager Plugin

As great as the official WordPress theme and plugin directories are, there are times when you don't want to use them for distributing your plugin or theme. Maybe it's because you are selling your plugins or themes, or maybe you just want to keep them to yourself, making them only available within your organization or group of friends. 

But what about updates?

If you are the only user, just uploading the plugin or theme manually works quite well. But when you have more users than that, using the Updates admin page inside WordPress would come in handy.

The WordPress Updates functionality has been designed with just the official WordPress plugin and theme directories in mind, but no worries: WordPress has actions and filters that make it possible for us to hook into that functionality and add a server of our own in the mix.

What You'll Learn

In this first tutorial in the series, we will start by creating a WordPress plugin to turn your website into a license management server. In part two, we will continue building the plugin by adding an API to it. In part three, we will use the API to make a WordPress plugin or theme talk back to the license manager for updates. 

While creating the plugin, in this first part, you will learn about the following WordPress plugin development techniques: 

  • Using the WordPress Plugin Boilerplate to get started quickly. 
  • Creating a new custom post type with a meta box for storing custom meta data.
  • Creating a maintainable database table for your plugin.
  • Adding items to that database table.
  • Listing items using WordPress's own list table implementation.

If you want to see the plugin in action, you can download the most recent version of the plugin from WordPress.org. For the exact source code used in this tutorial, check out the linked Tuts+ Github repository (on the right). We'll go through every step of creating the plugin one by one, but if you don't want to build everything from the ground up, following along with the source code is a good way to organize your learning.

Now, let's get to work.

1. Create the Plugin Using the WordPress Plugin Boilerplate

Getting started with a new WordPress plugin consists of a lot of repetitive work that you do over and over again with every plugin you create, such as writing new code or copying and cleaning up old projects.

But there is a better way. 

This time, instead of copying an existing project or starting from scratch, we will use Tom McFarlin's WordPress Plugin Boilerplate, a starting point designed to get you started with a well structured, object-oriented WordPress plugin in no time.  

So, before we start adding our own functionality, let's set up the basic plugin using the plugin boilerplate.

Download the Boilerplate and Make It Your Own

The easiest way to download the plugin boilerplate is to visit the project's web site and download the latest version as a zip file. 

Once you have downloaded and unpacked the zip package, locate the trunk folder inside it, copy it to your preferred location and rename it wp-license-manager

Then, it's time to go through the plugin boilerplate files and make them our own:

  1. Go through all of the files in the plugin directory (and its subdirectories) renaming all occurrences of plugin-name to wp-license-manager and Plugin_Name to Wp_License_Manager. Make sure to rename both the class names and their containing files. This will take a little bit of time and manual work, so using a PHP IDE to help in the renaming is a good idea.
  2. Add the plugin's information to the plugin bootstrap file, now called wp‑license-manager.php and located in the plugin's root directory. You'll find the information in the comment block at the top of the file, right after the PHPDoc tag @wordpress-plugin.

Now, you have created an empty plugin with some basic configuration, and it's just waiting for you to start adding functionality. It's time to build our license manager! 

If you want to read more about using the boilerplate, check Tom McFarlin's tutorial series, Developing Plugins With WordPress Boilerplates. It's based on an earlier version of the boilerplate, but will still give you a deeper understanding of the ideas behind a plugin boilerplate and working with one.

2. Create a Custom Post Type for Products

Our license manager plugin is quite simple and will store and use just two types of data: products and licenses. As products are required for creating licenses (and products are the easier of the two), that's where we'll start.

Here's what you will be building in this section:

WordPress plugin screenshot

product will represent a WordPress plugin or theme you want to manage through your license manager server. Just like a blog post or page, a product has a name and a description. In addition to this, it has a number of additional fields for defining product specific information:

  • Version: The product's version number. This field will be used for checking for updates in parts two and three of this tutorial series.
  • File bucket: The Amazon S3 bucket in which the file is stored. 
  • File name: The file name of the product zip stored in Amazon S3. We'll talk about these file options in part two of the series.
  • Tested with WordPress versionRequires WordPress versionLast updated, Banner high, and Banner low: These options are shown in the plugin update UI in part three of the tutorial series.

Now, let's build this by creating a custom post type and adding a meta box to it.

Step 1: Create the Post Type

The plugin boilerplate divides the plugin's functionality logically into two sections: public facing functionality and admin functionality. While this separation makes sense in most cases, post types are somewhere in between, and you could argue for placing them in either of the two. I decided to go with public.

So, look up the function define_public_hooks inside the class Wp_License_Manager in includes/class-wp-license-manager.php, and add the following new action right after the two wp_enqueue_scripts actions already present:

This line uses the boilerplate's action and filter loader to add an action handler to the WordPress action init. The function, add_products_post_type, goes into the class Wp_License_Manager_Public

Here's the entire function:

Let's go through the function and what it does—in other words, the parameters to the WordPress function register_post_type.

The first parameter, $post_type, (line 6) defines the identifier of the post type used in the WordPress admin links and querying posts of this type (I went with wplm_product to keep it from colliding with post types created by other plugins and themes).

The second parameter (lines 7–28) is an array that defines the properties of the post type (for a full list of options you can use, check the WordPress Codex):

  • labels defines a set of string labels used for referring to the post type in the WordPress admin area.
  • public defines the visibility of the posts of this new type. I wanted products to be browsable by people visiting the site so I set this to true. If, on the other hand, you want to keep products a private thing, just set this option to false.
  • has_archive defines whether WordPress serves an archive page for listing the posts of this type or not.
  • supports defines which post editing features are shown in the post editor.
  • rewrite defines how permalinks for this product type will look. 
  • menu_icon defines the icon to use for the post type in the admin menu. Visit the WordPress Developer site for a full list of dashboard icons available.

Listing, adding, and editing products are now all handled by WordPress. What's left for us to do is to add the meta box with the custom settings listed above.

Step 2: Add a Meta Box for Product Information

Now that we have created the custom post type for products, we have everything we need for storing products in the license management system. But to make the post type more usable, let's continue by adding a meta box for the product specific information.

Here's what the meta box will look like:

Meta box for Product Information

First, let's pick an action for adding the meta box. add_meta_boxes_{post_type} is a great choice: simply add the post type in place of {post_type} and your action gets called just when it's time to add meta boxes for a post of this given type (in our case, wplm_product).

As we're working on the admin area, add the following code in the function define_admin_hooks() inside the main plugin class Wp_License_Manager:

The function, add_product_information_meta_box() in Wp_License_Manager_Admin, simply defines the meta box and a rendering function for displaying its content:

The function contains just a call to the WordPress function add_meta_box that will define the meta box. The parameters in order of appearance are the following:

  1. $id: The HTML id field value for the meta box element.
  2. $title: The title of the meta box, shown at the top of the box.
  3. $callback: The function that will do the meta box rendering.
  4. $post_type: The post type of the page editor on which this meta box should be shown.
  5. $context: Where the meta box should be placed ('normal', 'advanced', or 'side').

Next, add the rendering function we defined in the third parameter:

Line 7: The function begins by reading in the current meta data.

Lines 9–20: If the meta data is empty (it is at this point, actually...), create a default meta data array with empty values.

Line 22: Print out a nonce field that will be used for some added security when saving the meta data. render_nonce_field is a helper function I created to help me with remembering the nonce's name. We'll add it in a little while.

Line 24: Include the actual meta box HTML. The partials directory is a part of the WordPress plugin boilerplate and meant for separating HTML code from the PHP. Here's how the template file for the meta box should look: 

The template is rather straightforward HTML, a series of labels followed by input elements with their values read from the $product_meta array we retrieved in the function above.

Now, with the meta box created, let's take care of saving its data.

Step 3: Save the Meta Box Data

As you have probably noticed by now, when developing a WordPress plugin, adding a new piece of functionality always begins with finding a suitable action or filter for it. 

This is true also for saving the meta box data.

This time, the action to hook to is save_post, an action that is activated whenever a post is saved in the WordPress admin. Again, in the class Wp_License_Manager and its function define_admin_hooks(), add a new line:

The function, save_product_information_meta_box, goes in the Wp_License_Manager_Admin class:

Let's go through the function to see what it does:

  • Lines 7–9: As you remember, we added a nonce field right before rendering the product meta box. In this function, we use that nonce to verify that the person who is posting the data is coming from that form (we'll add the function is_nonce_ok soon).
  • Lines 11–14: Don't save the meta box data when WordPress is doing its periodic auto saves. This is because by default, WordPress doesn't pass the meta box data when it makes an AJAX call to do the autosave, and so updating the meta box data at that point would mess things up.
  • Lines 16–19: Only allow saving the data if the user can edit posts. One thing to consider in the future would be adding a custom capability for editing license manager products.
  • Lines 22–25: Read the existing product meta data, or create a new data array if no meta data has been saved yet (get_post_meta returns an empty string when the meta data item isn't found and the third parameter is set to true).
  • Lines 27–34: Read in the submitted data, doing some basic sanitation.
  • Line 37: Everything is OK, save the data.

Now, before we move on to licenses, let's do that one final thing I've been promising and add the helper functions for rendering and verifying the meta box nonce. 

First, creating one:

The core of this function is the call to wp_nonce_field that does the actual work of creating the one-time token used for the nonce and writing it out in a hidden HTML field.

Then, the check:

The nonce checking function uses the same naming conventions from the function above, and then uses them to retrieve the nonce from the submitted form data (lines 11–15). Then, if the nonce is found, it uses the WordPress function wp_verify_nonce to check that the submitted code matches the saved one (line 17).

3. Add Licenses

We are now about halfway through this first tutorial in the series: products are in place and it's time to take a look at licenses.

A license at its simplest consists of two elements: a license key and a user id (we'll use an email address for it). For more control over the license, we'll also add a third element: a license expiration date, a date after which the license is no longer valid and will not receive updates from our license manager server. 

The admin UI for licenses will be quite similar to the one we created for products: a list of licenses and an option for creating new ones. The implementation, however, will be quite different: while a product matches the post metaphor nicely and was therefore natural to implement as a custom post type, licenses are best implemented using a database table of their own.

Step 1: Create a Database Table

Building the licenses functionality begins with creating the database table that will hold the licenses. The most natural time for creating a new database table is right at plugin activation, before the user has the chance to try and do anything with the table.

The WordPress Plugin Boilerplate makes this easy by providing an empty function that we can start writing our code in. The function, activate, in the class Wp_License_Manager_Activator, is called every time the plugin is activated, either by clicking on Activate in the Plugins menu or when a plugin update finishes. 

First, add the following variable definition at the top of the class:

And then, update the activation function with the following code:

Here's what the function does:

Lines 6–9: Read in the option wp-license-manager-db-version. We will use this option to store the plugin's database version currently active on the site.

Line 11: Compare the current database version with the one defined in the plugin's codebase ($db_version, defined above). If the version number set in the plugin's code is higher than the one stored in WordPress options, a database update is needed. 

Line 12: Run the database update.

Line 13: If the database update was successful, update the option wp-license-manager-db-version to match with the version in code.  

Now, we have created a system for keeping track of database versions and can move to creating the database table. Add the following function to Wp_License_Manager_Activator:

Most of this function is about creating the SQL CREATE TABLE query that we will use for creating the database table:

Line 10: Construct the name for the database table.

Lines 12–18: Some charset definitions that will be used in the final SQL.

Lines 20–29: The SQL for the CREATE TABLE query. The table will have the following columns:

  • id: A unique id for the license row.
  • product_id: The id of the product to which the license is linked.
  • license_key: A string license key used as a password.
  • email: The license owner's email address, which works as the user name.
  • valid_until: The license's expiration date.
  • created_at: The timestamp of when the license was created.
  • updated_at: The timestamp of the most recent update.

Lines 31–32: Use WordPress's database update method dbDelta to create or update the database table. Notice that dbDelta doesn't actually run the CREATE TABLE query as is, but analyzes it and compares it to the current table structure, doing modifications as necessary. 

So, later, if you decide to make changes to the table's structure, instead of writing a new SQL query, you will just edit this CREATE TABLE query, update the $db_version parameter, and let dbDelta handle the rest. 

For more information about creating database tables in WordPress and using dbDelta, read the article Creating Tables with Plugins in the WordPress codex.

And that's it. The next time you activate the plugin, a database table for the licenses will be created. If you have already activated the plugin, you'll need to do it again (deactivate and then activate again) to create the database.

Step 2: Create the License Menu Pages

Now that we have created the database table for storing licenses, let's create the menu pages: "Licenses" and "Add new". 

Again, we begin by hooking to the right action in Wp_License_Manager's function define_admin_hooks:

The action function, add_license_menu_page, goes to Wp_License_Manager_Admin and looks like this:

Let's take a closer look: 

Lines 5–13: Create a top level menu page, with the title, "Licenses". The function, add_menu_page, takes the following parameters:

  1. $page_title: The title of the menu page (HTML title tag value).  
  2. $menu_title: The on-screen title for the menu page.
  3. $capability: The capability required for viewing the page. I used edit_posts, but in the future, I'll probably consider adding a capability of my own in its place.
  4. $menu_slug: The identifier for the menu page, used in the page's URL.
  5. $function: The function that will handle the rendering of this menu page.
  6. $icon_url: This field can be used in many different ways, but I chose to go with the dashboard icons as explained earlier in this tutorial.
  7. $position: The placement of the menu item in the WordPress menu. A problem with using this parameter is that if two menu items have the same $position value, only one of them will be shown. According to WordPress documentation, using a decimal number, as we have done here, helps a little.

Lines 15–22: Add a submenu for listing the licenses. The parameters for add_submenu_page are otherwise identical to those for add_menu_page but the first parameter should be the id of the top menu to which the submenu should be added. 

Also worth noticing is that we point the first submenu to the same action function as the top menu. What this does is that when a user clicks on the top level menu, this first submenu is opened right away.

Lines 24–31: The second submenu is the one we'll start with, the page for adding a new license. 

To make the code run without errors, add two empty functions: 

Step 3: Create the Add New License Page

With the two settings pages created, let's add the functionality to the first one, the "Add New License" page. 

The page will look like this:

Add New License page

As we defined above, the function that will do the rendering for the Add new page is called render_licenses_menu_new. The function itself is simple, with most of its lines spent on populating a list of products that will be used for rendering a drop-down list:

Lines 7–16: Retrieve all published posts of our custom type wplm_product

Line 18: Include the partial that contains the HTML for this menu page.

And here's what goes inside the HTML template:

It's a rather basic form, using a few CSS classes defined in the WordPress admin to make everything look the way a WordPress admin screen is supposed to look.

Some lines that you should pay attention to are:

Line 22: When the user submits the form, it will be posted to WordPress's admin-post.php.

Line 23: Just like with the meta box, add a nonce to make sure someone posting to add a license is actually doing so through this page.

Line 24: Define a hidden field named action with the value 'license_manager_add_license'. This field will be used for adding a handling function for the form's submission—we'll get to this next.

Step 4: Save the License

In the previous step, we created our "Add New License" form. Now's the time to create the functionality for saving it.

Go back to the function define_admin_hooks in Wp_License_Manager and add a new action:

This time, we use admin_post_{action}, a clever action for handling custom forms. 

When a form with the hidden field action is posted, WordPress looks up the field's value and uses it to create call a matching action. The value we used for the hidden field was "license_manager_add_license" and so we can add an action with the name admin_post_license_manager_add_license

The function, handle_add_license, goes to Wp_License_Manager_Admin:

Let's go through the function to see what it does:

Lines 8–10: Verify the nonce added in the HTML form. 

Lines 14–16: Collect and sanitize the submitted license data.

Line 18: Generate a license key. In this plugin, we treat the license key like a password that is always used together with the user's email address, so I decided not to require license keys to be unique. WordPress's password generation function is a simple way to create a random password—probably not the most secure option of all time, but good enough.

Lines 21–40: Save the data to our database table. The first parameter to the insert function in $wpdb is the name of the table. The second is an array with database columns and their values. The third specifies the types of the parameters for formatting the query (%s means a string and is quoted, numeric values specified with %d are left without quotes).

Line 43: Redirect the user to the license list. We'll build it next.

4. List Licenses

Now that we have saved some data for licenses, it's time for the last step in this tutorial: building the list for browsing licenses.

Licenses page in plugin

I always like to make my admin UIs look as much like the WordPress admin itself as I can, and so, when creating this list, I decided to go with the same code that the WordPress core uses for rendering its own lists: the Wp_List_Table class, described as a "[b]ase class for displaying a list of items in an ajaxified HTML table" in its PHPDoc documentation.

The class makes it very easy to create good looking list tables such as the one you see above in WordPress, but it comes with a caveat:

WordPress developers have documented the class as @private, meaning that they reserve the right to change it radically any time they please. In other words, using the class is a risk and means that you'll have to test your plugin carefully before any new WordPress release to make sure the lists are still working. 

If that sounds too risky to you, there is another option: copy the current version of the class into your own project, rename it and use the copied file as your own list's base class. In the end, I decided to go with the copying option myself, to make sure everything works still in the future.

Step 1: Create the List Table Class

First, locate the Wp_List_Table class (it's in wp-admin/includes/class-wp-list-table.php) and copy it to your own project. Make sure to rename the class and file so they won't conflict with the original class from the WordPress core (for example Wp_License_Manager_List_Table).

Then, create a class of your own class to extend this base class. Call the class Licenses_List_Table and place it in the admin directory. Then add the following require_once lines to the function load_dependencies in Wp_License_Manager:

Open your newly created class, Licenses_List_Table, and add a constructor that takes the text domain for localization as a parameter and a field for storing the value. This one doesn't need explanations:

Step 2: Define the List Columns

Wp_List_Table comes with a set of functions that we can override to define the data and formatting rules for the list. 

Let's start by defining the columns to show in the list, their order, and the headers for each column. Add this function to the Licenses_List_Table class.

Notice that the keys in the array need to match with the column names in the database table.

If we don't want to display the created_at column, we can easily hide it using the function get_hidden_columns:

Defining the columns that can be used for sorting the list data is done in a similar way:

Next, let's look at formatting the column data. Formatting can be done in one of two ways: either by defining a custom formatting function with the name column_{column_name} where column_name is the name of the column as listed in get_columns above, or by using a default renderer function, column_default.

Let's use column_default for the columns that are simply printed out. The function takes two parameters: the database row being handled ($item) and the name of the column ($column_name).

Then, let's take an example of the custom output functions. Looking at the plugin source code, you can see that I have created a bunch of those. 

Here's an example, the renderer for the valid_until column:

This renderer displays "Forever" when the value of the field is '0000-00-00 00:00:00' and otherwise the value itself. You get the point.

Step 3: Query List Data

Now that we have defined the rendering settings for the list, let's add some data to the mix. This is done in the WP_List_Table function prepare_items

Here's the function:

Let's go through the function to see what it does:

Lines 8–12: Collect the column header and sorting information using the functions we created above.

After this, the remaining part is about querying data. 

Lines 15–22: Calculate pagination information. If the user has requested a page, the parameter paged contains the page number (starting from 1), so we can use it to calculate the offset for the SQL query.

Lines 24–30: Pass the pagination information to the the list table so it can show the correct navigation buttons when rendering the table.

Lines 33–46: Prepare the sort column and order based on user input.

Lines 49–51: Use the variables defined earlier in the function to do a database query and populate the $items class variable.

And that's it: you have now created a paged and sortable table for displaying the licenses.

Step 4: Use the List Table

Earlier in this tutorial, we created an empty function for showing the contents of the Licenses page. Now that we have created the list table, we can fill that function (render_licenses_menu_list in Wp_License_Manager_Admin) and finally make the licenses visible:

The function first creates an instance of our class, Licenses_List_Table, then calls its function prepare_items (defined above) to initialize the data, and finally includes an HTML template to render the page. 

This template also contains a call to $list_table->display(), which renders the list on the page:

What's Next?

We have now created a basic plugin for storing products and licenses. This is not where it ends, however.

In the second part of the tutorial series, we will continue working on the plugin and extend it with an API that your plugins and themes can use to check a user's license and download updates.

See you next time!

Tags:

Comments

Related Articles