Adding menu items dynamically using wp_nav_menu_objects

On my primary navigation, I want each top level page to have a list of the subpages. So I created code that dynamically adds menu items to the primary navigation. This works only on the first level of subpages. You can see that I commented out the code that goes down to the second level because it output those links on the main level. I don’t know why it does not work on the second level. Could it be that we cannot assign a menu item to a dynamically generated parent menu item?

It looks like:

add_filter( 'wp_nav_menu_objects', 'epc_wp_nav_menu_items', 10, 2 );
function epc_wp_nav_menu_items($items, $args) {
    if ($args->theme_location == 'primary') {
        $menu_order = 10000;
        $menu_order2 = 20000;
        global $wpdb;
        global $post;
        $post_id = 0;       
        if($post){
            $post_id = $post->ID;
        }

        foreach($items as $item){
            $pageChildren = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$item->object_id." AND post_status="publish" AND post_type="page" ORDER BY menu_order", 'OBJECT' );
            foreach($pageChildren as $child){
                $menu_order++;
                $new_item = epc_add_menu_item($post_id, $menu_order, $item, $child);
                $items[] = (object)$new_item;
                /*
                $pageChildrenSecondLevel = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$child->ID." AND post_status="publish" AND post_type="page" ORDER BY menu_order", 'OBJECT' );
                foreach($pageChildrenSecondLevel as $child2){
                    $menu_order2++;
                    $new_item2 = epc_add_menu_item($post_id, $menu_order2, $new_item, $child2);
                    $items[] = (object)$new_item2;
                }
                */
            }
        }
    }
    return $items;
}

function epc_add_menu_item($post_id, $menu_order, $item, $child){
                $new_item = new stdClass;
                $new_item->ID = $menu_order;
                $new_item->menu_item_parent = $item->ID;
                $new_item->url = get_permalink( $child->ID );
                $new_item->title = $child->post_title;
                $new_item->menu_order = $menu_order;
                $new_item->object_id = $child->ID;
                $new_item->post_parent = $item->object_id;
                $classes="menu-item";
                $classes .= ' menu-item-parent-' . $item->ID;
                $classes .= ' menu-item-type-post_type';
                $classes .= ' menu-item-object-page';
                if($post_id == $child->ID){
                    $classes .= ' current-menu-item';
                    $classes .= ' page-item';
                    $classes .= ' page-item-' . $child->ID ;
                    $classes .= ' current_page_item';
                }   
                $new_item->classes = $classes;
                return $new_item;
}

3 Answers
3

You should also specify db_id field for the parent menu item:

function epc_add_menu_item( $post_id, $menu_order, $item, $child ) {
    ...
    $new_item->db_id = $menu_order;
    ...
}

On a side note, menu item that has children should also have menu-item-has-children class.

Leave a Comment