WordPress template_include - how to hook it properly
Asked Answered
A

2

5

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 ?

Angers answered 30/11, 2011 at 3:24 Comment(0)
H
4

Have you tried using an add_action instead? For example, you might want to try something like the following in your plugin:

add_action('template_redirect', 'mcd_set_template');
//Redirect to a preferred template.
function mcd_set_template() {
    $template_path = TEMPLATEPATH . '/' . "templatename.php";
    if(file_exists($template_path)){
        include($template_path);
        exit;
    }
}

Here is a helpful reference: http://www.mihaivalentin.com/wordpress-tutorial-load-the-template-you-want-with-template_redirect/

Hertzfeld answered 30/11, 2011 at 4:25 Comment(7)
Sorry, calling exit() or die() is definitely not an option - because it kills the script one query sooner than it should... Need to filter template_loader.php @ line 42Angers
Please note the word properly in title - what the code you've pasted does is rather lame. Why? Because hook template_redirect happens before the template-loader decides which template to load...Angers
I've seen in BuddyPress bug-tracker that your suggestion was used there before - but with a priority of 999 - instead of the default 10.Angers
exit is used to exit the add_action for mcd_set_template once the preferred template is included. Otherwise, the preferred template and the default template is loaded, which is one of the reasons why I think it is proper to use template_redirect. You are right in that template_redirect happens before template loader, which is why I think it is proper. Here is a site that I found helpful: linkHertzfeld
Meanwhile I found out what the problem was... it was also related to the timeline... Because query_vars created with add_query_var(), set_query_var(), get_query_var() are not yet available at this stage of the request (an undocumented "feature"?). Now since I restructured everything it works as intended - just reading that values directly from a function. If I will commit the plugin with hook template_redirect I'll accept it as the correct answer - but if I can make it happen with hook template_include - then not. Will post a link to the result once it's up.Angers
Well, I could hook it template_include ... but will accept your the answer, since it's not exactly wrong. In fact, you made me try it once more - when I already had given up :) But I still believe (according to trac) they added that new hook just to get rid of the workaround which you suggested. Plugin code always should mess around with hooks as less as just possible...Angers
and exit isn't as bad as die() in this case... which I read in another version of that workaround method...Angers
C
20

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.

Cavil answered 15/3, 2012 at 22:57 Comment(3)
add_filter('single_template', 'filter_callback') works very well for custom post types. By the way, as of WP 3.4, WP automatically checks for templates that look like 'customPostType-single-slug.php' so no extra code needed to switch templates for a custom post typeChoctaw
How would I use this code to include a page template for a specific page, through a plugin?Peat
@GregL - To target a specific page you don't need this custom stuff. You get that right out of the box with WordPresses Template Hierarchy or by making your template selectable as, what is confusingly similarly named, "Page Templates"Cavil
H
4

Have you tried using an add_action instead? For example, you might want to try something like the following in your plugin:

add_action('template_redirect', 'mcd_set_template');
//Redirect to a preferred template.
function mcd_set_template() {
    $template_path = TEMPLATEPATH . '/' . "templatename.php";
    if(file_exists($template_path)){
        include($template_path);
        exit;
    }
}

Here is a helpful reference: http://www.mihaivalentin.com/wordpress-tutorial-load-the-template-you-want-with-template_redirect/

Hertzfeld answered 30/11, 2011 at 4:25 Comment(7)
Sorry, calling exit() or die() is definitely not an option - because it kills the script one query sooner than it should... Need to filter template_loader.php @ line 42Angers
Please note the word properly in title - what the code you've pasted does is rather lame. Why? Because hook template_redirect happens before the template-loader decides which template to load...Angers
I've seen in BuddyPress bug-tracker that your suggestion was used there before - but with a priority of 999 - instead of the default 10.Angers
exit is used to exit the add_action for mcd_set_template once the preferred template is included. Otherwise, the preferred template and the default template is loaded, which is one of the reasons why I think it is proper to use template_redirect. You are right in that template_redirect happens before template loader, which is why I think it is proper. Here is a site that I found helpful: linkHertzfeld
Meanwhile I found out what the problem was... it was also related to the timeline... Because query_vars created with add_query_var(), set_query_var(), get_query_var() are not yet available at this stage of the request (an undocumented "feature"?). Now since I restructured everything it works as intended - just reading that values directly from a function. If I will commit the plugin with hook template_redirect I'll accept it as the correct answer - but if I can make it happen with hook template_include - then not. Will post a link to the result once it's up.Angers
Well, I could hook it template_include ... but will accept your the answer, since it's not exactly wrong. In fact, you made me try it once more - when I already had given up :) But I still believe (according to trac) they added that new hook just to get rid of the workaround which you suggested. Plugin code always should mess around with hooks as less as just possible...Angers
and exit isn't as bad as die() in this case... which I read in another version of that workaround method...Angers

© 2022 - 2024 — McMap. All rights reserved.