Support » Plugins » register_activation_hook and Global Variables

  • Resolved shanncan

    (@shanncan)


    Hi,

    I am updating my plugin so that it is compatible with wordpress 2.6.

    Currently I cannot use any global variables (other than the wordpress core ones) within the register_activation_hook function hook.

    I have documented the whole thing here :

    http://blog.mcnicholl.com/2008/09/03/wordpress-26-register_activation_hook-cannot-see-global-variables/

    Its not link/comment bait… honest.

    Has anyone else noticed this behaviour?

    At the link above I created a sample plugin that you can use to replicate the issue.

    Is this meant to happen? or am I missing something? I was able to use global variables in this function in WordPress 2.3.2.

    Any help would be great.

Viewing 10 replies - 1 through 10 (of 10 total)
  • Moderator Samuel Wood (Otto)

    (@otto42)

    WordPress.org Admin

    Stop bumping. I’ve deleted your useless bump posts. See the rules, part B6.

    And your plugin is not working because you’re doing it wrong. Look at your code:

    require ‘mcn_constants.php’;
    $mcn_test_blabla    =   “Well ??????”;
    register_activation_hook(__FILE__,’mcn_test_install’);
    register_deactivation_hook(__FILE__, ‘mcn_test_uninstall’ ) ;
    
    add_action(’parse_query’, ‘mcn_test_check’);
    
    function mcn_test_install() {
        global $this_is_broke, $mcn_test_blabla;
    
        add_option(”mcn_test_value”, “The value is: $this_is_broke And :: $mcn_test_blabla “);
    }
    
    function mcn_test_uninstall() {
        delete_option(”mcn_test_value”);
    }
    
    function mcn_test_check() {
        global $this_is_broke;
    
        echo get_option(”mcn_test_value”);
        echo “Proper value : $this_is_broke”;
    }

    First problem:
    $mcn_test_blabla is not a global when you set it to “well”. You’re being included inside the activate_plugin function, and so are not in a global context at that point. So you’re setting a local variable and then drawing from a global. If you want to reference the global, then explicitly say that it’s a global, even in the main plugin body.

    Second problem:
    The activation hook happens immediately after your plugin is included after you activate it. The “parse_query” action has not run yet, so your mcn_test_check() function has not run and you’ve not set the global $this_is_broke variable to anything at all. So of course it won’t display anything in the activation function.

    Thread Starter shanncan

    (@shanncan)

    ok – so… First off – Apologies for “bumping”. In every other forum I’ve used – if you fall off the first page you are in the black hole of never being seen again.

    So – I’ll take the rap on the knuckles.

    As for the code:

    You’d be best to download the code that I posted on my site. It contains all files.

    I am not sure what you mean by : “$mcn_test_blabla is not a global when you set it to “well””.

    As you can see : the first line has a require “mcn_constants.php” which imports my list of constants. I prefer this level of abstraction in my code. This is where the variable $this_is_broke is defined.

    In PHP, it is my understand that if I want to reference a variable that is defined outside of the scope of the current function – then I do so via the “global” call. This is what I do in my code.

    Both $mcn_test_blabla and $this_is_broke are defined outside of the scope of the activation call to function mcn_test_install() and hence – if I wish to use their values within the mcn_test_install() function – I must explicitly call them into the functions scope via the “global” keyword.

    Lets put it like this:

    If I run the exact same plugin code in WordPress version 2.3.2 – it works. The problem is variable scope.

    I don’t seem to have the same scope issue with the “add_action” function so can only assume that something specific has been programmed for the “register_activation_hook” function.

    Do you know if WordPress 2.6 simply parses the plugin file for the activation function defined in the “register_activation_hook” hook? As it seems to be leaving out any (GLOBAL) variables I have defined outside of this function.

    Please say if I am not being clear…

    Moderator Samuel Wood (Otto)

    (@otto42)

    WordPress.org Admin

    In every other forum I’ve used – if you fall off the first page you are in the black hole of never being seen again.

    We’re more clever than that around here. Notice the “No Replies” link at the top (or bottom) of the forum? We usually use that to find unanswered posts. So when you bump your own posts, you actually hurt yourself, as we will no longer see it.

    Both $mcn_test_blabla and $this_is_broke are defined outside of the scope of the activation call to function mcn_test_install() and hence – if I wish to use their values within the mcn_test_install() function – I must explicitly call them into the functions scope via the “global” keyword.

    They’re outside the scope of your functions, yes, but that does not automatically make them globally scoped. In point of fact, at activation time, they are in the scope of the “activate_plugin” function, which is what makes the “include” call to your php file. Which makes them not global. After that first time, they will get included by wp-settings.php, and yes, in that case they will be global. But not that first time.

    You need to declare them global before you use them *anywhere*, even in the main body of your plugin. Why? Because your plugin is being included in one of several places, and so you cannot make the assumption that your main body is always going to be globally scope. Yes, it usually is, but you cannot assume it will be all the time.

    Quick demo in case you’re still uncertain on what I mean:

    File main.php

    function activate_plugin($pluginfile) {
    include $pluginfile; // we're including the file contents inside this function!
    }
    activate_plugin('example.php');
    do_something();

    In example.php:

    /* my plugin */
    $var = 'test'; // this $var is NOT globally scoped. Really.
    function do_something() {
    global $var;
    echo $var;
    }

    What happens when you run main.php? If you think that it outputs “test”, then you are mistaken.

    If I run the exact same plugin code in WordPress version 2.3.2 – it works.

    Yes, and many things have changed since then. That’s the way it rolls.

    Thread Starter shanncan

    (@shanncan)

    So:

    function activate_plugin($pluginfile) {
      //the following code is the equation of "include $pluginfile"
      $test   = "Otto42";
    
      function showTest() {
        global $test;
        echo $test;
      }
    }

    I’m expecting the output of showTest() to be “Otto42” – but it isn’t as a result of:

    • a) How I have specified my variable scope?
    • b) How WordPress handles plugin activations?

    Obviously you are of the “a” corner. I am in the “b” camp.

    Variable scope should be handled the exact same way with every plugin function – no matter how it is called. That way there is a standard that people can work with.

    Ultimately it should follow the notation of the script being imported as this prevents the need to know the complete inner workings of the of the application (wordpress). Although I acknowledge no authority on such design decisions.

    And also prevents this kind of dog – chasing tail scenario.

    This page http://codex.wordpress.org/Function_Reference/register_activation_hook mentions nothing about this.

    Moderator Samuel Wood (Otto)

    (@otto42)

    WordPress.org Admin

    It’s actually both a and b. Plugin activation is handled inside another function (special case). Normal (as in non-just-activated) loading of the plugin is handled by code inside the global scope. Although it might not be in the future.

    The short answer is that there’s never any way to tell where and how your plugin is being included. It’s perfectly acceptable to declare a global var when you’re already globally scoped, so when you want to use a global variable, *always* be explicit about it. Even in the main code of your plugin. Never assume anything.

    The reason you didn’t have this problem in 2.3 is that 2.3 didn’t handle plugin activation in the same way. The new way is better in some ways (code is poetry and all that), but yes, you can’t make this particular assumption any more.

    Thread Starter shanncan

    (@shanncan)

    Thanks for your help with this Otto!

    Hello, I have this issue. Here’s my code:
    register_activation_hook( dirname(__FILE__).’/visitors.php’, ‘visitors_install’ );
    add_action(‘admin_menu’, ‘ip_tracker_map_add_options’);

    function visitors_install()
    {
    global $wpdb;
    $table_name = “wp_accessips”;

    if($wpdb->get_var(“SHOW TABLES LIKE ‘$table_name'”) != $table_name)
    {
    $sql = “CREATE TABLE “.$table_name.” (
    id int(11) NOT NULL auto_increment,
    ip varchar(15) NOT NULL,
    latlon varchar(100) NOT NULL,
    hits int(11) NOT NULL,
    PRIMARY KEY (id) )”;

    dbDelta($sql);
    add_option( “visitor_map_db_version”, “0.3.0” );
    }
    }

    I keep getting an error about re-declaring the visitors_install function. This very code is being used on another plugin I use and it works like a charm, can you tell the problem here?

    Thank you

    Fixed it, thank you.

    peeta

    (@peeta)

    aicholzer how did U fix it? I’m having the same problem..

    I’m encountering an issue with the plugin activation. About 1 in 10 times I’ll get cannot redeclare class php errors. I’m thinking the way to solve this would be to create a new php script in a seperate file that only includes my plugin if it isnt already declared and then pass that through for the file argument rather than the actual plugin php file. Thoughts?

Viewing 10 replies - 1 through 10 (of 10 total)
  • The topic ‘register_activation_hook and Global Variables’ is closed to new replies.