Get entire hierarchy of categories

I am trying to set up a hierarchal list of categories for my woocommerce site. This is hard to describe but what I have is something similar to this for product categories…

Animals
 -Dog
  --Beagle
  --Poodle
 -Cat
 -Rabbit
Cars
 -Chevy
 -Toyota
People
Cities
Planets

If I’m looking at the Poodle page I want to display this as my list of categories..

Read More
Animals
 -Dog
  --Beagle
  --Poodle

Here is the code I have currently..

<?php
$args = array( 
    'taxonomy' => 'product_cat',
    'hide_empty' => false,
    'child_of' => get_queried_object()->term_id,
    //'child_of' => 6,
    'title_li' => __( 'Categories' ),
    'depth' => 3
);

wp_list_categories( $args ); 
?>

I’m able to make this work if I set a specific term ID for child_of (commented out above). But I’d like for this to work automatically. Basically I need it to loop back through all of the categories and start listing terms from its highest level category.

Its almost like displaying a breadcrumb, but showing all children categories under the first level category.

Related posts

1 comment

  1. There are two properties you should be interested in in the term object which you get back from get_queried_object() and that is

    • term_id which is the ID of the term

    • parent which is an integer value of the term’s parent. This value is either 0 if the term is top level or any other integer value which is equal the term ID of the current term’s parent

    With this in mind, we can use parent to determine if the term being viewed is a top level term or a term lower down in the hierarchy. This only solves half the issue though as we still do not know when parent is not 0 if that term is a child or grandchild term. To determine that, we will use get_ancestors() to get all the hierarchy of the current term, and from there we can get the top level term

    get_ancestors() return an array of term ids, the last id being the top level term and the first id beign the direct parent of the term passed. For top level terms, an empty array will be returned. As there are overheads here, we will first check if the current term is a top level term or not before we run get_ancestors()

    For large blocks of code, it is always easier for me to write a proper wrapper function which I can call into my templates as needed, so lets code the function

    /**
     * Function to display all terms from a given taxonomy in a hierarchy
     *
     * @param (array) $args Array of valid parameters for wp_list_categories
     */
    function custom_term_list( $args = [] )
    {
        // Make sure that this is a taxonomy term archive for the ttaxonomy 'product_cat', if not, return
        if ( !is_tax( 'product_cat' ) )
            return;
    
        // Get the current term object
        $term = get_queried_object();
    
        // Check if current term is top level or not
        if ( 0 == $term->parent ) {
            // Show all terms in hierarchy below the current term
            $parent = $term->term_id; 
            // If you need to show all terms regardless, you can do the following
            //$parent = 0;
        } else { // Term is not top level
            $hierarchy = get_ancestors( $term->term_id, $term->taxonomy );
            $parent    = end( $hierarchy );
        }
    
        // Make sure we override `child_of` if it is set by the user
        $args['child_of'] = $parent;
        // Make sure we set the taxonomy to the term object's taxonomy property
        $args['taxonomy'] = $term->taxonomy;
    
        wp_list_categories( $args );
    }
    

    Before we look at how to use the function, a few notes:

    • The code is untested and might be buggy. be sure to testthis locally first with debug set to true

    • The code requires at least PHP 5.4

    • I have written the code to only work on taxonomy archive pages of the taxonomy product_cat. You do not need to pass the taxonomy to the function and the taxonomy is taken from the term object. You can however modify the code to work with any taxonomy

    • I have written the code in such a way that if the user sets the child_of parameter, that value will not be used. The function will override that value

    Lets look at usecases. You can use the function as follow: (Code used from OP)

    $args = [
        'hide_empty' => false,
        'title_li'   => __( 'Categories' ),
        'depth'      => 3
    ];
    custom_term_list( $args );
    

Comments are closed.