I am trying to customize the behavior of my blog to serve a specific single post template based on the category the post is assigned to.
I came across this filter in my parent theme which is what gave me the idea. The theme is Photo Workshop by Graph Paper Press.
//add single post template depending on category slug
add_filter('single_template', 'gpp_single_template');
function gpp_single_template($single) {
global $wp_query, $post;
foreach((array)get_the_category() as $cat) :
// single posts template based on category slug
if(file_exists(TEMPLATEPATH . '/single-' . $cat->slug . '.php'))
return TEMPLATEPATH . '/single-' . $cat->slug . '.php';
//else load single.php
elseif(file_exists(TEMPLATEPATH . '/single.php'))
return TEMPLATEPATH . '/single.php';
endforeach;
return $single;
}
Instead of overriding the file it uses (which may not be possible because it’s included using TEMPLATEPATH), I thought it would be a better idea to just remove their filter & then add my own. Essentially, I’m not really trying to do something different than their code, but I want it to look in the child theme directory first which is why I am using the locate_template()
function. In addition to that, I wanted to hard-code the highest priority template.
My version of the filter from my child theme’s functions.php
:
// remove the stock filter
remove_filter('single_template','gpp_single_template');
// add the new one
add_filter('single_template', 'single_template_override');
//add single post template depending on category slug
function single_template_override($path) {
global $wp_query, $post;
$categories = get_the_category();
$cat_slugs = array();
foreach ($categories as $cat) {
$cat_slugs[] = $cat->slug;
}
$templates = array();
// add in the top priorities if present
if (in_array('fine-art', $cat_slugs)) {
// add to the beginning
$templates[] = 'single-fine-art.php';
}
foreach($cat_slugs as $cat_slug) :
// single posts template based on category slug
$filename = 'single-' . $cat_slug . '.php';
// if not already in the array, add it
if (!in_array($filename, $templates)) {
$templates[] = $filename;
}
endforeach;
$found = locate_template($templates, false);
if ($found) {
return $found;
} else {
return $path;
}
}
For some reason posts with the Fine Art category are not pulling the single-fine-art.php
template.
I have dug into the depths of the wordpress core to see where this filter is applied and everything seems like it should work to me. The filter can be found in get_single_template()
which passes it’s parameters to get_query_template()
.
Any help would be much appreciated!
The problem was that the
remove_filter
function wasn’t working. Apparently this is not uncommon from what I’ve read. I tried testing it with different priorities (1, 9, 20, 999), but there was no difference.So my filter in the child theme and the filter I was trying to remove from the parent theme both had the same priority. WP loads the child theme’s functions.php right before the parent’s so I’m guessing that’s why my filter was not taking effect because it was happening first and then being filtered again by the parent’s.
Anyways, my solution was simply to change the priority of my
add_filter
function to 11, like so:You can also use “next level”
singular
(via https://developer.wordpress.org/reference/hooks/type_template/) with optional prioritySince
single_template
did not work for me on site with alot of custom templates, this was workaround.