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
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
- Inside the template loader file, the template gets loaded by a query var/wp_query conditional:
is_*()
.
- The conditional then triggers (in case of a “single” template):
is_single() && $template = get_single_template()
- This triggers then
get_query_template( $type, $templates )
, where $type
is single
- 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