1
votes

Based on Sort WooCommerce product category sub menu items by name ASC in Wordpress menu answer code to my previous question, I am able to automatically display child subcategories as menu sub items for some product categories in my WordPress navigation menu.

My question is: Is it possible to hide empty subcategories (sub menu items)?

And maybe if possible hide categories that contains only one product that is Sold Out.

2

2 Answers

1
votes

You can use additionally get_terms() with the following parameters:

  • 'include' to include all child terms from get_term_children() function as a coma separated string of term ids.
  • 'orderby' with 'name' attribute to sort terms by name,
  • 'order' with 'ASC' attribute to sort terms ascending,
  • 'hide_empty'with true attribute to not include empty terms.

So sorting will be made directly without requiring a foreach loop and you will get also directly an array of WP_Term objects.

The revisited code:

add_filter( 'wp_get_nav_menu_items', 'custom_submenu_product_categories', 10, 3 );
function custom_submenu_product_categories( $items, $menu, $args ) {
    // don't add child categories in administration of menus
    if (is_admin()) {
        return $items;
    }

    $taxonomy = 'product_cat';

    foreach ($items as $index => $post) {

        if ( $taxonomy !== $post->object ) {
            continue;
        }

        $children_terms_ids = get_term_children( $post->object_id, $taxonomy );

        if( ! empty($children_terms_ids) ) {
            $sorted_terms       = get_terms(array(
                'taxonomy'   => $taxonomy,
                'include'    => implode(',', $children_terms_ids),
                'orderby'    => 'name',
                'order'      => 'ASC',
                'hide_empty' => true,
            ));

            // Loop through sorted child terms to set them as sorted sub menu items
            foreach ( $sorted_terms as $index2 => $child_term ) {
                $item = new \stdClass();

                $item->title            = $child_term->name;
                $item->url              = get_term_link( $child_term, $taxonomy );
                $item->menu_order       = 500 * ($index + 1) + $index2;
                $item->post_type        = 'nav_menu_item';
                $item->post_status      = 'published';
                $item->post_parent      = $post->ID;
                $item->menu_item_parent = $post->ID;
                $item->type             = 'custom';
                $item->object           = 'custom';
                $item->description      = '';
                $item->object_id        = 0;
                $item->db_id            = 0;
                $item->ID               = 0;
                $item->position         = 0;
                $item->classes          = array();
                $item->target           = ''; // <= Missing - Mandatory to avoid an error
                $item->xfn              = ''; // <= Missing - Mandatory to avoid an error

                $items[] = $item;
            }
        }
    }
    return $items;
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Now is not really possible to hide subcategories that contains only one product that are Sold Out, sorry.

1
votes

You can use get_terms() , here you can specify more options, so

get_term_children( $post->object_id, $taxonomy );

Will become

get_terms(array(
  'taxonomy' => $taxonomy,
  'parent' => $post->object_id,
  'hide_empty' => true,
));

This also has a 'order_by' parameter, that defaults to the name of a term