WordPress Plug-in Self Deactivation

WordPress 3.5 is almost upon us, and I was excited to learn that my Sort Query by Post In plug-in had been folded into core, thanks to a ticket I opened and submitted a patch for some time ago. Sort Query by Post In allowed developers to return posts from a post query (WP_Query) in the order designated using the post__in parameter.

Now that identical functionality is in core, I wanted to update my plug-in to automatically disable itself – with a notice – for users running 3.5 or newer. This code would also prevent the plug-in from being activated if installed on 3.5 or newer. Surprisingly, there seemed to be a dearth of good tutorials, so I came up with my own solution.

Trick #1 – which isn’t really that tricky – was getting the plug-in to deactivate itself, and notify the user of the change. Trick #2 – a bit more tricky – was preventing new activations without showing an ugly and scary warning message on the plug-in activation screen.

Here’s how it works:

if ( version_compare( floatval( get_bloginfo( 'version' ) ), '3.5', '>=' ) ) {

     if ( current_user_can( 'activate_plugins' ) ) {

          add_action( 'admin_init', 'my_plugin_deactivate' );
          add_action( 'admin_notices', 'my_plugin_admin_notice' );

          function my_plugin_deactivate() {
              deactivate_plugins( plugin_basename( __FILE__ ) );
          }

          function my_plugin_admin_notice() {
               echo '<div class="updated"><p><strong>Plug-in name</strong> was folded into WordPress core in 3.5; the plug-in has been <strong>deactivated</strong>.</p></div>';
               if ( isset( $_GET['activate'] ) )
                    unset( $_GET['activate'] );
          }

     }

} else {
     ... normal plug-in code ...
}

So let’s break this down a bit.

You can retrieve the current WordPress version using get_bloginfo(‘version’) (or the global $wp_version). If you’re not running a final / stable release (i.e. a beta or trunk), that doesn’t return just a number, but something like “3.5-beta2-…”. PHP’s floatval will take care of stripping that down to a comparable numeric version, and we can use PHP’s version_compare to reliably compare against the version number we’re looking for.

If we pass the “deactivate / don’t run this” test, I than recommend another test to check the current user’s right to activate_plugins (only administrators, out of the box). This will ensure that Joe subscriber doesn’t see a plug-in deactivation message, and that the next administrator to log-in does.

I add two hooks. The admin_init hooks runs when the admin dashboard is loaded; this will ensure it doesn’t deactivate until a message can be shown, and also ensures that plug-ins have been loaded up before we run our deactivation code. The callback simple executes WordPress’s deactivate_plugins function.

The second hook,  admin_notices, will allow us to show a notice / message in the admin, and also conveniently runs right before the code that generates the “Plug-in activated” or error message generated by activating a plug-in. In the callback, I echo out the desired, formatted notice, and, should it be set (translation: should the administrator have just activated the plug-in), unsets the $_GET parameter (activate) that core code checks to determine whether and what message to show after attempting to activate a plug-in.

The result is a clean deactivation (even if the plug-in was just activated), with a clear message!

7 Comments

  1. George Stephanis

    You don’t need to floatval() it first — version_compare is designed to take a string like 3.5-alpha or 3.5-RC2 and successfully compare it against 3.4, 3.5-beta4, or 3.7.1

    http://php.net/manual/en/function.version-compare.php

    · Reply
  2. This Week In WordPress: Dec 17, 2012 – Max Foundry

    [...] WordPress Plugin Self Deactivation [...]

    · Reply
  3. Paul

    I found this tutorial that seems to work well.
    http://www.squarepenguin.com/wordpress/?p=6

    This solution is better for me as I’m using OOP and so I can integrate the function in my class and call it on the activation hook

    · Reply
    • Jake Goldman
      Jake Goldman

      Not a bad approach either, but… (1) it doesn’t account for users who already have the plug-in active (that hook doesn’t fire on plug-in updates anymore), and (2) I don’t like that it should a “fatal error” warning.

      · Reply
      • Paul

        I agree. I ended up doing a mashup of this and the way that woocommerce extensions check for the presence of woocommerce with get_option( ‘active_plugins’ )

        · Reply
  4. Andrew

    Hi Jake,

    I came across your code and it’s pretty much what I need, but I can’t get it to work.

    I’ve coded an extension to Contact Form 7, so I just want to check that the Contact Form 7 plugin is active for mine to activate.

    This is what I’ve done so far: http://pastebin.com/hbMTvyHt

    The first debug line of ‘CF7 not active’ gets emailed to me. But the other functions I’ve created for those action hooks never get called.

    Any tips?

    · Reply
    • Jake Goldman
      Jake Goldman

      It’s almost certainly a timing issue (when this hook runs vs when those hooks run). Also – not really ideal to put your functions instead another function like that.

      · Reply

Leave a Comment