template_redirect is a popular WordPress hook, for good reason. When it runs, WordPress has made its main query. All objects have been instantiated, but no output has been sent to the browser. It is your last stop to hook in and redirect the user somewhere else, and the best place to do so if you need full knowledge of the queried objects. But what it is not good for is loading an alternative template.

I see code like this a lot:

add_action( 'template_redirect', 'my_callback' ); function my_callback() { if ( some_condition() ) { include( SOME_PATH . '/some-custom-file.php' ); exit(); } }

The problem with this code is that anything hooked in to template_redirect after this code isn’t going to run! This can break sites and lead to very odd bugs. If you want to load an alternative template, there’s a filter hook for that: template_include .

add_filter( 'template_include', 'my_callback' ); function my_callback( $original_template ) { if ( some_condition() ) { return SOME_PATH . '/some-custom-file.php'; } else { return $original_template; } }

Same effect, but doesn’t interfere with other plugin or theme code! This distinction should be easy to remember:

template_ redirect is for redirects .

is for . template_include is for includes.