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

I'm a WordPress / journalism junkie who thrives on all things relating to both. I built a portfolio site but it really wasn't indicative of a blog, so that's how WerdsWords came about. You can reach me at my Google Profile, Twitter or Facebook.

29 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?

  5. 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.

  6. 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

Leave a Reply