3

I'm trying to wrap the first sub-menu of a navigation into a seperate div. None of the children or sub-levels should get the same treatment.

I'm really new to the Nav Walker-thingie and I'm really struggling and could need some help 😜

This is the structure I'm trying to achieve:

<ul class="menu">
    <li class="menu-item">
        <a href="#">Menu Item</a>
        <!-- wrapper-class around the first sub-menu -->
        <div class="sub-menu__wrapper">
            <ul class="sub-menu">
                <li class="menu-item">
                    <a href="#">Menu Item</a>
                    <!-- NO wrapper-class around following levels -->
                    <ul class="sub-menu">
                        <li>...</li>
                    </ul>
                </li>
            </ul>
        </div>
    </li>
</ul>

I thought it would be easy to do with a simple if-statement that only prints the sub-menu__wrapper on the first level, but somehow the following HTML-output gets mixed up pretty bad.

Here's my Walker-class:

class sublevel_wrapper extends Walker_Nav_Menu {
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        if ($depth == 0) {
            $output .= "<div class='sub-menu__wrapper'><ul class='sub-menu'>\n";
        }
        //$output .= "<ul class='sub-menu'>\n";
    }
    function end_lvl( &$output, $depth = 0, $args = array() ) {
        if ($depth == 0) {
            $output .= "</ul></div>\n";
        }
        //$output .= "</ul>\n";
    }
}

Which prints the following structure:

<ul class="menu">
    <li class="menu-item">
        <a href="#">Menu Item</a>
        <!-- wrapper-class around the first sub-menu -->
        <div class="sub-menu__wrapper">
            <ul class="sub-menu">
                <li class="menu-item">Parent Menu Item</li>
                <!-- the following items are supposed to be nested in the "parent menu item" before -->
                <li class="menu-item">Child Menu Item</li>
                <li class="menu-item">Child Menu Item</li>
                <li class="menu-item">Child Menu Item</li>
                <li class="menu-item">Parent Menu Item</li>
                <!-- again the following items are supposed to be nested in the "parent menu item" before -->
                <li class="menu-item">Child Menu Item</li>
                <li class="menu-item">Child Menu Item</li>
                <li class="menu-item">Child Menu Item</li>
                ...
            </ul>
        </div>
    </li>
</ul>

As you can see in the comments I tried to alter the output, if the if-statement is false, but that messes up the output even more 😂

Any help, constructive criticism or nudge in the right direction is much appreciated 🙇

2 Answers 2

6

To be honest, I don't really know why my solution works, but it does 😂

I based my snippet on this solution and tweaked the output to my needs: Custom nav walker with different output depending on depth

class sublevel_wrapper extends Walker_Nav_Menu {
    // add classes to ul sub-menus
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        // 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(
            'sub-menu',
            'menu-depth-' . $display_depth
        );
        $class_names = implode( ' ', $classes );

        // build html
        if ($display_depth == 1) {
            $output .= "\n" . $indent . '<div class="sub-menu__wrapper"><ul class="' . $class_names . '">' . "\n";
        } else {
            $output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
        }
    }
}

Compared to my first snippet he leaves out the end_lvl-function completely and for whatever reason it worked. I also liked how he adds the $display_depth-variable.

1
  • Hmm, I think it will output the wrapper twice if you have two top parents on the same level. Commented Sep 28, 2019 at 0:05
1
function sevenMenu(  ) {
$menu_name = 'primary'; // specify custom menu slug
$menu_list ='';
if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name])) {
    $menu = wp_get_nav_menu_object($locations[$menu_name]);
    $menu_items = wp_get_nav_menu_items($menu->term_id);

    foreach( $menu_items as $menu_item ) {
        if( $menu_item->menu_item_parent == 0 ) {

            $parent = $menu_item->ID;

            $menu_array = array();
            foreach( $menu_items as $submenu ) {
                if( $submenu->menu_item_parent == $parent ) {
                    $bool = true;
                    $menu_array[] = '<li><a href="' . $submenu->url . '">' . $submenu->title . '</a></li> ' ."\n";
                }
            }
            if( $bool == true && count( $menu_array ) > 0 ) {
                $menu_list .= '<li role="presentation" class="dropdown">' ."\n";
                $menu_list .= '<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">' . $menu_item->title . ' <span class="caret"></span></a>' ."\n";

                $menu_list .= '<ul class="dropdown-menu">' ."\n";
                $menu_list .= implode( "\n", $menu_array );
                $menu_list .= '</ul>' ."\n";

            } else {

                $menu_list .= '<li>' ."\n";
                $menu_list .= '<a href="' . $menu_item->url . '">' . $menu_item->title . '</a>' ."\n";
                $menu_list .= '<li>' ."\n";
            }

        }

        // end <li>

    }

} else {
    $menu_list = '<!-- no menu defined in location "'.$theme_location.'" -->';
}

echo $menu_list;}

Check Out This bootstrap menu , you can add this at your function.php change your menu_name , and call this menu into your template by :

<?php if (function_exists(sevenMenu())) sevenMenu(); ?>
3
  • Hmm... I suppose this could work, but somehow it cuts off everything below level 2, so for now I'm missing the second sub-menu. Sorry, could you give me a hint, where in the function the depth of the navigation is defined? Commented Nov 3, 2016 at 11:17
  • I think inside this if( $bool == true && count( $menu_array ) > 0 ) { Commented Nov 3, 2016 at 13:42
  • maybe you can use this Git link . It will help you to select the menu depth Vote if you find my answer helpful . Danke Commented Nov 3, 2016 at 13:53

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.