skip to Main Content

What I’m trying to do is display a menu in my Woocommerce shop’s sidebar with the current product category name and current categories children. If the product category has no children, then it should display the parent category and parent category children.

This is how the hierarchy looks:
SHOP > PREPARED FOODS > FOODSTUFF


When you are on the PREPARED FOODS page you should see.

Prepared Foods

  • Bitters
  • Charcuterie
  • Foodstuff

When you are on the FOODSTUFF page you should see

Prepared Foods

  • Bitters
  • Charcuterie
  • Foodstuff

Right now I’ve gotten it to display the parent category links when you are in the top level category, but I haven’t gotten it to display the parent category name when you are in the top level. Here is the code I have so far:

<?php
      $queried_object = get_queried_object();

if ( is_product_category() && is_a($queried_object, 'WP_Term') ) {
    $taxonomy  = $queried_object->taxonomy;

    echo '<h2 class="shop__sidebar-heading">
    <a href="' . get_term_link( $queried_object ) . '">' . $queried_object->name . '</a>
    </h2>';
}
    ?>

<?php 
$term = get_queried_object()->term_id;
$termid = get_term($term, 'product_cat' );
if($termid->parent > 0) 
    { 
        $args = array(
            'orderby'       => 'name', 
            'order'         => 'ASC',
            'hide_empty'    => false, 
            'child_of'      => $termid->parent,
    ); 
    $siblingproducts = get_terms( 'product_cat', $args);
    foreach ($siblingproducts as $siblingproduct) { 
         if ($siblingproduct->term_id == $term ) {  ?>
            <li>
<?php } else { ?>    
        <li>
<?php } ?>
    <a href="<?php 
    echo get_term_link( $siblingproduct ); ?>"><?php echo $siblingproduct->name; ?><?php 
echo "<span class='count'>" .  $siblingproduct->count . "</span>"; ?></a></li>
<?php }
    } else { 
        $args = array(
            'orderby'       => 'name', 
            'order'         => 'ASC',
            'hide_empty'    => false, 
            'child_of'      => $term 
        ); 
    $subproducts = get_terms( 'product_cat', $args);
    foreach ($subproducts as $subproduct) { ?>
        <li> <a href="<?php echo get_term_link( $subproduct ); ?>"><?php echo $subproduct->name; ?><?php echo "<span class='count'>" . "</span>"; ?></a></li>
<?php }
}
?>

An example of what I’m trying to achieve can be see on the Food52 website sidebar https://food52.com/shop/pantry

2

Answers


  1. I’ve taken the liberty to clean up a few things along the way (such as removing some unnecessary open/closing PHP tags) and some clarifying things – I hope you don’t mind! Going through your existing code:

    • You shouldn’t need to check is_a() on the queried object (also, consider using instanceof instead, as it has lower overhead since it’s a language construct and not a function: if($queried_object instanceof WP_Term){}. Still, you shouldn’t need to check it because is_product_category() runs the is_tax() function which should handle that for you.

    • You seem to have an unused $taxonomy declaration

    • It’s less important on WordPress supplied functions, but it’s good to get into the habit of using esc_url and esc_attr on attribute fields.

    • You’ve got some redundancy issues with getting the $term set. It also seems like you could/should move these up into your outer if statement since you’re already checking to see if it’s a WP_Term object, so you shouldn’t have to worry about things not being set or redefining values from it. Also your $term and $termid declarations are a bit mixed, it seems like they are flipped ($term is the ID and $termid is the actual object)

    • You seem to be creating two separate loop argument arrays (and subsequent loops) for no real reason, other than changing variable names – based just on if it’s a toplevel term or not (parent_id > 0)

    • You add have a conditional <li> that doesn’t take advantage of the conditional check if it’s the current WP_Term being queried; Did you mean to add an active class or something in there?

    • You don’t appear to have a <ul> to contain the <li> elements. I’ve added that in conditionally based on the results of get_terms for the child/sibling terms loop.


    I’m familiar with WooCommerce, but don’t currently have it installed on my dumping ground site, but I’ve recreated the category (product_cat) structure from it and used this code (just with the taxonomy changed) and it appears to do what you’ve asked:

    <?php
        if( is_product_category() ){
            $queried_object = get_queried_object();
            $child_terms    = get_term_children( $queried_object->term_id, 'product_cat' );
            $based_term     = (is_wp_error($child_terms) || empty($child_terms)) ? get_term( $queried_object->parent, 'product_cat' ) : $queried_object;
    
            printf( '<h2 class="shop__sidebar-heading">
                <a href="%s?so64231449=true">%s</a>
            </h2>', esc_url(get_term_link($based_term->term_id)), $based_term->name );
        
            $display_terms = get_terms( 'product_cat', array(
                'orderby'       => 'name', 
                'order'         => 'ASC',
                'hide_empty'    => false,
                'parent'        => $based_term->term_id,
            ) );
    
            if( !empty($display_terms) && !is_wp_error($display_terms) ){
                echo '<ul>';
                    foreach( $display_terms as $display_term ){
                        printf(
                            '<li%s><a href="%s">%s <span class="count">%s</span></a></li>',
                            ($display_term->term_id == $queried_object->term_id) ? ' class="active"' : '',
                            esc_url(get_term_link($display_term->term_id)),
                            $display_term->name,
                            number_format($display_term->count)
                        );
                    }
                echo '</ul>';
            }
        }
    ?>
    

    A few notes:

    • I’ve replaced a lot of the echos with printf(). It may look a little daunting, but it removes the need for the mix of PHP Escapes and string concatenation that you have. It also makes it easier to pass functions and Ternary Operators to it.

      • The first argument is the string you want to work with
      • Each subsequent variable replaces each %s, in order, with that value.
    • Ternary Operators are basically a succinct, one line, "if/else" statement. This lets you check for the active WP_Term in the same declaration as the other terms really easily.

    Here are a few links to show you it’s working (scroll to the bottom of the page):

    Login or Signup to reply.
  2. You can get category and child category using following code. You need to call the following functions according to your needs and pass parameters.

    /**
     * Get Category
     * @param $taxonomy
     * @param string $order
     * @return array
     */
    function getPostTermCategory($taxonomy, $order = 'asc')
    {
        $term_query = new WP_Term_Query([
            'taxonomy' => $taxonomy,
            'order' => $order,
            'hide_empty' => false,
            'parent' => 0
        ]);
        $categories = [];
        foreach ($term_query->terms as $term) {
            $categories[] = $term;
        }
        return $categories;
    }
    
    /**
     * Get Child Categories of Parent
     * @param $taxonomy
     * @param $parentId
     * @param string $order
     * @return array
     */
    function getPostTermChildCategory($taxonomy, $parentId, $order = 'asc')
    {
        $term_query = new WP_Term_Query([
            'taxonomy' => $taxonomy,
            'order' => $order,
            'hide_empty' => false,
            'parent' => $parentId
        ]);
        $categories = [];
        foreach ($term_query->terms as $term) {
            $categories[] = $term;
        }
        return $categories;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search