How to display related posts by subcategory and not parent category

I’m trying to find a way to display related posts that are in a subcategory of a specific parent category based upon the subcategory of the current post. The current post may be assigned to multiple parent categories, but I only want to display related posts of one of the parent category’s subcategories.

So for example, a post may be assigned to categories A, B and C, but I want to show related posts based upon the current post’s B subcategory and not show all the posts from either A, B or C. Sorry, this question/problem is hard to explain.

Read More

I’m using this code to display the category name and posts, but I’m not sure how to exclude parent categories from it, so that only the subcategory posts will display.

More in 
    <?php $category = get_the_category(); 
        if ( in_category(52) || in_category(56) || in_category(57) || in_category(99) || in_category(28) ) {
            echo $category[1]->cat_name; 
        } else {echo $category[0]->cat_name;}
    ?>

<?php if (have_posts() && !(in_category('32'))) : ?>    
    <?php $i = 1; while (have_posts() && $i <= 1) : the_post(); ?>
        <?php $related = get_posts(array('category__in' => wp_get_post_categories($post->ID), 'numberposts' => 1, 'post__not_in' => array($post->ID)));
if($related) foreach( $related as $post) {
        setup_postdata($post); ?>
        <?php the_post_thumbnail('medium'); ?>
            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
                <a href="<?php the_permalink(); ?>"><?php the_excerpt(''); ?></a>
                <?php the_author(); ?></div>    
            <?php } wp_reset_postdata(); ?>
    <?php $i++; endwhile; ?>
<?php endif; ?>

Thanks!

Related posts

2 comments

  1. There is indeed a much simpler way to do this.

    First, to get the child category, just check the value of each category’s parent. If it’s a top-level category, the parent will be 0. So the child category will pass the test if( 0 != $category->parent ):

    $categories = get_the_category();
    foreach( $categories as $category ){
        if( 0 != $category->parent )
            $child_cat = $category;
    }
    

    Then query for your posts using that category ID as the cat argument. To output a thumbnail for only the first post, simply check if the current_post of your query object is 0. That number gets automatically incremented for each post in your loop, starting at 0:

    if( isset( $child_cat ) ){  
        echo 'More in ' . $child_cat->name;
        $args = array(
            'cat' => $child_cat->term_id,
            'post__not_in' => array( get_the_ID() )
        );
        $related = new WP_Query( $args );
        if( $related->have_posts() ){
            while( $related->have_posts() ){
                $related->the_post();
                if( 0 == $related->current_post ){
                    the_post_thumbnail('medium');
                }
                // your template tags, etc..
                the_title();
            }
            wp_reset_postdata();
        }
    }
    

    Also note, you never need to use wp_reset_query() unless you overwrite the global $wp_query, which doesn’t happen here.

  2. So here’s what I came up with. I don’t think that this is the ideal way to code this, but it is doing exactly what I need it to.

    This got me the label for the related items subcategory section in the sidebar by excluding the parent categories:

    More in 
        <?php 
            $category = get_the_category();
            $catname = $category[0]->cat_name;
            if ($catname == 'News' || $catname == 'Featured' || $catname == 'Nav Bar News') {
                $catname = $category[1]->cat_name;
                    if ($catname == 'News' || $catname == 'Featured' || $catname == 'Nav Bar News') {
                        $catname = $category[2]->cat_name;
                        if ($catname == 'News' || $catname == 'Featured' || $catname == 'Nav Bar News') {
                            $catname = $category[3]->cat_name;
                        }
                    }
                } else {
                    $catname = $category[0]->cat_name;
                }
                echo $catname;
            ?>
    

    This is where it gets a little messy, but the code works for what I needed to achieve. I excluded the parent categories and then used the loop to display the posts from the related subcategory:

            wp_reset_query();
            $this_post = $post->ID;
            $category = get_the_category($post->ID);
            $category = $category[0]->cat_ID;
            if ($category == '30' || $category == '28' || $category == '99') {
                $category = $category[1]->cat_ID;
                if ($category == '30' || $category == '28' || $category == '99') {
                    $category = $category[2]->cat_ID;
                    if ($category == '30' || $category == '28' || $category == '99') {
                        $category = $category[3]->cat_ID;
                    } 
                }
            } 
            $args = array(
                'category__in' => array($category),
                'post__not_in' => array($this_post)
            );
            $the_query = new WP_Query($args);
    
            if ( $the_query->have_posts() && !(in_category('32'))) {
                $i = 0; while ( $the_query->have_posts() && $i < 1) {
                    $the_query->the_post(); ?>
                            <?php the_post_thumbnail('medium'); ?>
                            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
                                <a href="<?php the_permalink(); ?>"><?php echo excerpt(30); ?></a>
                                <?php the_author(); ?>
                <?php $i++; } 
            } else {
                //echo 'no posts';
            }
            wp_reset_postdata();
    
            wp_reset_query();
            $this_post = $post->ID;
            $category = get_the_category($post->ID);
            $category = $category[0]->cat_ID;
            if ($category == '30' || $category == '28' || $category == '99') {
                $category = $category[1]->cat_ID;
                if ($category == '30' || $category == '28' || $category == '99') {
                    $category = $category[2]->cat_ID;
                    if ($category == '30' || $category == '28' || $category == '99') {
                        $category = $category[3]->cat_ID;
                    } 
                }
            } 
            $args = array(
                'category__in' => array($category),
                'post__not_in' => array($this_post),
                'offset' => 1
            );
            $the_query = new WP_Query($args);
    
            if ( $the_query->have_posts() && !(in_category('32'))) {
                $i = 0; while ( $the_query->have_posts() && $i < 3) {
                    $the_query->the_post(); ?>
                            <a href="<?php the_permalink() ?>" rel="bookmark" title="<?php the_title(); ?>"><?php the_title(); ?></a>
                        <?php if ($i < 2) { ?>
                            <hr style="width: 92%;">
                        <?php } ?>
                <?php $i++; } 
            } else {
                //echo 'no posts';
            }
            wp_reset_postdata();
    

    I tried to do this all in one loop, but I couldn’t figure out a way to display the featured image for only the first post and then exclude that post from being displayed again. If anyone has a cleaner way to write this, please let me know.

Comments are closed.