Posted by on in iDevelop, PHP | 2 comments

If you develop stuff on WordPress, chances are you’ll be familiar with the plugin activation and de-activation hooks. But should they be used? Or are they to be avoided? Now that’s a bit of a tricky question, as there are compelling reasons for both sides and not all are applicable to generic scenarios but deal with specific use-cases, so the decision to use them or not is subjective.

The plugin activation/de-activation hooks were implemented as people developing plugins for WordPress wanted a standard app installation kind of experience, ie., the plugin should be able to initialize some default settings or options, perform some specific tasks when its installed (activated) and clean up after itself when its uninstalled (de-activated). Now that is all good but what happens when you run into situations when you have to use plugins where you can’t do the standard activation/de-activation? When then?

Now you might be wondering why the heck the plugin page wouldn’t be accessible for the activation or de-activation of plugins. Lets try an example. Lets say you host your WordPress install currently, so you have all the things WordPress has available to you. But then you decide to shift to the excellent service provided by VIP, the robust stack of along with the goodness of your own custom code. Now you can use whatever plugins you want if they’re not already provided by VIP (provided that they pass the review done by the VIP team), but you won’t get the plugin manager section that you get in your own WordPress install. Reason? Its simple, while WordPress can do multiple websites on a single common install of the code, at present it does not provide the feature of a separate plugin manager for each website that it runs. Since there are other websites besides yours running on, you can’t get the plugin manager. So how do you use your own plugins? You load them up in your theme using the wpcom_vip_load_plugin() that is available to you on VIP platform. Essentially this function just does an include_once() on your plugin’s PHP file, that’s all. So the plugin activation or de-activation hooks of WordPress are not fired at all and if you depend on those to initialize your plugin, well, you’ll get stuck in a jam! 😉

Another scenario can be that you made some nifty plugin. Now if you make a theme that you’ll distribute to others (for free or for fee, doesn’t matter) & you decide to leverage that plugin’s features into your theme, the right way is to include the plugin as a library in the theme rather than providing it separately and asking users to upload it to plugins directory & activating the plugin. Frankly, asking users that would be dumb & unprofessional. They might be tech savvy or they might not be, your theme should be put in themes directory & activated in WordPress admin & that should be it, it should just work straight away. So again, if your plugin (which you included in your theme as a library) depends on plugin activation or de-activation hook, you’ll be stuck!

So to make your plugin suitable for the usual way and for such inclusions in themes, its best that you handle the initialization of your plugin yourself. Its not hard nor is it rocket science, some might say its re-inventing the wheel but thats what you’ll have to do if the current wheel is not suitable for you. You gotta do what you gotta do!

Here’s a quickie on how you might wanna do it:

  1. define( 'MY_PLUGIN_VERSION', '2.0' );
  3. class My_Plugin {
  5.     public function __construct() {
  6.         //call the init function for a quick check
  7.         $this->_init();
  8.         //... some other mundane constructor tasks
  9.         //... that you might wanna do
  10.     }
  12.     private function _init() {
  13.         $current_version = get_option( 'my-plugin-version', false );
  14.         if( $current_version == MY_PLUGIN_VERSION ) {
  15.             //no upgrade or new install, bail out
  16.             return;
  17.         }
  18.         switch( $current_version ) {
  19.             case '0.5':
  20.                 //upgrade DB from v0.5
  21.                 break;
  22.             case '1.0':
  23.                 //upgrade DB from v1.0
  24.                 break;
  25.             default:
  26.                 //new installation
  27.                 break;
  28.         }
  29.         //add or update the plugin version
  30.         update_option( 'my-plugin-version', MY_PLUGIN_VERSION );
  31.     }
  33.     //.. your other plugin code can come here
  35. }
  37. add_action( 'init', 'my_plugin_loader' );
  39. //init the plugin class
  40. function my_plugin_loader() {
  41.     if( ! isset( $GLOBALS['my_plugin'] ) ) {
  42.         $GLOBALS['my_plugin'] = new My_Plugin();
  43.     }
  44. }

Its pretty simple & straight forward, the _init() function is called whenever an object is created and it runs a quick check on the plugin version in database against the current version contained in the constant. If the versions match then it exits, else it sees whether the settings need to be upgraded from earlier version or is it a new installation of the plugin and then it acts accordingly.

This approach will also take care of things on plugin upgrade because from WordPress v3.1 the plugin activation hook is not fired on plugin upgrades, its fired only on plugin activation. So if you need to run an update on any settings in the database, you can’t use the plugin activation hook anymore. 🙂

If you are wondering why I used the update_option() instead of add_option() if its a new install, the reason is that update_option() will add the option if it doesn’t exist and it will also be set to autoload everytime WordPress initializes. Since we’ll be checking this option on every init, it doesn’t make sense to fetch it specifically from databse when WordPress can fetch it & cache it.

This was just an example on how a plugin init can be done without depending on plugin activation hook, this way the plugin will be usable anywhere, on your self-hosted WordPress install or in a theme you’re distributing and also on hosted services like VIP. You can expand on this technique, separate the initialization process from the main plugin, make it modular by having different update scripts and loading the appropriate upgrade/install script as necessary. Personally I think making it modular and having upgrade/install scripts in their own files is a better approach, keeps things clean and you load only what you need rather than have a bunch of unnecessary code loading up in memory everytime the plugin is loaded.