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 )
get_query_template( $type, ... )
named:"$type}_template"
B.1) How it works
is_*()
.is_single() && $template = get_single_template()
get_query_template( $type, $templates )
, where$type
issingle
"{$type}_template"
filterC) 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.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:
get_query_template()
Following the Template Hierarchy image, I don’t see such an option.
So heres how i’d go about it:
Solution 1 (Best in my opinion)
Make a template file and associate it to the review
Adding the template php file in your theme directory, it would appear as a template option in your post’s edit page.
Solution 2
This could probably be achieved using
template_redirect
hook.In functions.php file :
EDIT
Added
file_exists
checkThe top answer (from 4 years ago) no longer works, but the WordPress codex has the solution here:
Use Page Templates
Another approach for scalability would be to duplicate the page template drop-down functionality on the
page
post type for your custom post type.Reusable Code
Duplication in code is not a good practice. Overtime it can cause severe bloat to a codebase when then make it very difficult for a developer to manage. Instead of creating a template for every single slug, you most likely will need a one-to-many template that can be reused instead of one-to-one post-to-template.
The Code
This is a bit of a late answer, but I thought it would be valuable since no one on the web has documented this approach as far as I can tell. Hope this helps someone out.
In my case, I have Album and Track custom post types linked by an Album taxonomy. I wanted to be able to use different Single templates for the Album and Track posts depending on their Album taxonomy.
Based on Kaiser’s answer above, I wrote this code. It works well.
Note. I didn’t need the add_action().
I can now create templates named single-gregory-cpt-track-tax-serendipity.php and single-gregory-cpt-album-tax-serendipity.php and WP will use them automatically; ‘tax-serendipity’ is the slug for the first Album taxonomy term.
for reference, the ‘single_template’ filter hook is declared in:
/wp-includes/theme.php:
get_query_template()
Thank you Kaiser for the sample code.
Cheers,
Gregory
Update for Brians code, I found that when the dropdown box was not being used the “default” template option was being saved into wp_page_template which caused it to try and find a template called default. this change just checks for the option “default” when saving and deletes the post meta instead (useful if you changed the template option back to default)