Limit top level menu items on wp_nav_menu

A few lines before that filter is this line:

$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );

That filter passes the top level menu item objects before walk_nav_menu_tree() is called.

Here is some test code:

add_filter( 'wp_nav_menu_objects', 'my_nav_menu_objects', 10, 2 );

function my_nav_menu_objects( $sorted_menu_items, $args ) {
    wp_die( '<pre>' . var_export( $sorted_menu_items, true ) . '</pre>' );
}

It was tested on a 3 item menu. Two top level items and 1 sub menu.

The page tested had only 1 menu on the page. You may have to test the values in $args to find the correct menu on your page.

As expected, $sorted_menu_items returned 3 menu_item objects. The top level menu objects have the 'menu_item_parent' property set to 0.

'menu_item_parent' => '0',

You can use this to find the number of top level menu items.

add_filter( 'wp_nav_menu_objects', 'my_nav_menu_objects', 10, 2 );

function my_nav_menu_objects( $sorted_menu_items, $args ) {

    $top_level_menu_item_ids = array();

    foreach ( $sorted_menu_items as $sorted_menu_item ) {
        if ( 0 == $sorted_menu_item->menu_item_parent )
            $top_level_menu_item_ids[] = $sorted_menu_item->ID;
    }

    wp_die( '<pre>' . var_export( count( $top_level_menu_item_ids ), true ) . '</pre>' );
}

That code should break the page and display the number of top level menu items.

I didn’t write the code needed to limit the number of items, but remember that if you remove (unset) a menu item parent, you will also have to remove all of its children.

Here is another test:

function my_nav_menu_objects( $sorted_menu_items, $args ) {

    // Remove a menu item parent, but leave it's child menu item in place.
    unset( $sorted_menu_items[2] );

    return $sorted_menu_items;
}

The result was that the child menu looked like a top level menu on the page.