Problem getting single_template filter to work – I want to serve a different single.php file for posts in a certain category

The question:

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';


    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

// 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;


    $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 Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

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:

add_filter('single_template', 'single_template_override', 11);

Method 2

You can also use “next level” singular (via with optional priority

add_filter('singular_template', 'single_template_override');

Since single_template did not work for me on site with alot of custom templates, this was workaround.

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment