I'm using wp_nav_menu for a submenu that I only want to display (including the surrounding html) when there are sub-menu items to display.

The problem is, the function is always returning with either the menu items (when it's supposed to), or with an empty list when there's nothing to display. I need it to (and thought it would) return false.

Here's my code.

// Capture submenu as a variable
$args = array( 
            'theme_location' => $in_menu,
            'echo'           => '0',
            'sub_menu'       => true,
            'fallback_cb'    => 'coepio_return_false'
    ); // Note I've also tried 'fallback_cb' => false with the same result
$submenu = wp_nav_menu( $args );

// If the menu exists
if( $submenu ) {
    <div id="submenu" class="sidebar cf" role="navigation">

        <div class="widget">
            <div id="submenu-title" class="widget-title">
                <h4>In This Section</h4>
            <div class="widget-content">
                echo $submenu;

    </div><!-- #submenu -->

If you noticed that 'sub_menu' => true argument you have a good eye. Here's the code for that.

// Submenus - required for the submenu (above) to work
// filter_hook function to react on sub_menu flag
function coepio_submenu( $sorted_menu_items, $args ) {
  if ( isset( $args->sub_menu ) ) {
    $root_id = 0;

    // find the current menu item
    foreach ( $sorted_menu_items as $menu_item ) {
      if ( $menu_item->current ) {
        // set the root id based on whether the current menu item has a parent or not
        $root_id = ( $menu_item->menu_item_parent ) ? $menu_item->menu_item_parent : $menu_item->ID;

    $menu_item_parents = array();
    foreach ( $sorted_menu_items as $key => $item ) {
      // init menu_item_parents
      if ( $item->ID == $root_id ) $menu_item_parents[] = $item->ID;

      if ( in_array( $item->menu_item_parent, $menu_item_parents ) ) {
        // part of sub-tree: keep!
        $menu_item_parents[] = $item->ID;
      } else {
        // not part of sub-tree: away with it!
        unset( $sorted_menu_items[$key] );

    return $sorted_menu_items;
  } else {
    return $sorted_menu_items;
add_filter( 'wp_nav_menu_objects', 'coepio_submenu', 10, 2 );

2 Answers 2


it doesn't return false because the menu exists in every case, you're just unsetting all of the menu items. you're not setting an items_wrap arg, so that defaults to the ul wrapper. maybe try removing it by setting it explicitly to just the child items:

'items_wrap' => '%3$s'

note, you'll then have to manually wrap your menu in ul tags in that case.

  • Thanks, I managed to get it working by doing that, plus setting 'container' => falseand then checking for if( $submenu != '' ) Jul 3, 2013 at 8:11

I ran into this problem and my bug was with some other code I had written erroneously. I had the following code manipulating the $query:

function qd_post_queries( $query ) {
add_action( 'pre_get_posts', 'qd_post_queries' );

This resulted in hijacking EVERY query on the taxonomy page, including calls for navigation. I needed to add is_main_query() to the if to resolve the problem:

if(is_tax('qd_locations') && $query->is_main_query())
  • I just wanted to add this here because I landed here when trying to solve this problem and wanted to help the next fool that makes the same mistake 😊
    – Eric K
    Jun 1, 2017 at 16:46

Your Answer

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

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