List only child categories a post is in, of a specific parent category

The question:

Either this is harder than it needs to be or I am just not understanding WordPress/PHP very well 🙁 All I want to do is show the child/sub categories of a specific parent category…but only if the post is in those subcategories. Specific example:

I am building a wine reviews website and these are the categories:

  • Brand
    • Subcategory 1
    • Subcategory 2
    • etc.
  • Region
    • Subcategory 1
    • Subcategory 2
    • etc.
  • Grape
    • Subcategory 1
    • Subcategory 2
    • etc.

The parent categories will never change, and every post will have at least 1 subcategory selected under each parent, so in the LOOP I can just list the parents by name. But I am needing to dynamically output the subcategories, something like this:

Brand: <?php list_post_subcategories_of('brand'); ?>
Region: <?php list_post_subcategories_of('region'); ?>
Grape: <?php list_post_subcategories_of('grape'); ?>

Is there any easy way like this? It seems like this should be a basic function in WordPress? I’ve looked at the functions ‘get_categories’ and ‘in_category’ but they don’t seem to be able to do this.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

I would personally create three custom taxonomies rather than do this with categories/subcategories, then this becomes a non-issue.

To do this with categories/subcategories, start with the names/IDs of your parent categories, and loop over each parent, then within that, loop over the terms associated with the post and check the term’s parent ID against the top level category’s ID:

// names / IDs of parents
$parents = array(
    'Brand' => 42,
    'Region' => 22,
    'Grape' => 18
);
// get post categories
$categories = get_the_terms( $post->ID, 'category' );
// output top level cats and their children
foreach( $parents as $parent_name => $parent_id ):
    // output parent name and link
    echo '<a href="' . get_term_link( $parent_id, 'category' ) . '" rel="nofollow noreferrer noopener">' . $parent_name . '</a>: ';
    // initialize array to hold child links
    $links = array();
    foreach( $categories as $category ):
        if( $parent_id == $category->parent ):
            // put link in array
            $links[] = '<a href="' . get_term_link( $category ) . '" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">' . $category->name . '</a>';
        endif;
    endforeach;
    // join and output links with separator
    echo join( ', ', $links );
endforeach;

EDIT- dynamically fetch top level terms:

// get top level terms
$parents = get_terms( 'category', array( 'parent' => 0 ) );
// get post categories
$categories = get_the_terms( $post->ID, 'category' );
// output top level cats and their children
foreach( $parents as $parent ):
    // output parent name and link
    echo '<a href="' . get_term_link( $parent ) . '" rel="nofollow noreferrer noopener">' . $parent->name . '</a>: ';
    // initialize array to hold child links
    $links = array();
    foreach( $categories as $category ):
        if( $parent->term_id == $category->parent ):
            // put link in array
            $links[] = '<a href="' . get_term_link( $category ) . '" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">' . $category->name . '</a>';
        endif;
    endforeach;
    // join and output links with separator
    echo join( ', ', $links );
endforeach;


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment