WordPress
Article

WordPress Plugin Updates the Right Way

By Jérémy Heleine

Some weeks ago, I received an email about WP Photo Sphere, a WordPress plugin I developed. There was a big problem: updating the plugin broke it on some installations. After some investigation, I discovered that the problem came from the options used by the plugin: these installations hadn’t any default values for the new options I added.

WordPress Plugin Updates

These values were important, so I needed a way to create the default values. But, contrary to what I thought, WordPress doesn’t provide any native way to handle an update process.

That’s why I thought of writing this tutorial. First, we’ll see exactly why we need an update process and why WordPress doesn’t provide such a process. Then I’ll show you how to properly create your own process to update your options.

Why an Update Process for Your Plugin Is Important

Often, changing files is not enough to properly update something. For example, when you manually update the WordPress files to a new version, the platform will ask you to hit a button to update the database too.

Assume that you use options in your plugin. As your plugin evolves, you’ll need more options in new versions. Creating new options when a user activates your plugin for the first time is easy, you just have to use the activation hook.

For example, let’s look at the following code.

function my_awesome_plugin_activation() {
    update_option('my_awesome_plugin_option', 'default value');
}
register_activation_hook(__FILE__, 'my_awesome_plugin_activation');

If you’re unfamiliar with using update_option() instead of add_option(), don’t worry, we’ll explain it later, when we’ll look at how to handle our update process.

If you want a new option, or if you update the value of an existing option in a new version, you need to update the database of users who already use your plugin, so we need a function called right after the update.

The activation hook can seem a bit confusing. After all, when you automatically update a plugin, it is deactivated and reactivated, so we could expect this hook to be called. But it’s not the case.

To be more precise, it was, but WordPress stopped this behavior in version 3.1. The development team explained this choice, and you can read the entire explanation on the Make WordPress Core blog. The main reason is that it wasn’t called every time is that if a user manually updates a plugin, the activation hook can be skipped.

So WordPress doesn’t provide a default way to automatically call a function right after a plugin update. That’s why you’ll need to build your own process.

How To Handle an Update Process

In this part of the tutorial I’ll show you how to automatically call a given function right after an update of your plugin. We’ll see in the next part how to properly handle the updates of existing options, and the creation of new ones (in the same function).

The Principle of this Method

The global principle of our method will be that we’ll store the version number of our plugin in two places: in a constant in the main file of the plugin, and in an option in the database.

The number in the database will store the version currently installed by the user, while the number in the constant is the current version. If these two numbers are different, then the database options have not been updated since the last plugin update, so we’ll need to do it.

In this case, we call a function that updates all the necessary options. This function also updates the version number stored in the database: that way, we won’t call this function more than necessary.

The Constant

Now that we’ve covered what we’ll do, it’s time to code! First, add a constant definition in the main file of your plugin, with your current version number as a value. In order to prevent any problems, we test if it does not exit yet.

if (!defined('MY_AWESOME_PLUGIN_VERSION'))
    define('MY_AWESOME_PLUGIN_VERSION', '3.4.1');

Usually, plugin versions are identified with numbers but, if you use another system, feel free to use it. The only constraint here is to have a unique identifier for each version or, at least, for each version which requires changes in the database (new options, new default values, etc.).

The Checking Function

We need now to write a function that will check if the database needs to be updated. This function will compare the previously defined constant with the value currently stored in the database. To do that, we’ll make sure that our function is called everywhere, with the action plugins_loaded, triggered once all the plugins are loaded.

function my_awesome_plugin_check_version() {
}

add_action('plugins_loaded', 'my_awesome_plugin_check_version');

This function will be simple. We retrieve the version number stored in the database, as any other option, and we compare it to the constant. If these values are different, we call the my_awesome_plugin_activation() function.

if (MY_AWESOME_PLUGIN_VERSION !== get_option('my_awesome_plugin_version'))
    my_awesome_plugin_activation();

Now, there are some questions we need to clarify. First, what if the option doesn’t exist in the database yet? If the option doesn’t exist, get_option() returns false, which is different from your version number, so the function will be called.

So why do we call the activation function? To be clear, we could create a new function, dedicated to the update process. But, if you do this, you’ll see that this new function will be very similar to activation, as updating an option can be achieved the same way we create one.

Updating the Version Number in the Database

You can do whatever you want in the activation function called above. However, there is one thing needed, updating the version number stored in the database. That way, we won’t call our function every time a page is loaded.

update_option('my_awesome_plugin_version', MY_AWESOME_PLUGIN_VERSION);

Note the trick: we don’t use add_option(), just update_option(). In fact, if the option does not exist yet, update_option() will create it. If it exists, it will update its value to the indicated one. That’s why we can use our activation function as an update function without any problem.

Updating Options

Don’t Override Users’ Choices!

Updating any option can be done the same way we updated the version number: you call update_option(), and you’re done, even if it’s the first time WordPress sees the option.

However, we don’t always want to update the options values. In fact, if you use options, it’s often for letting your users personalize settings. By using update_option() you’ll override the users’ choices every time you update the plugin, which is not what we want to do.

Above, we saw that get_option() returns false if the option doesn’t exist. We’ll use this behavior to test if the option we want to update exists in the database. If this is the case, we don’t do anything. Otherwise, we create the option.

if (get_option('my_awesome_option') === false)
    update_option('my_awesome_option', 'my_value');

Note that this test is necessary for options you don’t want to override. In some cases, we might want to do this, think about the version number, where we surely don’t want to keep the old value!

A Special Case – Arrays

You should know that WordPress allows arrays to store values for our options, and creating them is not any more difficult that creating other options. For example:

update_option('my_awesome_plugin_settings', array(
    'awesome_titles' => true,
    'any_number' => 7
));

Using arrays is a good idea if you need several settings. That way, you don’t use a lot of entries in the database, and you limit the chances to have an option with the same name used by another plugin. However, this can cause issues when we think about the update process.

To understand why, assume that you have an array as an option, with some keys. Your users will surely personalize these values. With the test we did above, we can create the option only if it does not exist, and these choices won’t be overridden. It seems straightforward, but what if you want to create a new key in your array?

If the option exists in the database, the previous code won’t create it, so your new key won’t exist. But if we erase the condition, the array will retrieve its default values with each new update. Not ideal. Fortunately, there’s a solution!

First, we define an array containing the default values of our options (with the new keys if they exist).

$default = array(
    'awesome_title' => true,
    'any_number' => 7,
    'new_option' => 'default'
)

Then, we retrieve the array currently stored in the database.

$option = get_option('my_awesome_plugin_settings');

Now we can use the PHP function array_merge(), with our default values array as the first parameter, and the user’s values array as the second one. That way, we’ll get an array containing all of the keys defined in the $default array and we won’t have any non-existing options. If the user has changed one of the old options, their values will be kept. With array_merge() we always keep the latest definition.

$option_to_store = array_merge($default, $option);

Finally, we store the result in the database with update_option().

update_option('my_awesome_plugin_settings', $option_to_store);

We’re close to the end, but we now need to fix a bug that you can run into if the function is executed for the very first time.

This function is called when the plugin is activated, that’s what we want. But, in this case, the option does not exist yet, so get_option() returns false. The problem is that using false as a parameter for array_merge() will cause an error.

What we want is simple, if the option doesn’t exist, we want $option to be an empty array. For that, we can use the second parameter of get_option() which represents the default value to get (in order to not return false).

$option = get_option('my_awesome_plugin_settings', array());

Conclusion

Once you’ve gone over it, handling the update process for a WordPress plugin is not overly complicated. However, it’s important if you use options, since not initializing options can cause some problems.

Currently, WordPress doesn’t provide a native way to handling plugin updates. The fact is, considering the problems we listed above, if we see this type of feature introduced one day, it should be implemented in a similar way to this tutorial.

You can get the code for my example plugin here. Treat this code as a skeleton for you to implement your own WordPress plugin update process. If you have any feedback, please let me know in the comments below.

No Reader comments

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Instant Website Review

Use Woorank to analyze and optimize your website to improve your website to improve your ranking!

Run a review to see how your site can improve across 70+ metrics!

Get the latest in WordPress, once a week, for free.