0

I want to display only a given level of menu items in my main nav menu when on that page. Currently sub menus of my main menu are part of the main menu HTML being an unordered list within the nav link list.

<ul id="menu-main-top-navigation">
    <li class="menu nav-1">
        ...
        <ul>
            <li class="menu sub-nav-1"></li>
            <li class="menu sub-nav-2"></li>
        </ul>
    </li>
    <li class="menu nav-2">...</li>
    <li class="menu nav-3">...</li>
</ul>

When on the page of menu nav-1, I want something like

<ul id="menu-main-sub-navigation">
    <li class="menu sub-nav-1">...</li>
    <li class="menu sub-nav-2">...</li>
</ul>

Currently I have written a hacky piece of code which displays only the second level navigation for a given menu item when that page is open. However it doesn't work for any given level.

I think a custom walker is the way to go but I cannot seem to get it to work...

EDIT:

Here is my hacky code which currently only works to display the second level sub navigation when on that page;

function submenu_display( $items, $args ) {

    $current_page_id = (string)get_the_ID();
    $top_level       = array();
    $second_level    = array();

    foreach ( $items as $item ) {
        // The parent menu ID is different to the object (post) ID
        if ( $item->object_id === $current_page_id ) {
            $current_parent_id = $item->ID;
        }
        if ( $item->menu_item_parent === '0' ) {
            $top_level[ $item->ID ] = $item->object_id;
        }
        if ( array_key_exists( $item->menu_item_parent, $top_level ) ) {
            $second_level[ $item->ID ] = $item->object_id;
        }
    }

    if ( isset( $current_parent_id ) ) {
        if ( array_key_exists( $current_parent_id, $second_level ) ) {
            foreach ( $items as $item => $details ) {
                if ( $current_parent_id === $details->ID ) {
                    $current_parent_id = $details->menu_item_parent;
                }
            }
        }
        if ( array_key_exists( $current_parent_id, $top_level ) ) {
            foreach ( $items as $item => $details ) {
                if ( $details->menu_item_parent != $current_parent_id ) {
                    unset( $items[ $item ] );
                }
            }
        }
    } else {
        $items = array();
    }

    return $items;
}

And used via

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

wp_nav_menu( array( 'theme_location' => 'primary_navigation',
            'menu_class'     => 'nav nav-sub',
            'menu_id'        => 'menu-main-sub-navigation'
) );

remove_filter( 'wp_nav_menu_objects', 'submenu_display', 10 );
2
  • Have you written any of that custom walker yet? Is so, post it please.
    – s_ha_dum
    Jun 8, 2015 at 17:18
  • @s_ha_dum - I couldn't get the walker to work in any meaningful way, just the code I have edited in above.
    – myol
    Jun 9, 2015 at 8:41

2 Answers 2

2

You need to extend Walker_Nav_Menu in such a way that it only outputs, if I understand you, items that are not "zero" depth-- top level.

class my_extended_walker extends Walker_Nav_Menu {
  function start_lvl(&$output, $depth, $args ) {
    if (0 !== $depth) {
      parent::start_lvl($output, $depth, $args);
    }
  }

  function end_lvl(&$output, $depth, $args) {
    if (0 !== $depth) {
      parent::end_lvl($output, $depth, $args);
    }
  }

  function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    if (0 !== $depth) {
      parent::start_el($output, $item, $depth, $args, $id);
    }
  }

  function end_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    if (0 !== $depth) {
      parent::end_el($output, $item, $depth, $args, $id);
    }
  }
}
// testing
wp_nav_menu( 
  array( 
    'walker'=>new my_extended_walker(),
    'menu' => 'mymenu'
  ) 
);
1
  • Thankyou, this is much cleaner. I will have to test this later. If I am on the page of a top level item, will this show only its children or all children of all top level pages? I am after the former functionality.
    – myol
    Jun 9, 2015 at 14:58
0

Maybe you can use wp_get_nav_menu_items() to get the items and then check if an item has a parent.

<?php
$items = wp_get_nav_menu_items( 'header' );
if( $items ) {
    echo '<ul id="menu-main-top-navigation">';
    foreach( $items as $index => $item ) {
        if( $item->menu_item_parent != 0 ) 
            echo '<li class="menu"><a href="' . get_permalink( $item->ID ) . '">' . $item->post_title . '</a></li>';
    }
    echo '</ul>';
}
?>

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.