When a plugin is activated, the first order of business is setting up a stable environment so that subsequent runs are smooth and error-free. Nothing is more horrific to plugin developers than hearing from disgruntled users about fatal errors, blank pages or unpredictable issues during plugin activation or update. This article provides you with a checklist of things your plugin should consider doing, so that your plugin can hit the ground running smoothly right the moment your users click the “Activate” button.

Table of Contents

  1. A Dummy Plugin
  2. Register Activation Hook
  3. Flush Rewrite Rules
  4. Initialize Options
  5. Manage Plugin Version
  6. Update Routines
  7. Welcome Screen
  8. Check Dependencies

A Dummy Plugin

Let’s make a little plugin called my-awesome-plugin to help demonstrate all the interesting things we will cover in this tutorial. Create the following folder structure within your wp-content/plugins folder:

It’s up to you how to structure your plugin code, but I usually start with the following simple skeleton:

Alright, you’re good to go!

Register Activation Hook

First order of business is to let WordPress know our plugin wants to do some stuff upon activation. This is quite easy with register_activation_hook(), just call it when the plugin bootstraps:

Flush Rewrite Rules on Activation

Flushing rewrite rules upon plugin activation is very important if the plugin needs to register custom post types (CPT) and / or custom taxonomies. Let’s assume our plugin wants to do that. Modify your bootstrap() function to hook into init and register post types and taxonomies to your heart’s content:

By now you might assume hooking into init is enough, and WordPress would magically regenerate the rewrite rules so that your users can view these CPTs and taxonomies on the front-end right away. Unfortunately, that won’t happen. You need to manually flush the rewrite rules upon activation. You might also think: “That doesn’t seem too hard isn’t it? Just call flush_rewrite_rules() in activate()!”. Something like this:

Well that’s not wrong, but it’s not complete either, because flush_rewrite_rules() alone won’t make any difference in an activation hook. This is because when our user clicks the “Activate” link on our plugin, this is what happens:

  1. The browser loads the plugins.php file.
  2. plugins.php file includes admin.php file. As a result, all other plugins have been loaded, and the init hook has already been called. WordPress doesn’t even know our plugin is activated yet, so of course your register_post_type() function hasn’t been hooked into init. Consequently, your CPTs are not registered.
  3. Then plugins.php calls activate_plugin()
  4. Our plugin is included, and your activate() function is called. Rewrite rules are flushed, but because your CPTs are not registered, nothing really changed.

This chain of events might sound simple and straightforward to you, but it got me every single time I create a plugin. Every. Single. Time. I’ve wasted hours debugging my activation routines wondering why 404 errors comes up whenever I try to access my CPT on the front-end. And then comes the realization that I forgot to initialize the CPT upon activation and flush the rewrite rules. This not only applies to flushing rewrite rules, but whenever you do anything that involves manipulating custom post types and taxonomies upon plugin activation, always make sure init hook has already run, otherwise register them manually:

Also, this applies to themes as well, the only difference is all this activation stuff needs to happen in the after_switch_theme action.

Initialize Options on Activation

Most plugins lets users customize its features via options. We should initialize these options as early as possible, preferably right after the plugin is activated. Uninitialized options are dangerous because they are very hard to debug. If you forget to initialize an option, the value of that option will always defaults to a blank string ''.  Say, you have a my_cpt_posts_per_page option, and you forget to initialize it. Then this will give you a division by error fatal error:

So, rule of thumb, whenever you introduce new options into your plugin, always initialize them upon activation. This is really straight-forward:

Here we prepend our option names with solis_, to prevent collision with other plugins’ options using the same name. Also, by using add_option, if these options have already been initialized, they will not be overwritten, so there’s nothing to worry about.

Manage Plugin Version

It’s often a smart idea to detect whether a previous version of our plugin has been installed or not. This is helpful when you need to migrate or change certain data after each major release is rolled out. In my experience, you’ll need two kinds of version numbers:

  • A formal version number, such as 0.1-dev. This is good for general version detection scenario (for example, display a certain message when the user upgrades from version 0.1 to 0.4).
  • An incremental version number, starting with 1, and incremented by 1 each time there’s a required database update.

Let’s use options to store these two version numbers:

Usually the formal version number (0.1) needs to always be up to date. That’s why we use update_option() on this number. But for the db_ver option, we should only initialize it if it doesn’t already exist. This is because we might need the original value in order to run update routines (explained in the next section). Hence, add_option() is used.

Update Routines

If your plugin is complicated enough, every major release, you’ll find yourself writing code to update your users existing database to accommodate new changes (remember back when custom post types were first introduced?).

Here’s where you take advantage of the DB_VER constant. The main idea is, each time your database schema changes and requires an update on your user’s database, you need to increment the DB_VER by 1, then write a database upgrade routine for the current DB_VER. This would create some sort of an evolution trail of your database schema, which is very helpful when your user needs to upgrade from an ancient version to the  latest one. WordPress itself keeps track of its schema changes this way, so it’s always safe to upgrade from WordPress 2.x to 3.x without much issue.

Let’s use a very contrived example to demonstrate how this works. Let’s say we have an option called solis_coffee_consumed.

So far you’ve consumed no coffee at all, so it makes sense to initialize it at 0. At the end of this v0.1 release cycle, you’ve tallied a total of 22 cups of coffee, and you want to make a big deal out of it by updating the solis_coffee_consumed option using an update routine. Let’s bump the version numbers first:

Then it’s time to call the update routine upon activation.

Nothing will happen if the solis_db_ver option is greater than or equal to the DB_VER constant. If the option is greater than the constant, we need to include the update routines and run the update. Here’s the content of the update.php file in the same folder as my-awesome-plugin.php:

It’s pretty clear from the snippet above what we’re doing:

  • Each update routine is supposed to bring the database schema from version n to version n+1.
  • If the existing database version is a, and the plugin requires the database to be at version b, then update routines a + 1 to b will be executed. Consequently, at the end of the update process, the database schema is at version b.

Alright, remember that our goal for the update routine number 2 is to increment the number of  coffee consumed by 22. So let’s write this simple update routine in update.php:

Now if you deactivate our plugin, and activate it again, and go to wp-admin/options.php, you’ll see that the db_ver option has been bumped to 2, and the amount of coffee consumed is 22 cups!

Plugin Activation Checklist: Database Update

To further illustrate the convenience of our update routine strategy, let’s say you also happen to consume a lot of beer while working on this awesome plugin, and you want the plugin to acknowledge that. This time you’d like to combine the tally for coffee and beer into one single option “solis_beverage_consumed”. So basically this requires two changes:

  • Rename “solis_coffee_consumed” into “solis_beverage_consumed”.
  • Increment the option value by 44, because obviously for every 2 beer you consumed, you need 1 cup of espresso to regain your consciousness.

So let’s bump the DB_VER constant to 3, and initialize the solis_beverage_consumed option (remember our rule of thumb?):

In update.php, let’s write the update routine for DB_VER 3:

Deactivate and activate your plugin again, then go to wp-admin/options.php. You’ll see that all the changes are made successfully.

Plugin Activation Checklist: Database Update

Note that being the perfectionist you are, you might be tempted to delete the solis_coffee_consumed option when updating to DB_VER 3. That would be fine in the majority of cases, but if your plugin is used by a lot of other plugins, or if your users doesn’t like your new version and want to roll back to an earlier version, it’s probably safer to leave the option there. Otherwise, it might break compatibility with third-party plugins or its on older version (backward-compatibility).

Dealing with Plugin Update

OK, we’ve talked about doing an update upon plugin activation. However, the plugin activation hook  is not triggered when our plugin is updated. So what we need to do is to also check for db version change on plugins_loaded. It’s actually quite easy, just hook it up:

Now, for a final test, without deactivating the plugin, if you go wp-admin/options.php, set solis_db_ver to 1, solis_coffee_consumed and solis_beverage_consumed to 0, then submit that form, you’ll see that right away that the db version is bumped back to 3, and beverage consumed is set to 66, because the plugin automatically detects the discrepancy in db versions and runs the update routines accordingly. Isn’t that neat?

Welcome Screen

When you upgrade WordPress to a new version, you’re always greeted by the “About WordPress” page.

Plugin Activation Checklist: Welcome Screen

This helps making a good first impression to your new user, and also familiarize them with changes in a new release. It’s also quite easy to code too. Our plugin’s “welcome screen” is in fact just an Admin Page. The only trick is to display it as soon as your plugin is activated. Let’s create this page:

Now you’ll see a “About M.A.P” plugin item under “Plugins” parent menu.  Next step, we will activate the About screen automatically when our plugin is activated.

Try deactivating and activating our plugin again. You’ll see that you’ll be taken directly to the plugin’s about page. Granted it doesn’t look all that glamorous right now but it’s totally up to you what you want to do with it. You can also take a peek at the source code of WordPress about page for some inspiration.

Check Dependencies

Sometimes a plugin might require that some other plugins (or theme) be installed and activated before it can operate. There are four ways to check whether another plugin or theme is activated:

  • Use function_exists() to check whether a function of that plugin has been loaded.
  • Use class_exists() to check whether a class defined by that plugin exists.
  • Use is_defined() to check whether a constant of that plugin has been defined.
  • Use is_plugin_active(). However this is not recommended because it requires a plugin base path, which obviously changes based on the folder name of the dependent plugin (which the user can set to anything). So this cannot be used as reliably as the first two ways.

Let’s say our plugin depends on bbpress. Upon activation, if bbpress is not activated yet, our plugin should deactivate itself and show an error message. This is not as hard as it sounds:

What we do here is check whether the class bbPress exists and if it doesn’t, trigger a fatal error. WordPress will automatically stop deactivating the plugin and display the error message to the user.

That makes sure our awesome plugin does not activate unless bbPress is already activated. We also need to make sure our plugin turns itself off when bbPress is suddenly deactivated as well. This is also easy:

Conclusion

As you can see, plugin activation is a crucial routine for any plugins. If executed poorly, it not only creates unpredictable and hard to debug errors, but also gives your users a bad first impression and degrades user experience.

Hopefully this article gives you some idea to try on your own plugins. If you have any feedback or ideas, please don’t hesitate to share in the comment section below.