Global variables and understanding scope in WordPress

If you are a developer who understands scope, variables,  functions, and classes you can just skip the “confusion” and go right to the experimental/hypothetical hack to make any variable set in functions.php globally available to your templates (or the WHY if you want to hear me pontificate).

Confusion with global variables in WordPress

If you set a variable in function.php it is in the global scope (because functions.php is included in wp-settings.php on lines 260-264 in the global scope):

require( ABSPATH . WPINC . '/functions.php' );

HOWEVER, it is not available to all of your templates because unlike functions.php they are loaded by a function putting all variables created there in the scope of that variable.

In functions.php:

$my_new_variable = 'I am a global variable';

Then in index.php…

<?php echo "my_new_variable = $my_new_variable";?>

Returns:

my_new_variable = I am a global variable

But in header.php called using the recommended function get_header() it returns…

my_new_variable =

And is throwing a warning you won’t see unless you turn on debug.

The problem is that we used a function to include our header.php (get_header())template file and in PHP you must explicit define a variable as global in a function call.

But more importantly the file index.php was loaded by many function calls (not tracing the entire flow):

get_index_template() that calls get_query_template() which calls locate_template() (via hooked callback)  which calls locate_template() which calls load_template() which ultimately ends by included the file (using either require or require_once).

SO…all the variables you create in index.php belong to the LOCAL FUNCTION SCOPE load_template() for that one time that function loads index.php. And that is why when you use get_header() and that function calls load_template (if the file was found otherwise it calls locate_template() then load_template() and your header.php file is included it belongs to a DIFFERENT LOCAL FUNCTION SCOPE of that same function. In the same way that…

function increment($a) {
    $a++;
    return $a;
}
$x = increment(1) // returns 2
$y = increment(10) // returns 11
$a = increment(1) // returns 2

Thus anytime you want to use a variable you set in functions.php inside ANY of your templates you need to put

global $my_variable_name

at the top of that template.

As my friend (Scragz) working on the  Kitchen Sink HTML5 Base development/framework/reset plugin with me pointed out, this is a proper thing and expected behavior. However, it’s easy to forget about the scoping issues of all these templates since you only see the function calls to the header, sidebar, footer, and whatever you load for get_template_part() and I’ve spent more than a couple of minutes figuring out why the object I created in functions.php was not available in index.php because I wasn’t thinking.

But more importantly,  from what I can tell, if you are like the majority of WordPress users you are not a programmer, but likely a designer, business owner, or casual blogger who has for whatever reason decided you want to edit your themes/plugins yourself. And if you are that person you are probably not going to understand any of this and will be wanting to scream when you attempt to do something simple like define a variable and expect to be able to use it anywhere in the normal template flow.

WordPress uses too many global variables

The fact that WordPress uses so many global variables is a key reason why WordPress can be a major headache to develop for sometimes. (See this hilarious article about developing for WordPress where this person describes reading WordPress source code as, “like jabbing red-hot fire pokeys into your eyes.”) . That said I love WordPress because I think of myself as a creative first and a programmer second (if only I were a better designer — or programmer for that matter ;) and despite the screwball things you need to do sometimes to work with WordPress, the actual sites created with WordPress run great, are easy to develop (once you have your base theme worked out), is relatively easy for people/clients to learn to use, and there is such a large community surrounding it you can find help at all levels.

As Scragz pointed out when we were chatting about this the other day, “It’s called FUNCTIONS.php, not VARIABLES.php.” So at the core of THEME API is a not so subliminal recommendation to not use global variables and still the core of WP is riddled with them to the point of madness.

Strange workaround hack experiment

And it AIN’T PRETTY…

I came across this snippet of code here and here .

include(locate_template('custom-template-part.php'));

Which then at least loads the variables in the included file in the same scope.

But then this breaks at least one action hook that a plugin might be expecting and I am pretty sure breaks the coolness of get_template_part() for child themes to overload a template file by part.

So as an exercise I made my do_actions to replace the ones that were being skipped in the core to see if  I could load the templates in the same scope without affecting the API at all and it worked great. This still left the get_template_part() child issue but you could probably do that as well. Stupid but if you were doing something stupid that required a shit ton of global variables you didn’t want to keep declaring in all your templates (ahem, WordPress) then you could totally do it without breaking the API.

But I personally wouldn’t recommend doing this because there are better ways to be doing whatever you were doing that need such a hack.

Remember your scope and prosper

I hope this helps some folks out there who don’t understand scope. Chat with you later.

Oh, and I stumbled on this introductory discussion of scope, functions, references, and all that stuff while I was researching this post if you aren’t understanding how to use functions and having scoping troubles.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>