Mastering WordPress Template Control with template_redirect and template_include
A Developer's Guide to Smarter WordPress Theme Logic
Building a WordPress theme can be a bit like untangling spaghetti. But by using template_redirect
and template_include
you can gain a lot of control over where your users go and what they see.
Controlling Your WordPress Templates
Sometimes you need to display different layouts based on which user is logged in or the state of your application. This can lead to complex nested routes and tangled template hierarchies.
Introducing the template_redirect
and template_include
hooks.
These useful WordPress filters can help you to take more control over the layouts presented to your visitors, and insert custom templates or take other actions based on the current URL and state of the user’s current session.
- template_include – used to override WordPress’ default template behaviours. This is executed just before WordPress includes the default template file for a given route. Use this to get more control over what users see.
- template_redirect – used to override what WordPress does before it starts to load the default template. You use this hook to determine where users go.
They’re similar, but the difference between them is important. Only use template_redirect
to guide a user to another part of your site. Don’t use it to load a different template, that’s what template_include
is for!
template_redirect And template_include – The Perfect Pair
When the template_redirect
and template_include
hooks run, WordPress has already done the heavy lifting, has populated the global objects, and has full knowledge of the state of the current page. In other words, it’s a great time to make a decision as to where you want the user to go next or what they should see on the page.
You can see why this gives you a lot more control over your template appearance and functionality. Use that power wisely!
Template Redirection
There’s a small but important distinction between these two hooks. template_redirect
is designed only for redirecting a user to another page or location (hence the name!). Use this if you want to:
- Send an unauthorised user to a specific page
- Modify the HTTP headers before the page loads (this is a great place to do it as you can’t modify headers once the content loads)
- Load non-WordPress content, such as loading in data from a 3rd party database
- Prevent access –
template_redirect
is the perfect place to check if a user should be blocked from accessing a resource
The reason why this is not the place to be placing other code to adjust the template layout is that WordPress may be relying on additional functionality hooked into template_redirect
. If you try to output a template at this point then exit to terminate the script, that additional functionality may not run.
One example use for template_redirect
could be to disable the single page view for a given post type but only for guest users.
add_action('template_redirect', 'single_view_disable');
/**
* Redirect away from the single view for my_custom_post_type only
* if the user is not logged in
*/
function single_view_disable() {
global $post;
if($post->post_type == 'my_custom_post_type' && is_single() && !is_user_logged_in()):
// Redirect back home
wp_redirect(home_url(), 301);
exit;
endif;
}
Template Inclusion
The other hook, template_include
would be used if you wanted to display a different template than the one which will be served up normally as part of WordPress’ process flow rather than redirecting the user to an entirely new page.
You might use template_include
to:
- Filter template files – dynamically select a template based on custom logic
- Create a child theme – override some specific parent templates conditionally
- Develop a plugin –
template_include
is an excellent way to give your plugin control over the front-end appearance - Debug during development –
template_include
is a perfect place to force specific templates for testing purposes
To give another specific example, modifying the example above, say we want to have two different layouts for logged in and non-logged in users for a given post type.
add_action('template_include', 'single_view_adjustment');
/**
* Load a different template for my_custom_post_type single view
* if the user is logged in
*/
function single_view_adjustment($template) {
global $post;
if($post->post_type == 'my_custom_post_type' && is_single() && is_user_logged_in()):
// Search for the new template file either within the parent
// or child themes
$new_template = locate_template(array('my_custom_post_type-single-for-auth-users.php'));
if ( '' != $new_template ) {
return $new_template;
} // if the template doesn't exist, WordPress will load
// the default template instead
endif;
return $template;
}
Easily Locating A Template In The Filesystem
Note here, our use of the locate_template()
function. This handy little helper function returns the path to a given template file, allowing for optional overrides within the parent/child themes.
You will also need to create a file my_custom_post_type-single-for-auth-users.php
within your theme folder. To get started, you can copy the contents of single.php
into this file.
Finally…
These two hooks are great places to run functionality which is dependent on the overall state of WordPress’ objects for any given URL, but to keep things tidy, it’s best to pop any non-template-related code into another hook. The init
hook is a great place to do that.
add_action('init', 'do_some_stuff');
function do_some_stuff()
{
// And here we go...
}