WordPress Nav Walker – Multilevel navigation

I need help with navigation in WordPress site. I’m trying to get WordPress print my navigation in this format:

Read More
<ul data-menu="main" class="menu__level">
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-1" href="#">Vegetables</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-2" href="#">Fruits</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-3" href="#">Grains</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-4" href="#">Mylk & Drinks</a></li>
      </ul>
      
<!-- Submenu 1 / Shown when user clicks the first list item (item with data-submenu="submenu-1") on data-menu="main" -->
      <ul data-menu="submenu-1" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="#">Stalk Vegetables</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Roots & Seeds</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Cabbages</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Salad Greens</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Mushrooms</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-1-1" href="#">Sale %</a></li>
      </ul>
      
<!-- Submenu 2 / Shown when user clicks the second list item (item with data-submenu="submenu-2") on data-menu="main" -->
      <ul data-menu="submenu-2" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="#">Citrus Fruits</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Berries</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-2-1" href="#">Special Selection</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Tropical Fruits</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Melons</a></li>
      </ul>
      
<!-- Submenu 3 / Shown when user clicks the third list item (item with data-submenu="submenu-3") on data-menu="main" -->
      <ul data-menu="submenu-3" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="#">Buckwheat</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Millet</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Quinoa</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Wild Rice</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Durum Wheat</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-3-1" href="#">Promo Packs</a></li>
      </ul>
      
<!-- Submenu 4 / Shown when user clicks the forth list item (item with data-submenu="submenu-4") on data-menu="main" -->
      <ul data-menu="submenu-4" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="#">Grain Mylks</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Seed Mylks</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Nut Mylks</a></li>
        <li class="menu__item"><a class="menu__link" href="#">Nutri Drinks</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-4-1" href="#">Selection</a></li>
      </ul>

But I can’t figure out how to specify child items to specific parent item and then printing them with data-submenu.

Navigation structure is taken from here:
http://tympanus.net/Blueprints/MultiLevelMenu/

Thanks!

Update: This crossed my mind: would it be easier or cleaner to just get navigation data with php and then populate it in right format with Javascript? Does anyone know if this would be better way to handle this?

Or how about using rest-api with this (I’m fairly new with this, so is there point to use it as a part of in small website project)

Related posts

2 comments

  1. Actually, you can just grab all menu data (from certain location) into the array & output it any way you like.

    For example, you have menu structure like this:

    Menu_parent1_item
        Submenu_item_1
        Submenu_item_2
        Submenu_item_3
    Menu_parent2_item
        Submenu2_item_1
        Submenu2_item_2
        Submenu2_item_3
    Menu_parent3_item
        Submenu3_item_1
        Submenu3_item_2
        Submenu3_item_3
    

    Put this code inside function.php:

    function custom_menu_output( $theme_location ) {
        if ( ($theme_location) && ($locations = get_nav_menu_locations()) && isset($locations[$theme_location]) ) {
            $menu = get_term( $locations[$theme_location], 'nav_menu' );
            $menu_items = wp_get_nav_menu_items($menu->term_id);
    
            $menus = array();
    
            foreach( $menu_items as $menu_item ) {
                $pid = $menu_item->menu_item_parent ? $menu_item->menu_item_parent : 0;
    
                $menus[$pid][] = array(
                    'link' => $menu_item->url,
                    'title' => $menu_item->title,
                    'id' => $menu_item->ID,
                );
            }
    
            foreach($menus as $key => $menu) {
                if($key == 0)
                    echo '<ul data-menu="main" class="menu__level">';
                else
                    echo '<ul data-menu="submenu-'.$key.'" class="menu__level">';
                foreach($menu as $item) {
                    if(isset($menus[$item['id']]))
                        echo '<li class="menu__item"><a class="menu__link" data-submenu="submenu-'.$item['id'].'" href="'.$item['link'].'">'.$item['title'].'</a></li>';
                    else
                        echo '<li class="menu__item"><a class="menu__link" href="'.$item['link'].'">'.$item['title'].'</a></li>';
                }
                echo '</ul>';
            }
    
        } else {
            $menu_list = '<!-- no menu defined in location "'.$theme_location.'" -->';
        }
        echo $menu_list;
    }
    

    And use it like this in your template:

    <?php custom_menu_output('menu_location_name_from_register_nav_menu'); ?>
    

    It will generate HTML like this (I’ve based it on your question description):

    <ul data-menu="main" class="menu__level">
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-717" href="http://yourdomain.tld/your_link/">Menu_parent1_item</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-720" href="http://yourdomain.tld/your_link/">Menu_parent2_item</a></li>
        <li class="menu__item"><a class="menu__link" data-submenu="submenu-725" href="http://yourdomain.tld/your_link/">Menu_parent3_item</a></li>
    </ul>
    
    <ul data-menu="submenu-717" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu_item_1</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu_item_2</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu_item_3</a></li>
    </ul>
    
    <ul data-menu="submenu-720" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_1</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_2</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_3</a></li>
    </ul>
    
    <ul data-menu="submenu-725" class="menu__level">
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_1</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_2</a></li>
        <li class="menu__item"><a class="menu__link" href="http://yourdomain.tld/your_link/">Submenu2_item_3</a></li>
    </ul>
    

    You can further customize this code for your needs.

  2. You can use walker class to make the changes in ul and li strcuture.

    class themeslug_walker_nav_menu extends Walker_Nav_Menu {
    
    
            private $color_idx = 0;
    
            // add classes to ul sub-menus
            function start_lvl( &$output, $depth) {
                //p($output);
                // depth dependent classes
                $indent = ( $depth > 0  ? str_repeat( "t", $depth ) : '' ); // code indent
                $display_depth = ( $depth + 1); // because it counts the first submenu as 0
                $classes = array(
                    'sidebar-menu',
                    ( $display_depth % 2  ? 'menu-odd' : 'menu-even' ),
                    ( $display_depth >=2 ? 'sub-sub-menu' : '' ),
                    'level-' . $display_depth
                    );
                $class_names = implode( ' ', $classes );
    
                $back_btn = '';
                if($display_depth > 0){
    
                    /*$parent_label = '<li class="top custom-row">
                                        <a class="close-menu" href="#"><span class="parent_label"></span><i class="fa fa-close"></i></a>
                                      </li>';
    
                    $back_btn = '<li class="sidebar-item back no-children back'.$display_depth.'">
                                  <div class="inner">
                                    <a class="hit-area" href="#">Back</a>
                                    <i class="fa fa-chevron-left"></i>
                                  </div>
                                </li>';*/
                }
    
                // build html
                $incri = $this->color_idx-1;
                $output .= "n" . $indent . '<ul class="menu__level" data-menu="submenu-'.$incri.'">' .$parent_label.$back_btn. "n";
            }
    
            // add main/sub classes to li's and links
             function start_el( &$output, $item, $depth, $args ) {
    
    
                global $wp_query;
                $indent = ( $depth > 0 ? str_repeat( "t", $depth ) : '' ); // code indent
    
                // depth dependent classes
                /*$depth_classes = array(
                    'sidebar-item',
                    ( $depth == 0 ? 'li0' : '' ),
                    ( $depth == 1 ? 'li1' : '' ),
                    ( $depth == 2 ? 'li2' : '' ),
                    ( $depth == 3 ? 'li3' : '' ),
                    /*( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
                    'menu-item-depth-' . $depth
                );*/
    
    
    
                if(in_array('menu-item-has-children',$item->classes)){
                    $has_children = 'data-has-children="1"';
                    $has_children_var = 1;
                    $depth_classes[] = 'has-children';
                } else{
                    $has_children_var = 0;
                    $depth_classes[] = 'no-children';
                }
    
    
                $li_attributes = 'data-level="'.$depth.'" data-title="'.apply_filters( 'the_title', $item->title, $item->ID ).'" '.$has_children;
    
    
    
                $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
    
    
    
    
                // passed classes
                $classes = empty( $item->classes ) ? array() : (array) $item->classes;
                $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
    
                // build html
                $output .= $indent . '<li class="menu__item">';
    
                // link attributes
    
                $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
                $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
                $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
                if($has_children_var == 1){
                    $attributes .= ' data-submenu="submenu-'.$this->color_idx.'"';
                } 
                $attributes .= ' class="menu__link"';
    
    
                $item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
                    $args->before,
                    $attributes,
                    $args->link_before,
                    apply_filters( 'the_title', $item->title, $item->ID ),
                    ($has_children_var == 1 ? $args->link_after : ''),
                    $args->after
                );
    
                // build html
                $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    
                if($has_children_var == 1){
                    $this->color_idx++;
                }
            }
    
        }
    

    But it doesn’t provide a method to separate the submenu ul from the parent li.

    Else all the classes like submenu-1, submenu-2 can be managed.

    Try modifying this code.

    For reference see this website Energy & Manpower

    The right side menu when clicked on the menu button on the right side of the page is build in same way

Comments are closed.