1

I've got a situation where I need to limit the top level menu items on a custom menu. The design only has room for 4 fixed width items, and I want to future proof it from displaying more.

Looking at Is there a way to limit the number of top level items in a custom menu?, the answer referred to using wp_nav_menu_items.

Unfortunately, looking through the wordpress.org forums and various blog posts, I can only examples that add items, and nothing that removes them.

When I echo out $items, I only receive a list of each menu item in it's full html. I'm not good enough with regex to figure out how to set a limit to stop after 4 items (and am not sure if that's actually possible with regex anyway).

I have also tried just using css to hide all remaining items through overflow:hidden, but that also hides the dropdowns, so that isn't an option either.

Is there any way I can limit top level items through my custom wp_nav_menu?

2 Answers 2

1

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.

3

Based off the response from Charles I was able to complete the code to limit top menu items. It creates a counter of top level menu items and then unsets them after 4. Then, it stores that ID so it can remove any further items that have that item as a parent.

/**
 * Limit number of nav menu items on primary menu
 */
function my_nav_menu_objects( $sorted_menu_items, $args ) {
    if ( $args->theme_location != 'primary' )
        return $sorted_menu_items;
    $unset_top_level_menu_item_ids = array();
    $array_unset_value = 1;
    $count = 1;

    foreach ( $sorted_menu_items as $sorted_menu_item ) {

        // unset top level menu items if over count 4
        if ( 0 == $sorted_menu_item->menu_item_parent ) {
            if ( $count > 4 ) {
                unset( $sorted_menu_items[$array_unset_value] );
                $unset_top_level_menu_item_ids[] = $sorted_menu_item->ID;
            }
            $count++;
        }

        // unset child menu items of unset top level menu items
        if ( in_array( $sorted_menu_item->menu_item_parent, $unset_top_level_menu_item_ids ) )
            unset( $sorted_menu_items[$array_unset_value] );

        $array_unset_value++;
    }

    return $sorted_menu_items;
}
add_filter( 'wp_nav_menu_objects', 'my_nav_menu_objects', 10, 2 );
1
  • Looking at this code, I probably don't really need to check if child pages are in an array, but remove every item after the limit has been set. Aug 12, 2013 at 19:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.