register_activation_hook isn’t adding table to DB

I’ve started my first plugin and I need to store values returned from an API call to a database. But before I do that, I need to be able to make a database table. I have the following code in a file that is required of the main plugin file:

register_activation_hook(__FILE__, 'PLUGIN_activation');
function PLUGIN_activation() {
    //setup DB Tables
    global $wpdb;

    $table_name = $wpdb->prefix . "table_name";//insert actual tablename here

    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
      id mediumint(9) NOT NULL AUTO_INCREMENT,
      event_id text NOT NULL,
      event_date mediumint(8) DEFAULT '00000000' NOT NULL,
      event_unique mediumint(13) NOT NULL,
      name tinytext NOT NULL,
      PRIMARY KEY  (id)
    ) $charset_collate;";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
}

I have reinstalled the plugin and activated it, but nothing happened.

For some reason, the table is not being created. What could be stopping this?

1 Answer
1

Note that the $file in register_activation_hook( $file, $callback ), should be equal to path to the main plugin file, but when you have it in a sub file as __FILE__ then it’s not the same! That means your callback is never called.

I would also recommend prefixing the function’s name to avoid possible name collision or use namespaces.

More in the Codex here.

Update

It’s informative to peek into the function’s definition:

/**
 * Set the activation hook for a plugin.
 *
 * 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'.
 *
 * When the plugin consists of only one file and is (as by default) located at
 * wp-content/plugins/sample.php the name of this hook will be
 * 'activate_sample.php'.
 *
 * @since 2.0.0
 *
 * @param string   $file     The filename of the plugin including the path.
 * @param callable $function The function hooked to the 'activate_PLUGIN' action.
 */
function register_activation_hook($file, $function) {
    $file = plugin_basename($file);
    add_action('activate_' . $file, $function);
}

and this is the corresponding do_action call for the plugin acitvation in the activate_plugin() function:

/**
 * Fires as a specific plugin is being activated.
 *
 * This hook is the "activation" hook used internally by register_activation_hook().
 * The dynamic portion of the hook name, `$plugin`, refers to the plugin basename.
 *
 * If a plugin is silently activated (such as during an update), this hook does not fire.
 *
 * @since 2.0.0
 *
 * @param bool $network_wide Whether to enable the plugin for all sites in the network
 *                           or just the current site. Multisite only. Default is false.
 */
  do_action( "activate_{$plugin}", $network_wide );

Example

Let’s walk through this with a real plugin.

So take for example the WooCommerce plugin, that has the main plugin file:

/full/path/to/wp-content/woocommerce/woocommerce.php 

where it defines:

register_activation_hook( __FILE__, array( 'WC_Install', 'install' ) );

where $file is __FILE__ or

/full/path/to/wp-content/woocommerce/woocommerce.php 

Then the line:

$file = plugin_basename( $file );

becomes:

$file = plugin_basename( '/full/path/to/wp-content/woocommerce/woocommerce.php' );

that gives:

$file="woocommerce/woocommerce.php";

Then the dynamic hook:

add_action('activate_' . $file, $function);

generates:

add_action('activate_woocommerce/woocommerce.php', $function);

So if WooCommerce would place the registration activation hook in a special file under e.g.

/full/path/to/wp-content/woocommerce/include/activation.php

then this would be the value of __FILE__ and we would be registering the following action:

add_action('activate_woocommerce/include/activation.php', $function);

but there’s no do_action() call for that one.

Instead they might store the main plugin file path, to use it elsewhere, like they already do in the main plugin file here:

$this->define( 'WC_PLUGIN_FILE', __FILE__ );

Hope it helps!

Leave a Comment