A heads up to all WordPress plugin developers: There is a bug in WordPress’s plugin activation related to variable collisions. Here’s a plugin that will reproduce the error:
/* Plugin Name: Broken Plugin */ $plugin = "oops!";
Looks innocent enough. But try to activate this plugin and you’ll get an admin error notification:
The plugin “oops!” has been deactivated due to an error: Plugin file does not exist.
The reason for this is that when WordPress activates the plugin it includes your plugin file into the scope of the activate_plugin function. It does this in order to do a “Sandboxed” execution of your plugin to catch any errors, or premature output that could mess with the WordPress headers. The problem is that the “Sandbox” scope is full of other variables that are used in the process of registering the plugin. One of those variables is… you guessed it… $plugin.
Here’s a simplified version of what’s happening in activate_plugin:
function activate_plugin ($plugin, /* other stuff */) { include(WP_PLUGIN_DIR . '/' . $plugin); // OOPS! NOW $plugin HAS AN UNINTENDED VALUE if (/* NO ERRORS */) { $installedPlugins = get_option( 'active_plugins', array() ); $installedPlugins[] = $plugin; update_option('active_plugins', $installedPlugins); } }
What made this bug a giant PITA for me was that I happened to assign an object to $plugin. So, not only did my plugin not install, but it riddled my WP install with cryptic errors about incomplete objects.
The Solution…
The simple work around to this is to not use $plugin, or any other variable name that happens to be used in the body of activate_plugin. The better solution is to eliminate variable declarations and code execution from the top scope of your plugin altogether. This can be achieved easily by wrapping any code in a bootstrap function:
function my_plugin_bootstrap () { $plugin = new MyPlugin(); $plugin->init(); } my_plugin_bootstrap();
There is a note in the WordPress documentation about scoping in plugins that is related to this issue. Personally, I think this is a bug — If I get a change to file it, I’ll link to the ticket and followup here.