WordPress template_include - how to hook it properly

Martin Zeitler picture Martin Zeitler · Nov 30, 2011 · Viewed 18.2k times · Source

I'm currently coding a WP plugin and would need to override templates.

My filter hook looks like that - and it executes:

add_filter('template_include', 'mcd_set_template',10);

function mcd_set_template() just returns the required path as string - or the default WP template in case the file not exists.

I'm toying with this for hours already, even could include that alternate template (but it appears at the bottom of the page).

So my question is, how to force WP 3.2.1 to just load another template file instead - and which priority is required??

Update: Also I noticed when using var_dump ... it outputs almost at the end of the file - but should appear before the opening HTML tag...

According to this ticket it should work with template_include hook: http://core.trac.wordpress.org/ticket/11242

Or is the only way to hook these filters instead: http://codex.wordpress.org/Template_Hierarchy#Filter_Hierarchy ?

Answer

eddiemoya picture eddiemoya · Mar 15, 2012

You could use template_redirect as shown above, but that does require exit, and it does trample on everything else WordPress would normally do to find the current template. You may want to let that happen and then apply logic to the current template.

Using some of what is above...

add_action('template_include', 'mcd_set_template');

function mcd_set_template() {
    return locate_template('templatename.php');
}

That is fairly simple, you can also pass an array to locate_template() to define a hierarchy. If you were to use 'template_redirect as shown above, you should still be using locate_template, and this is how.

add_action('template_redirect', 'mcd_set_template');

function mcd_set_template() {

      /**
       * Order of templates in this array reflect their hierarchy.
       * You'll want to have fallbacks like index.php in case yours is not found.
       */
      $templates = array('templatename.php', 'othertemplate.php', 'index.php');

      /**
       * The first param will be prefixed to '_template' to create a filter
       * The second will be passed to locate_template and loaded.
       */
      include( get_query_template('mcd', $templates) );

      exit;
}

Finally, the best way would be to filter specific types instead of the whole hierarchy. For example you could filter 'category_template' or 'page_template'. That would be more specific, it would avoid messing with the whole template hierarchy if you don't want to - and it lets WordPress do more of the heavy lifting

For example:

add_filter('category_template', 'filter_category_template');
function filter_category_template($template){
    /* Get current category */
    $category = get_queried_object();

    /* Create hierarchical list of desired templates */
    $templates = array (
      'category.php',
      'custom-category-template.php', 
      'category-{$category->slug}.php',
      'category-{$category->term_id}.php', 
      'index.php'
    ); 


    return locate_template($templates);
}

You can of course create that array of hierarchical templates any time you use locate_template(). Using this method, its easy to see how easily you could create all sorts of very detailed and specific hierarchies either as part of or separate from the native Template Hierarchy.