My favorite part of the WordPress template hierarchy is the ability to quickly create template files for pages by slug, without having to edit the page in WordPress to select a template.

We can currently do this:

page-{slug}.php

But I would like to be able to do this:

single-{post_type}-{slug}.php

So that, for example, in a post type called review, I could make a template for a post called “My Great Review” at single-review-my-great-review.php

Has anybody set this up before? single-{post_type}-{slug}.php

6

A) The Base in Core

As you can see in the Codex Template Hierarchy explanation, single-{$post_type}.php is already supported.


B) Extending the core Hierarchy

Now there’re gladly some filters and hooks inside /wp-includes/template-loader.php.

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • AND: a specific filter inside get_query_template( $type, ... ) named: "$type}_template"

B.1) How it works

  1. Inside the template loader file, the template gets loaded by a query var/wp_query conditional: is_*().
  2. The conditional then triggers (in case of a “single” template): is_single() && $template = get_single_template()
  3. This triggers then get_query_template( $type, $templates ), where $type is single
  4. Then we have the "{$type}_template" filter

C) The solution

As we only want to extend the hierarchy with one template that gets loaded before the actual "single-{$object->post_type}.php" template, we’ll intercept the hierarchy and add a new template to the beginning of the templates array.

// Extend the hierarchy
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // New 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Like in core
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Now we add the filter to the appropriate hook
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

NOTE: (If you want to use something other than the default objects slug) You’ll have to adjust $slug according to your permalink-structure. Just use whatever you need from the global (object) $post.

Trac Tickets

As the above approach is currently not supported (you can only filter the absolute located path this way), here’s a list of trac tickets:

  • Extending the hierarchy with post_type->slug
  • Introduce a filter for get_query_template()
  • Filter the complete hierarchy – most promising ticket ⤎ follow this ticket by @scribu as cc

Leave a Reply

Your email address will not be published. Required fields are marked *