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. 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? Nov 3, 2016 at 11:17
  • I think inside this if( $bool == true && count( $menu_array ) > 0 ) { 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 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.