WooCommerce: Work Out the First Action a Global Variable Can Be Accessed From

WooCommerce uses a number of global variables, if you’ve spent any time looking at code snippets then you’ll often see code like this

global $product;

Which is used to get a reference to the current product that is being displayed, typically on the shop screen or the single product page.

Recently whilst looking through the WooCommerce slack channel, I saw a question which asked

Does anyone know when the global $product is set up? when is the earliest you can access it. 

The question was answered by Brian Henry via an ingenious code snippet, so I thought I’d write a quick blog post about the code to try and cement it into my brain. Here’s the code that Brian posted.

global $has_product_global_been_set;
$has_product_global_been_set = function() {
    global $product;
    if( !empty( $product ) ) {
        $was_set = current_action();
        error_log( "global \$product first set on action {$was_set}" );
        global $has_product_global_been_set;
        remove_action( 'all', $has_product_global_been_set, 999 );
    }
};
add_action( 'all', $has_product_global_been_set, 999 );

I’ll go through what the code is doing line by line

  • Firstly, it sets up a global variable named $has_product_global_been_set
  • It then assigns a function to this variable
  • The first line of the function gets a reference to the global $product variable
  • It then checks to see if the $product value has been set via PHP’s empty function
  • If the $product variable is set then it it writes the name of the current running action to the $was_set variable
  • It then logs then name of the action in the $was_set variable using the error_log function. I recently wrote a blog post about using error_log and the associated constants you need to set it up in WordPress.
  • Now the function has discovered an action in which the  $product variable is set, it stops itself from running by removing itself from the “all” hook
  • It does this by firstly getting a reference to itself  using the global $has_product_global_been_set; code to retrieve the reference that was written into the global scope in the first two lines of the code.
  • It then calls the remove_action function to unhook itself from the “all” action, this will ensure that the function is not run for any future actions that are fired and that the log entry that records which action the $product variable is set in will only be written once. If the code to unhook the function had not been added then the log entry would have been written multiple times for each action that fired after the $product variable was set.
  • Finally the $has_product_global_been_set variable containing the function is hooked up to the “all” action. Notice how a variable is used that contains a reference to the function rather than providing the function name as a string.

If you add the code to your functions.php file then it will log the first action that fires after the $product value is set.

One the shop page it logs

[23-May-2021 10:53:26 UTC] global $product first set on action woocommerce_shop_loop

On the single product page it logs

[23-May-2021 10:56:07 UTC] global $product first set on action wp

Providing you’ve used the default logging settings for WordPress then the logs above will be written to the “debug.log” file inside the “wp-content” directory of your WordPress site.

Conclusion

Hopefully that snippet will help you, I think there are quite a few ways that the code could be used to dig into how the WordPress or WooCommerce codebase works.

I may write some further blog posts about the  “all” hook in the future as it is very useful debugging tool, if you have any ideas about what you’d like me to write about or have questions or queries about this article then please don’t hesitate to let me know in the comments.

Leave a Comment