Painted Man Blending Into Scenery

3-minute read

Activation and deactivation hooks failing? Obscure behavior revealed!

I came across an unexpected behavior when writing the activation and deactivation methods for a plugin. This one had me stumped for awhile! Don’t get caught by this one!

In writing a new object-oriented boilerplate plugin, I started with the activate, deactivate, and uninstall processes. At first, everything went as expected, then I ran into some trouble that had me stifled for hours.

Me and My Big Ideas

As the plugin code grew, I had the notion to change the structure of the plugin slightly. This meant moving a few files and methods. No biggie. The file in the root of my plugin was changed to be a simple bootstrap and my “actual” plugin code was tucked into a directory. It wasn’t until nearly a week later that I realized…

Activation and Deactivation Hooks Were Broken

The activate, deactivate, and uninstall methods were no longer working! Since my code was namespaced, I tried every variation I could think of, starting with the activation hook. Note that all of the following variations will typically work, but they didn’t work anymore in my plugin. I’d only later find out that this was a red herring.

`register_activation_hook(__FILE__, [$this, ‘activate’]);`

`register_activation_hook(__FILE__, [__CLASS__, ‘activate’]);`

`register_activation_hook(__FILE__, [‘MyPlugin’, ‘activate’]);`

`register_activation_hook(__FILE__, [‘\\MYNAMESPACE\\MyPlugin’, ‘activate’]);`

What the…

Still figuring there was something wrong with my namespacing, I spun up a single-file plugin with a namespace, a class, and activate/deactivate methods. And, the thing worked just like you would expect. UGH! This wasn’t immediately helpful, but, it did lead me to the solution.

The Solution

Hours later, I finally discovered the problem. As it turns out, the methods that you register with register_activation_hook, register_deactivation_hook, and `register_uninstall_hook` must be contained in the same file in which they are registered – if you move these methods into another file or class, they simply (and silently) fail.

Note: if you prefer to not have your uninstall functions or methods in your plugin’s main files, you can place them into a file named uninstall.php in the root of the plugin’s own directory. This isn’t necessary, but, it’s possible.

Wrapping Up

I ended up reading a whole lot of tutorials, documentation, and Stack Overflow posts trying to solve this issue. Unfortunately, it wasn’t covered anywhere I could find it. The issue was simply that my activation, deactivation, and uninstallation methods did not reside in the file in which there were hooked. Once they were moved there, everything was golden. So, if you’re having trouble with these particular hooks and you’re positive you’re writing the code correctly, perhaps the issue is simply that you have your code in the wrong place. Here’s a code snip to look at.

 * Plugin Name: My Plugin

namespace MYNAMESPACE;

class MyPlugin {

    public function __construct() {
        register_activation_hook(__FILE__, [$this, 'activate']);
        register_deactivation_hook(__FILE__, [$this, 'deactivate']);
        register_uninstall_hook(__FILE__, [__CLASS__, 'uninstall']); // Static; use __CLASS__

    public function activate() {
        update_option('my_plugin', 'activated');

    public function deactivate() {
        update_option('my_plugin', 'deactivated');

    // Static method.
    public static function uninstall() {

new MyPlugin;

What do you think?

Have you ever run into this issue? If so, did you also go off on a wild-goose-chase trying to figure it out? I thought it had to do with the namespacing – what did you think it was? I’d love to hear your thoughts – let me know in the comments!