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!

  • What happens if you var_dump and wp_die after $found = locate_template($templates, false);? Commented Feb 21, 2012 at 17:36
  • Never tried that, but it is coming back as I would expect: /***/***/***/***/fineart/wp-content/themes/fpp-custom/single-fine-art.php. Commented Feb 21, 2012 at 18:26
  • @StephenHarris - Just figured it out! I'm not sure why this made the difference, but when I changed the priority of my add_filter to 11, it worked. The original filter I was removing had the default priority and so did my remove function, so why would changing my filter's priority matter? Commented Feb 21, 2012 at 18:34
  • Maybe your remove_filter wasn't working? It could have been called before the add_filter of the parent theme...? Can you post your solution as answer and then accept it after 24 hours, just so it takes this question off the unanswered pile and helps see what worked for you Commented Feb 21, 2012 at 19:05

2 Answers 2


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

You can also use "next level" singular (via https://developer.wordpress.org/reference/hooks/type_template/) 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.