As I’ve been tinkering with my Arras theme over the years, one of the things that I keep coming up against is the odd way that WordPress handles templating. It makes accessing objects in theme templates a less-than-intuitive process.

Essentially, there are two ways that WordPress templates get included into a webpage:

  • The Main template (like index.php, page.php, single.php and all their ilk) are included in the global scope via the template-loader.php file.
  • Sub-templates (like header.php, sidebar.php, footer.php along with any other templates that get called from the main template via get_template_part()) are included in the scope of a call to the locate_template() function.

What that means for themes is that there isn’t a consistent way to access theme variables in templates.

For the main templates, you can, in your theme setup, declare a global variable (yuk), and use it in your global templates:

functions.php

some_setting_things_up_function() {
  global $theme_variable;
  $theme_variable = 'xyz';
  ...
}

single.php

echo $theme_variable;

But to use the same global variable inside a sub-template, I need to declare global in each of the sub-templates.

header.php

global $theme_variable;
...
echo $theme_variable;

So, what’s the big deal? It’s only one little thing in the sub-templates. But if you plan on distributing your theme, it’s not obvious to someone looking at the code (who is probably not so familiar with WP templates) why it’s in some template files but not others. Even seasoned WP developers are going to have to think it through to get to “Oh, yeah, that’s why.”

Another hack for getting your variable into the sub-templates is to insert it into WP’s $wp_query global variable. Here’s how:

functions.php

add_action(  'wp', 'set_my_theme_variable' );
function set_my_theme_variable() {
  $theme_variable = 'xyz';
  set_query_var(  'theme_variable', $theme_variable );
}

For it to work, you have to hook your variable injection into $wp_query after the query has been set up. (That’s why, above, I’ve hooked it to the wp hook.) It works because locate_template() extracts all the query variables within the $wp_query global object into it’s own scope before including the template. So now you can call your variable in sub-templates without declaring (yet another) global variable:

header.php

echo $theme_variable;

Unfortunately, though, the template-loader.php file doesn’t extract the $wp_query variables before calling your main template, so you can’t access your theme variable in any of your main templates.

I suppose you might implement both the global and the $wp_query insertion together.

Both of the preceding methods are ultimately hacks. WordPress calls the theme’s functions.php file functions, after all, because it comes from a time when PHP was a purely procedural templating language. As such, WordPress is intended for you to handle your theme’s business using functions, not variables and objects. Functions in the theme’s functions.php are globally accessible, and the events API intends that we call functions when we want something to happen in a template.

So the third way of going about getting a variable into a theme template uses the WordPress events API and uses a function’s return parameter to inject your variable:

functions.php

add_filter ( 'get_my_variable', 'get_my_theme_variable' );
function get_my_theme_variable() {
  $theme_variable = 'xyz';
  return $theme_variable;
}

single.php*or*header.php

$theme_variable = apply_filters( 'get_my_variable' );
echo $theme_variable;

In most use cases, by now, you may as well just do what you want to with the variable inside the function anyway, since your function is in global scope, and dispense with trying to inject it into a template:

functions.php

function echo_my_theme_variable() {
  $theme_variable = 'xyz';
  echo $theme_variable;
}

single.php or header.php

echo_my_theme_variable();

This is how WordPress was intended to work in a world without any concept of object oriented solutions. “Variables? We don’t need no stinkin’ variables.”

It’s the introduction of an object oriented approach that makes the passing of objects rather than functions critical – because you need to get at the object from within your template in order to access it’s methods/behavior/functionality. And the only way to get at the object is to pass it in as a variable or instantiate it within the template. Instantiating within the template, most of the time, is probably not what you want, because (objects being stateful) you already have an object ready to go, and you don’t want to create a new one; you want the one that’s in the state to do what it needs to.

So with an object, you’re looking to do something in a template like:

$theme_object->do_stuff_with_what_i_already_set_up_in_this_object();

The question is, how are you going to get $theme_object into the template? And probably the easiest (least hack-y) way is to grab it by some pre-arranged hook and filter as in the example above. At the point you have hooked your object to a filter in functions.php, you can apply it in the template and then access it’s functionality:

functions.php

add_filter ( 'get_my_object', 'get_my_theme_object' );
function get_my_theme_object() {
  $theme_object = new ThemeObject();
  return $theme_object;
}

single.php*or*header.php

$theme_object = apply_filters( 'get_my_object' );
...
$theme_object->do_stuff_I_already_set_up();

Regardless of the how you do it, using objects in theme templates is going to be outside of the usual WordPress way of doing things. It’s going to feel like a hack. Heck, it is a hack.

But sometimes, you’ve just gotta do what you gotta do.