Hook being called twice on activate, once on deactivate

View: New views
9 Messages — Rating Filter:   Alert me  

Hook being called twice on activate, once on deactivate

by mark waterous :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I was hoping somebody on here might be able to explain the following strange
behavior I stumbled across.

 

I've been working on a plugin that during activation needs to create some
tables. The table names are stored in constants for use in various locations
around the plugins codebase, and are defined ala;

 

define( 'MYPLUGIN_TABLE_WHATEVER', $wpdb->prefix . 'table_whatever' );

 

Which works fine everywhere else in the code, returning the desired
'wp_#_table_whatever' string I need. Right up until the constant is used
from inside an activation callback, at which point it drops the
$wpdb->prefix, and I wind up with tables called only 'table_whatever' (no
prefix). So I wrote a quick'n'dirty to try and discern what was occurring;

 

<?php /*

Plugin Name: WPDB Object Test

Description: If you only knew.

Version: 0.1

*/

 

define( 'WPDB_TEST_TABLE', $wpdb->prefix . 'table_name' );

 

$outside_data = WPDB_TEST_TABLE;

 

function wpdb_test_activate( $outside_data ) {

                global $wpdb;

 

                $file = dirname( __FILE__ ) . '/test.log';

 

                $data = 'Outside: ' . $outside_data . "\n";

                $data .= 'Constant: ' .WPDB_TEST_TABLE . "\n";

                $data .= 'Inside: ' . $wpdb->prefix . "table_name\n\n";

 

                $fp = @fopen( $file, 'a' );

                if ( $fp )

                                fwrite( $fp, $data );

                fclose( $fp );

}

 

register_activation_hook( __FILE__, call_user_func( 'wpdb_test_activate',
$outside_data ) );

?>

 

This resulted in behavior I wasn't expecting - it would appear that the hook
runs twice on activation. The first run strips $wpdb->prefix, the second
time it doesn't. It also runs the activation hook again on deactivation.
Should it be doing that? The actual plugin has a deactivation hook of
course, but I wasn't expecting it to run the activation hook in absence of
this.

 

My test.log file looks like this, though you could run it for yourself to be
sure (the first two groups are from activation, the third from
deactivation):

 

<test.log>

Outside: table_name

Constant: table_name

Inside: wp_3_table_name

 

Outside: wp_3_table_name

Constant: wp_3_table_name

Inside: wp_3_table_name

 

Outside: wp_3_table_name

Constant: wp_3_table_name

Inside: wp_3_table_name

</test.log>

 

(sorry about the long post, and this apology that makes it even longer)

 

--

Mark Waterous

 <http://mark.watero.us/> http://mark.watero.us/ ( <mailto:mark@...>
mark@...)

 

_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by scribu :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

A solution might be to summon wpdb, before defining the constant:

global $wpdb;

I assume your problem is caused by the different scope that the plugin is
activated in.

--
http://scribu.net
_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by mark waterous :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

> -----Original Message-----
> Sent: Thursday, October 29, 2009 12:24 PM
> To: wp-hackers@...
> Subject: [wp-hackers] Hook being called twice on activate, once on
> deactivate
>
> I was hoping somebody on here might be able to explain the following
> strange behavior I stumbled across.
>

That's odd how it added extra line breaks. *kicks Outlook*
-Mark

_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by Otto-19 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I can't explain why you're having it run twice or whatever, but the
reason you lose the prefix is simple. Your $wpdb is not in scope at
the initial activation point.

When you first get activated, your plugin is included from inside the
activate_plugin function, meaning that you're not in global scope for
that one run, you're in the function scope.

When you get included from then on, in the normal load-everything
sequence, your plugin gets included from the main path, inside
wp-settings.php.

$wpdb won't be defined in the function scope, unless you global it first.

Which just goes to show: If you want a global variable, then *always*
say so. Never assume scope.


-Otto
_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by Austin Matzko :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Oct 29, 2009 at 2:24 PM, mark waterous <mark@...> wrote:
> register_activation_hook( __FILE__, call_user_func( 'wpdb_test_activate',
> $outside_data ) );

>
> This resulted in behavior I wasn't expecting - it would appear that the hook
> runs twice on activation. The first run strips $wpdb->prefix, the second
> time it doesn't. It also runs the activation hook again on deactivation.
> Should it be doing that? The actual plugin has a deactivation hook of
> course, but I wasn't expecting it to run the activation hook in absence of
> this.

That's not how to use register_activation_hook.  call_user_func()
there is calling the wpdb_test_activate function when it's defined,
which is when the file is read in, rather than when the activation
hook fires.

Should be something like register_activation_hook( __FILE__,
'wpdb_test_activate');

and then figure out another way to pass the $outside_data stuff.
_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by chrisbliss18 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Frankly, your code is a mess.

Your register_activation_hook call is not passing the name of a function
that should be called; rather, it is directly calling the function.
That's what call_user_func does, it runs the function.

That means that when the register_activation_hook portion of the code is
encountered, it immediately executes the wpdb_test_activate function.

The reason why it is running three times when you activate and then
deactivate is because it does the following:

   1. Runs once when the activate link is clicked. WordPress basically
      tries to run it just to ensure that the code is valid and doesn't
      crash before actually activating it. This would also account for
      why $wpdb doesn't exist since it is more or less working in just a
      sandbox environment at this point.
   2. Runs again when the Plugins page reloads after having the plugin
      activated. It runs since it is now an active plugin and as all
      active plugins do, it executes.
   3. Runs again when you deactivate the plugin since a full run of the
      code executes before deactivating the plugin in order to give the
      plugin time to respond to deactivation actions.

I bet if you navigated through the site with the plugin activated, you
would see output each time as each time the code runs, the
call_user_func is executing wpdb_test_activate.

Personally, I think using a define for the table name is sloppy and
error-prone (this situation makes a case for it).

Getting back to the topic, your main issue is the call_user_func. It
should look like the following:

    register_activation_hook( __FILE__, 'wpdb_test_activate' );

Notice that you can't add any variables. All register_activation_hook
does is create an action, and you can't pass variable data to an
add_action. The idea is that variable data gets passed to the registered
function, but in this case, no parameters are passed to the registered
activation function.

Chris Jean
http://gaarai.com/
@chrisjean



mark waterous wrote:

> I was hoping somebody on here might be able to explain the following strange
> behavior I stumbled across.
>
>  
>
> I've been working on a plugin that during activation needs to create some
> tables. The table names are stored in constants for use in various locations
> around the plugins codebase, and are defined ala;
>
>  
>
> define( 'MYPLUGIN_TABLE_WHATEVER', $wpdb->prefix . 'table_whatever' );
>
>  
>
> Which works fine everywhere else in the code, returning the desired
> 'wp_#_table_whatever' string I need. Right up until the constant is used
> from inside an activation callback, at which point it drops the
> $wpdb->prefix, and I wind up with tables called only 'table_whatever' (no
> prefix). So I wrote a quick'n'dirty to try and discern what was occurring;
>
>  
>
> <?php /*
>
> Plugin Name: WPDB Object Test
>
> Description: If you only knew.
>
> Version: 0.1
>
> */
>
>  
>
> define( 'WPDB_TEST_TABLE', $wpdb->prefix . 'table_name' );
>
>  
>
> $outside_data = WPDB_TEST_TABLE;
>
>  
>
> function wpdb_test_activate( $outside_data ) {
>
>                 global $wpdb;
>
>  
>
>                 $file = dirname( __FILE__ ) . '/test.log';
>
>  
>
>                 $data = 'Outside: ' . $outside_data . "\n";
>
>                 $data .= 'Constant: ' .WPDB_TEST_TABLE . "\n";
>
>                 $data .= 'Inside: ' . $wpdb->prefix . "table_name\n\n";
>
>  
>
>                 $fp = @fopen( $file, 'a' );
>
>                 if ( $fp )
>
>                                 fwrite( $fp, $data );
>
>                 fclose( $fp );
>
> }
>
>  
>
> register_activation_hook( __FILE__, call_user_func( 'wpdb_test_activate',
> $outside_data ) );
>
> ?>
>
>  
>
> This resulted in behavior I wasn't expecting - it would appear that the hook
> runs twice on activation. The first run strips $wpdb->prefix, the second
> time it doesn't. It also runs the activation hook again on deactivation.
> Should it be doing that? The actual plugin has a deactivation hook of
> course, but I wasn't expecting it to run the activation hook in absence of
> this.
>
>  
>
> My test.log file looks like this, though you could run it for yourself to be
> sure (the first two groups are from activation, the third from
> deactivation):
>
>  
>
> <test.log>
>
> Outside: table_name
>
> Constant: table_name
>
> Inside: wp_3_table_name
>
>  
>
> Outside: wp_3_table_name
>
> Constant: wp_3_table_name
>
> Inside: wp_3_table_name
>
>  
>
> Outside: wp_3_table_name
>
> Constant: wp_3_table_name
>
> Inside: wp_3_table_name
>
> </test.log>
>
>  
>
> (sorry about the long post, and this apology that makes it even longer)
>
>  
>
> --
>
> Mark Waterous
>
>  <http://mark.watero.us/> http://mark.watero.us/ ( <mailto:mark@...>
> mark@...)
>
>  
>
> _______________________________________________
> wp-hackers mailing list
> wp-hackers@...
> http://lists.automattic.com/mailman/listinfo/wp-hackers
>  
_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by mark waterous :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

That fixes the constant returning the proper string, but is the activation
hook supposed to be run twice like that? And again on deactivation if there
is no deactivation hook?

--
Mark (http://mark.watero.us/)


> -----Original Message-----
> Sent: Thursday, October 29, 2009 12:39 PM
> To: wp-hackers@...
> Subject: Re: [wp-hackers] Hook being called twice on activate, once on
> deactivate
>
> A solution might be to summon wpdb, before defining the constant:
>
> global $wpdb;
>
> I assume your problem is caused by the different scope that the plugin
> is activated in.
>
> --
> http://scribu.net

_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by Austin Matzko :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Oct 29, 2009 at 2:58 PM, mark waterous <mark@...> wrote:
> That fixes the constant returning the proper string, but is the activation
> hook supposed to be run twice like that? And again on deactivation if there
> is no deactivation hook?

The *activation hook* is not being called during those times; the
*call_user_func()* call is.

Each time:

1. Test include of plugin file to check for fatal errors, immediately
prior to activation.
2. Actual include of plugin file because it's activated.
3. Include of plugin file just prior to deactivation.
_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers

Re: Hook being called twice on activate, once on deactivate

by mark waterous :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I appreciate the comments, but the plugin itself doesn't use
call_user_func(), I simply did that in the test as a way to pass an argument
to the function. It was meant to be a quick and dirty test, I wasn't really
priding myself on the coding style in that sample - the root of the problem
was the scope during activation as Otto informed me.

Thank you for also pointing out however that call_user_func is executing
every time the file is accessed, it's not a function I've used very much in
the past, and I will make sure the same mistake isn't made twice.
- Mark

> -----Original Message-----
> Sent: Thursday, October 29, 2009 12:53 PM
> To: wp-hackers@...
> Subject: Re: [wp-hackers] Hook being called twice on activate, once on
> deactivate
>
> Frankly, your code is a mess.

_______________________________________________
wp-hackers mailing list
wp-hackers@...
http://lists.automattic.com/mailman/listinfo/wp-hackers