Deactivating a plugin at activation time
June 19, 2014
While developing the Route Pages plugin I've ran into the need to make sure that WP Router plugin is installed and activated in the WordPress installation and got a little confused while trying to sort out a way to
- avoid plugin activation
- give the user information about what's happening
A first, non working, version
My first attempt was code like this
/**
* Activate the plugin
*/
public static function activate()
{
// check for WP Router plugin to be activated
$isWPRouterInactive = is_plugin_inactive('WP-Router/wp-router.php');
if ($isWPRouterInactive) {
deactivate_plugins(plugin_basename(__FILE__));
add_action('admin_notices', function()
{
$wpRouterUrl = "http://wordpress.org/plugins/wp-router/";
echo sprintf("Route Pages requires <a href=\"%s\">WP Router plugin</a> to be installed and activated.<br>Install and/or activate it and try again.", $wpRouterUrl));
}
// if all ok then...
$this->goOnWithActivation();
}
Sadly that's not working at all. I've searched the web for a while and could not find much information and have set for an informative wp_die
generated screen like the one below [caption id="attachment_1103" align="aligncenter" width="1024"][](http://theaveragedev.local/wordpress/wp-content/uploads/2014/06/2014-06-18-at-09.11.png) Die with style[/caption]
The entry point
The below function, defined in my plugin main file, will take care of checking for the required WP Router plugin and prompt the user with possible actions
/**
* Activate the plugin
*/
public static function activate()
{
// check for WP Router plugin to be installed and activated
$isWPRouterActive = is_plugin_active('WP-Router/wp-router.php');
if (!$isWPRouterActive) {
$installOrActivateLinkFormat = '<a style="float:right;" href="%s">%s WP Router now →</a>';
$installOrActivateLink = '';
$wpRouterPath = self::checkWPRouterInstalled();
if ($wpRouterPath) {
// generate an activation URL
$installOrActivateLink = self::generateWPRouterActivationLink($installOrActivateLinkFormat, $wpRouterPath);
} else {
// generate an installation URL
$installOrActivateLink = self::generateWPRouterInstallationLink($installOrActivateLinkFormat);
}
// do not activate the plugin
deactivate_plugins(plugin_basename(__FILE__));
// display the die message
$dieMessage = self::generateWpDieMessage($installOrActivateLink);
wp_die($dieMessage);
}
// requirements are ok, go on
...
}
thanks to PHPStorm magical refactoring abilities I've moved the code into separate functions and will walk them here for my future memory.
Checking if a plugin is installed
WordPress does not pack a is_plugin_installed
function so I've created one to check if WP Router is installed.
protected static function checkWPRouterInstalled()
{
// get all the plugins
$installedPlugins = get_plugins();
foreach ($installedPlugins as $installedPlugin => $data) {
// check for the WP Router title
if ($data['Title'] == 'WP Router') {
// return the plugin folder/file
return $installedPlugin;
}
}
return false;
}
Generating an activation link for WP Router
That's probably the trickiest method among all as it requires spoofing the plugin request to pass the nonce check
/**
* @param $installOrActivateLinkFormat
* @return string
*/
public static function generateWPRouterActivationLink($installOrActivateLinkFormat, $plugin)
{
$activateUrl = sprintf(admin_url('plugins.php?action=activate&plugin=%s&plugin_status=all&paged=1&s'), str_replace('/', '%2F', $plugin));
// change the plugin request to WP Router to pass the nonce check
$_REQUEST['plugin'] = $plugin;
$activateUrl = wp_nonce_url($activateUrl, 'activate-plugin_' . $plugin);
$installOrActivateLink = sprintf($installOrActivateLinkFormat, $activateUrl, 'Activate');
return $installOrActivateLink;
}
Generating an installation link
Generating an installation link is easier and does not require any convolute hack
/**
* @param $installOrActivateLinkFormat
* @return string
*/
public static function generateWPRouterInstallationLink($installOrActivateLinkFormat)
{
$slug = 'wp-router';
$installUrl = admin_url('update.php?action=install-plugin&plugin=' . $slug);
$installUrl = wp_nonce_url($installUrl, 'install-plugin_' . $slug);
$installOrActivateLink = sprintf($installOrActivateLinkFormat, $installUrl, 'Install');
return $installOrActivateLink;
}
Generating an informative die message
Finally I've taken some care to generate a wp_die_message
that did not left a plugin administrator out of options forcing him/her to make assumptions and hit the dreaded Back button.
/**
* @param $installOrActivateLink
* @return string
*/
public static function generateWpDieMessage($installOrActivateLink)
{
$wpRouterUrl = "http://wordpress.org/plugins/wp-router/";
$notice = sprintf('<span style="display:block;text-align:center;">Route Pages requires <a href="%s" target="_blank">WP Router plugin</a> to be installed and activated.</span>', $wpRouterUrl);
$pluginsUrl = admin_url('plugins.php');
$backToPluginsLink = sprintf('<a href="%s">← Back to plugins.</a>', $pluginsUrl);
$dieMessage = sprintf("%s<br><br>%s%s", $notice, $backToPluginsLink, $installOrActivateLink);
return $dieMessage;
}
And the final result is the one from the image above.