Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

Modify custom menu function for automatic hierarchy and exclusion of empty product categories (WooCommerce) WordPress

  • SOLVED

Hi there WP gurus!

I have a WordPress website with WooCommerce and a theme built in Genesis. On the site I have a function that makes it possible for me to add product category parents in my menu and then the function adds all children categories that belong to this top category as sub menu items automatically.

Here is the function right now:

add_filter("wp_get_nav_menu_items", function ($items, $menu, $args) {

// don't add child categories in administration of menus
if (is_admin()) {
return $items;
}


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

if ("product_cat" !== $i->object) {
continue;
}


$term_children = get_term_children($i->object_id, "product_cat");


// add child categories

foreach ($term_children as $index2 => $child_id) {

$child = get_term($child_id);

$url = get_term_link($child);


$e = new \stdClass();

$e->title = $child->name;
$e->url = $url;
$e->menu_order = 500 * ($index + 1) + $index2;
$e->post_type = "nav_menu_item";
$e->post_status = "published";
$e->post_parent = $i->ID;
$e->menu_item_parent = $i->ID;
$e->type = "custom";
$e->object = "custom";
$e->description = "";
$e->object_id = 0;
$e->db_id = 0;
$e->ID = 0;
$e->classes = array();

$items[] = $e;

}


}


return $items;

}, 10, 3);


I haven't written this function myself and am not sure if it's possible to do it in a better way.

Anyway, the problem with this function that I want to change is:

1. I would like to make the category dropdowns hierarchical. Right now, the menu is only 1 level deep, although there are sub, sub-sub and sub-sub-sub-categories if you understand what I mean.

2. I want to exclude empty categories automatically, so if there are no products attached to a category, don't add it to the menu.

3. If I add another menu on the site, I don't want this function to affect that menu so if there is a way to only target my main menu by name, id or something, that would be great as well :)

Answers (1)

2017-10-24

Arnav Joy answers:

for the second point please try this
<?php
add_filter("wp_get_nav_menu_items", function ($items, $menu, $args) {

// don't add child categories in administration of menus
if (is_admin()) {
return $items;
}


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

if ("product_cat" !== $i->object) {
continue;
}


$term_children = get_term_children($i->object_id, "product_cat");


// add child categories

foreach ($term_children as $index2 => $child_id) {

$child = get_term($child_id);

if( $child->count == 0 ) continue;

$url = get_term_link($child);


$e = new \stdClass();

$e->title = $child->name;
$e->url = $url;
$e->menu_order = 500 * ($index + 1) + $index2;
$e->post_type = "nav_menu_item";
$e->post_status = "published";
$e->post_parent = $i->ID;
$e->menu_item_parent = $i->ID;
$e->type = "custom";
$e->object = "custom";
$e->description = "";
$e->object_id = 0;
$e->db_id = 0;
$e->ID = 0;
$e->classes = array();

$items[] = $e;

}


}


return $items;

}, 10, 3);


Jens Filipsson comments:

That part seems to work :)


Arnav Joy comments:

for the 3 point please use this code
add_filter("wp_get_nav_menu_items", function ($items, $menu, $args) {

if( $menu->term_id != 18 ) return ;
// don't add child categories in administration of menus
if (is_admin()) {
return $items;
}


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

if ("product_cat" !== $i->object) {
continue;
}


$term_children = get_term_children($i->object_id, "product_cat");


// add child categories

foreach ($term_children as $index2 => $child_id) {

$child = get_term($child_id);

if( $child->count == 0 ) continue;

$url = get_term_link($child);


$e = new \stdClass();

$e->title = $child->name;
$e->url = $url;
$e->menu_order = 500 * ($index + 1) + $index2;
$e->post_type = "nav_menu_item";
$e->post_status = "published";
$e->post_parent = $i->ID;
$e->menu_item_parent = $i->ID;
$e->type = "custom";
$e->object = "custom";
$e->description = "";
$e->object_id = 0;
$e->db_id = 0;
$e->ID = 0;
$e->classes = array();

$items[] = $e;

}


}


return $items;

}, 10, 3);


please see this line

if( $menu->term_id != 18 ) return ;

change that '18' with id of your menu


Jens Filipsson comments:

Seems to work, but if I change it to another ID (that does not exist though) the menu disappears altogether.


Jens Filipsson comments:

Yeah, same thing when I'm creating a new menu and use that ID, then my main menu disappears. Maybe because we interrupt the filter?


Arnav Joy comments:

please change this line
if( $menu->term_id != 18 ) return ;
to
if( $menu->term_id != 18 ) return $items ;


Jens Filipsson comments:

That did the trick


Jens Filipsson comments:

So now only the 1st point left :)


Jens Filipsson comments:

Any ideas on point number 1 possibly?


Arnav Joy comments:

I tried but its not easy and fast to work on this point.
I will have to work directly on your site and it will need some more cost .
please mail me : [email protected] so we can discuss it further.


Jens Filipsson comments:

No thanks, I'll wait and see if someone else solves it