Force sub-categories to use the parent category template

A couple of times in the last several years, I’ve needed sub-categories to inherit their parent’s archive template, but it’s just not something the Template Hierarchy supports. I’ve seen several plugins that tried and failed to do it, so finally I wrote a little filter that in my testing, works any number of levels deep, from sub-sub-categories to sub-sub-sub-categories. Enjoy!


function new_subcategory_hierarchy() {	
	$category = get_queried_object();

	$parent_id = $category->category_parent;

	$templates = array();
	
	if ( $parent_id == 0 ) {
		// Use default values from get_category_template()
		$templates[] = "category-{$category->slug}.php";
		$templates[] = "category-{$category->term_id}.php";
		$templates[] = 'category.php';		
	} else {
		// Create replacement $templates array
		$parent = get_category( $parent_id );

		// Current first
		$templates[] = "category-{$category->slug}.php";
		$templates[] = "category-{$category->term_id}.php";

		// Parent second
		$templates[] = "category-{$parent->slug}.php";
		$templates[] = "category-{$parent->term_id}.php";
		$templates[] = 'category.php';	
	}
	return locate_template( $templates );
}

add_filter( 'category_template', 'new_subcategory_hierarchy' );

Published by

Drew Jaynes

Drew is a former Core Developer for the WordPress open source project, and he works on cool plugins like AffiliateWP, Easy Digital Downloads, and Restrict Content Pro.

49 thoughts on “Force sub-categories to use the parent category template”

  1. Thanks. It works perfectly. I also have another similar problem, how do force the sub page to use its parent page template?

    1. If you’re using post_class() or body_class(), I’d just write a filter callback to add the parent class and then do add_filter() with ‘body_class‘ or ‘post_class‘ as the hook, and call the callback inside new_subcategory_hierarchy() or whatever.

  2. Tried this but it didn’t work.

    function body_class_add_parent_category( $classes ) {

    if ( is_category() ) {
    $category = get_the_category();
    $parent = $category[0]->category_parent;
    $class = get_cat_name($parent);
    } return $classes;
    }
    add_filter( ‘body_class’, ‘body_class_add_parent_category’ );

    Not quite sure what’s wrong here. Any suggestions are appreciated.

    1. First off, remember that $classes is an array. So you’d want to assign the returned value of get_cat_name( $parent ) with something like

      function body_class_add_parent_category( $classes ) {
      
      	if ( is_category() ) {
      		$category = get_the_category();
      		$parent = isset( $category[0]->category_parent ) ? $category[0]->category_parent : '';
      		$classes[] = get_cat_name( $parent );
      	}
      	return $classes;
      }
      add_filter( ‘body_class’, ‘body_class_add_parent_category’ );
      

      Note that $class became $classes[]. Also, I added an isset() ternary to avoid a notice.

  3. Thanks again for your help. Just learning php. This looks good but for some reason it’s not adding the parent category body class. I used the script below for single posts. This worked perfectly but I was not able to adapt it for child categories. Any thoughts?

    <?php
    // Add categories to body class on Posts
    function body_class_add_categories( $classes ) {
     
    	// Only proceed if we're on a single post page
    	if ( !is_single())
    		return $classes;
     
    	// Get the categories that are assigned to this post
    	$post_categories = get_the_category();
      
    	// Loop over each category in the $categories array
    	foreach( $post_categories as $current_category) {
     
    		// Add the current category's slug to the $body_classes array
    		$classes[] = 'category-' . $current_category->slug;
     
    	}
    	
    	foreach( $post_categories as $current_category) {
     
    		// Add the current category's slug to the $body_classes array
    		$classes[] = 'category-' . $parent_category->slug;
     
    	}
     
    	// Finally, return the $body_classes array
    	return $classes;
    }
    add_filter( 'body_class', 'body_class_add_categories' );
    
  4. Thanks for the snippet. Really useful. How would you modify the code to use it with custom taxonomy instead of default categories?

    1. Hi Petr,

      Something like the following should work for hierarchical taxonomies (untested):

      /**
       * Filter the taxonomy hierarchy to inject a parent level of templates.
       * 
       * @param string $template The current template.
       * @return string Filtered taxonomy template.
       */
      function new_tax_hierarchy( $template ) {
      	$term = get_queried_object();
      
      	// If not an object, or the object doesn't have a taxonomy, bail.
      	if ( ! is_object( $term ) || ! isset( $term->taxonomy ) )
      		return $template;
      
      	$taxonomy = $term->taxonomy;
      
      	// If the taxonomy isn't hierarchical, bail.
      	if ( ! is_taxonomy_hierarchical( $taxonomy ) )
      		return $template;
      
      	$templates = array();
      	$parent_id = $term->parent;
      
      	if ( 0 == $parent_id ) {
      		// Use default values from get_taxonomy_template().
      		$templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
      		$templates[] = "taxonomy-$taxonomy.php";
      		$templates[] = 'taxonomy.php';
      	} else {
      		$parent = get_term( $parent_id, $taxonomy );
      
      		// Current templates.
      		$templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
      		$templates[] = "taxonomy-$taxonomy.php";
      
      		// Parent templates.
      		$templates[] = "taxonomy-$taxonomy-{$parent->slug}.php";
      		$templates[] = "taxonomy-$taxonomy-{$parent->term_id}.php";
      		$templates[] = 'taxonomy.php';
      	}
      	return locate_template( $templates );
      }
      add_filter( 'taxonomy_template', 'new_tax_hierarchy' );
      
      1. Thanks for your reply, really appreciate your help.

        I have tried your function, but it still doesn’t work. Here is what I am trying to achieve:

        Render all products with producttype (kitchen, bathroom) taxonomy using this template:
        taxonomy-producttype.php (works fine)

        Render all products in kitchen category using this template:
        taxonomy-producttype-kitchen.php (works fine)

        Render all products in kitchen subcategories using this template:
        taxonomy-producttype-kitchen.php (but it currently renders as taxonomy-producttype.php)

        Any thoughts?

      2. Hey Drew, great article, I am trying this for taxonomies, it didn’t work as Petr.
        I tried debugging it, it is returning the correct template (the parent) at this line “return locate_template( $templates );”

        but it didn’t work.

        1. I used this filter “template_include” intead of “taxonomy_template”
          and I rearranged the templates according to my need:
          // Parent templates.
          $templates[] = “taxonomy-$taxonomy-{$parent->slug}.php”;
          $templates[] = “taxonomy-$taxonomy-{$parent->term_id}.php”;
          $templates[] = ‘taxonomy.php’;

          // Current templates.
          $templates[] = “taxonomy-$taxonomy-{$term->slug}.php”;
          $templates[] = “taxonomy-$taxonomy.php”;

          and it worked out 😀

  5. Thanks Drew! It worked for me. I tried several other code snippets from other sites as well, but they didn’t work. But this one worked at first go! 🙂

  6. Thank you ! It’s perfect. 🙂
    Unfortunately, it doesn’t take sub sub category as you said. Then i make this :

    $category = get_queried_object();
    $temp = $category;
    
    do {
    	$parent_id = $temp->category_parent;
    	$temp = get_category( $parent_id );
    } while ( $temp->category_parent );
    

    instead of :

    $category = get_queried_object();
     
    $parent_id = $category-&gt;category_parent;
    

    Have a nice day.

    1. Thank you! This alteration works perfectly. As you said, the original code doesn’t work for sub-sub- categories.

  7. I tried using this code to show a single post for a particular category name- products but it does not work for me. Somehow it picks the single.php file and not the category-products.php

    I am new to php functions kindly help me achieve different templates for different category & its sub-category should also show the layout of its parent’s category template

  8. This didn’t work for me copying and pasting the snippet from your main post into my function.php file in a 2015 child theme (which I’m just starting to customise so there’s not really anything in function.php for it to clash with.

    I’ve created a template for my parent category – category-artwork.php (which works) and I’d like the child categories (portraits, petportraits etc) to use this, rather than having to duplicate this for each child category, or changing the default archive page for all categories. So it sounds like your code should work but the display still seems to be the default twentyfifteen one.

    Is it meant to go somewhere else? 🙂

    1. Nevermind, I’d forgotten that when I set up the categories I initially had a category level in between the two so it wasn’t the direct parent. Have fixed that and its working fine, thanks for the code!

  9. Nice! But have question, have hierarchy Parent – Child – Child. For first two works, but for latest child – not.

  10. Hi!

    I have a question: If I need apply this to only one parent category and it’s child? The rest of the others parent categories must keep as usual.

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *