Smarter Wordpress templates with the template_redirect and template_include hooks

Building a Wordpress theme can be more like untangling template spaghetti rather than working from a fresh slate. Sometimes you need to display different views or layouts depending on your users’ or your application’s state but digging around in the hot mess that is Wordpress’ legacy API can be a pain.

Enter the template_redirect and template_include hooks. These useful features of Wordpress 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.

The right time to make a decision

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.

Redirect vs. Include

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 e.g. send a user to a login page or if you want to otherwise block access to a specific section of the site.

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 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;
}

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. For 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');

/**
* Redirect away from the single view for my_custom_post_type only
* if the user is not 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;
}

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 wp_loaded hook is a great place to do that.

add_action('wp_loaded', 'do_some_stuff');

function do_some_stuff()
{
    // And here we go...
}