Wordpress - Using register_activation_hook in classes

Having reread your question, I think I see the issue, and it stems from a misunderstanding of how register_activation_hook works, combined with some confusion over how you're bootstrapping your code and what it means to bootstrap

Part 1: register_activation_hook

This function takes 2 parameters:

register_activation_hook( string $file, callable $function )

The first parameter, $file is the main plugin file, not the file that contains what you want to run. It's used the same way as plugins_url, so you need the value of __FILE__, specifically its value in the root plugin file with your plugin header.

The second parameter is a callable and works as you expect, but it's really just using add_action internally

When a plugin is activated, the action ‘activate_PLUGINNAME’ hook is called. In the name of this hook, PLUGINNAME is replaced with the name of the plugin, including the optional subdirectory. For example, when the plugin is located in wp-content/plugins/sampleplugin/sample.php, then the name of this hook will become ‘activate_sampleplugin/sample.php’.

Part 2: Bootstrapping and __FILE__

A fundamental problem here is that __FILE__ will have different values in different locations, and you need a specific value.

You also have a problem, that bootstrapping should assemble the object graph, but you don't do that. All your objects are created as soon as they're defined, or created inside eachother, making it difficult or impossible to pass values to them.

As an example, I could write a plugin like this:

plugin.php:

<?php
/**
 * Plugin Name: My Plugin
 * Version: 0.1
 */

// loading step
require_once( 'php/app.php' );

// bootstrapping step
$app = new App( __FILE__ );

// execution step
$app->run();

I defined all my classes in the php subfolder, and loaded them all in the same place. PHP now knows what my classes are, their names etc, but nothing has happened yet.

I then create all my objects, passing them what they need, in this case App needs the value of __FILE__ so I pass it along. Note that this creates the objects in memory, but doesn't do any work. The plugins application is ready to go, to pounce into action, but it's in the preparation phase.

The next step may be to pipe these objects into a set of unit tests, but now I'm going to run them. I've finished my bootstrapping process, and the application is ready to run, so I trigger the run method. I shouldn't need to pass anything to run as everything necessary has been passed to the constructors. During the run method, I add all my filters and hooks. It's during those hooks that all the other parts of the plugin run.

The important part though is that I have a defined structure, and that I pass in what's necessary during the construction/bootstrapping phase, with a defined life cycle


You can set a const who will conation the __FILE__ value and use in wherever you want in you classes.

Example:

main-plugin-file.php

<?php
/**
* Plugin Name: Plugin with Classes
*/

define( 'PLUGIN_WITH_CLASSES__FILE__', __FILE__ );

include( 'my-class.php' );

my-class.php

<?php
class myClass {
  function __construct() {
    // Run this on plugin activation
    register_activation_hook( PLUGIN_WITH_CLASSES__FILE__,  [ $this, 'create_plugin_database_table' ] );
  }

  function create_plugin_database_table(){
    //Create DB Table ...
  }
}

new myClass();