4

I have a blog in WordPress. I have multiple categories. I want to use a specific layout for all posts under a category and all of its sub categories.

Example : My categories organized as bellow.

  1. Guide(parent category)

    1.1 Electical

    1.1.1 TV

    1.1.2 Radio

    1.2 Plumbing

    1.3 Home Repair

    1.3.1 Kitchen

    1.3.2 Bathroom

3

You can do that with single_template filter. First you will need to check if a post belongs to a top level category. So here is the function.

// custom single template for specific category
function wpse_custom_category_single_template( $single_template ) {

    global $post;

    // get all categories of current post
    $categories = get_the_category( $post->ID );
    $top_categories = array();

    // get top level categories
    foreach( $categories as $cat ) {
        if ( $cat->parent != 0 ) {
            $top_categories[] = $cat->parent;
        } else {
            $top_categories[] = $cat->term_id;
        }
    }

    // check if specific category exists in array
    if ( in_array( '8', $top_categories ) ) {
        if ( file_exists( get_template_directory() . '/single-custom.php' ) ) return get_template_directory() . '/single-custom.php';
    }

    return $single_template;

}

add_filter( 'single_template', 'wpse_custom_category_single_template' );

In similar situation usually people check for parent category with $categories[0]->category_parent;, which is right but only works if you have assigned one category to each post. If you have 2 and more categories then this solution will always work.

| improve this answer | |
  • This will only work for the 1st level child terms and not for 2nd or 3 level children. Had something similar but deleted it after rereading the OP – Pieter Goosen Jun 18 '15 at 8:17
  • Oh. Then we will have to run nested loops. Kind of resource exhausting. I think he should use a better solution like use a custom field etc. – Robert hue Jun 18 '15 at 8:32
  • Custom fields is a really good option here if the OP wants to take that route. I have tried in my answer to keep things down to the minimum, but it will still be a bit hard on db calls :-) – Pieter Goosen Jun 18 '15 at 8:38
  • This code works fine. – Bikram Pahi Jun 18 '15 at 9:33
  • Just as a note, this seems like a good case for get_ancestors() - simple example: $ancestors_arr = get_ancestors( get_the_ID(), 'category' ); $ancestors_rev = array_reverse( $ancestors_arr ); $top_most_parent = $ancestors_rev[0]; if ( $top_most_parent == 123 ) {} – Nicolai Jun 18 '15 at 11:00
4

EDIT

NOTE If you need only the parent and first level child terms, the answer from @Roberthue should work great. If you need all level child terms, then my solution should work)

I have updated my code to be more effecient.

  • Run get_ancestors() only if we cannot find the parent term or its direct children

  • Stop the execution of the foreach loop immediately when we find our parent term from the get_ancestor function

  • Broke my checks up into smaller pieces and immediately stop execution when my checks return true

ORIGINAL ANSWER

By default, there is no option to set a specific template for posts from a specific category. This said, it doesn't mean it can't be done. To achieve this, you need to use the single_template filter to set your custom single template page to posts with a specific set of categories.

You can try something like the following: (CAVEAT: The code is untested and needs at least PHP 5.3)

add_filter( 'single_template', function ( $template ) 
{
    // Get the current queried post id
    $current_post = get_queried_object_id();

    // Get the post terms. Change category to the correct taxonomy name if your post terms is from a custom taxonomy
    $terms = wp_get_post_terms( $current_post, 'category' );

    // Check if we have terms and we don't have an error. If we do, return default single template
    if ( !$terms || is_wp_error( $terms ) )
        return $template;

    // Check if our custom template exists before going through all the trouble to find out terms
    $new_template = locate_template( 'single-custom.php' );
    if ( !$new_template ) 
        return $template;

    // Get al the term ids in an array and check if we can find our parent term
    $term_ids = wp_list_pluck( $terms, 'term_id' );
    if ( in_array( 10, $term_ids ) )
        return $template = $new_template;

    // Get all the parent ids in an array and look for our parent term if we could not find it using term ids
    $parent_ids = wp_list_pluck( $terms, 'parent' );
    if ( in_array( 10, $parent_ids ) )
        return $template = $new_template;

    // If we cannot find the parent or direct children, lets look for lower level children
    $bool = false;
    foreach ( $term_ids as $term ) {
        // Use get_ancestors and check if we can find our parent term id
        if ( in_array( 10, get_ancestors( $term, 'category' ) ) ) {
            $bool = true;
            // If we found our parent, stop execution of our foreach loop
            break;
        }
    }

    // If $bool is true, return our custom single template
    if ( $bool )
        return $template = $new_template;

    // If all our conditions failed, return the default single template
    return $template;
});

EDIT 2

The above code is now tested and working. Fixed a couple of small bugs :-)

| improve this answer | |
  • Post updated. Had a couple of bugs and syntax errors. :-) – Pieter Goosen Jun 18 '15 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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