I'm using a custom nav walker to render out the main menu, during this I want to store the second level navigation items to use/ render out later in a separate area of the page.
I want these second level navigation items to display block, if you're currently in that section (i.e. if you're on 'services' or a subpage of 'services' then the submenu will display block). Also, if I hover over "services" I want the submenu to show.
Currently I've done the submenu in a separate custom nav walker - but the navigation only displays when you're in the section, not when you hover over the main menu item. Also, with how I currently have it setup it shows the menu background/ styles on pages that don't have submenus
This is my existing nav walker for the submenu only:
class MainSubmenuCustomWalker extends \Walker_Nav_Menu
{
function start_lvl(&$output, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::start_lvl($output, $depth, $args);
}
function end_lvl(&$output, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::end_lvl($output, $depth,$args);
}
// Don't print top-level elements
public function start_el(&$output, $item, $depth=0, $args=array(), $id=0)
{
if ($depth == 0) {
return;
}
parent::start_el($output, $item, $depth, $args);
}
function end_el(&$output, $item, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::end_el($output, $item, $depth, $args);
}
function display_element($element, &$children_elements, $max_depth, $depth, $args, &$output)
{
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
$current_class = array_intersect( $current_element_markers, $element->classes );
$ancestor_of_current = !empty($current_class);
if (0 == $depth && !$ancestor_of_current) {
return;
}
$id = $element->ID;
if (($max_depth == 0 || $max_depth > $depth+1) && isset($children_elements[$id])) {
foreach ($children_elements[$id] as $child) {
if (!isset($newlevel)) {
$newlevel = true;
//start the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array($this, 'start_lvl'), $cb_args);
}
parent::display_element($child, $children_elements, $max_depth, $depth + 1, $args, $output);
}
unset($children_elements[$id]);
}
if (isset($newlevel) && $newlevel) {
//end the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
}
}
}
It is being called from here, which renders the menu container even if there are no submenu items :(
<div class="main-submenu-navbar navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#main-submenu-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<?php Menu::submenus(); ?>
I'm using a custom nav walker to render out the main menu, during this I want to store the second level navigation items to use/ render out later in a separate area of the page.
I want these second level navigation items to display block, if you're currently in that section (i.e. if you're on 'services' or a subpage of 'services' then the submenu will display block). Also, if I hover over "services" I want the submenu to show.
Currently I've done the submenu in a separate custom nav walker - but the navigation only displays when you're in the section, not when you hover over the main menu item. Also, with how I currently have it setup it shows the menu background/ styles on pages that don't have submenus
This is my existing nav walker for the submenu only:
class MainSubmenuCustomWalker extends \Walker_Nav_Menu
{
function start_lvl(&$output, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::start_lvl($output, $depth, $args);
}
function end_lvl(&$output, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::end_lvl($output, $depth,$args);
}
// Don't print top-level elements
public function start_el(&$output, $item, $depth=0, $args=array(), $id=0)
{
if ($depth == 0) {
return;
}
parent::start_el($output, $item, $depth, $args);
}
function end_el(&$output, $item, $depth=0, $args=array())
{
if ($depth == 0) {
return;
}
parent::end_el($output, $item, $depth, $args);
}
function display_element($element, &$children_elements, $max_depth, $depth, $args, &$output)
{
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
$current_class = array_intersect( $current_element_markers, $element->classes );
$ancestor_of_current = !empty($current_class);
if (0 == $depth && !$ancestor_of_current) {
return;
}
$id = $element->ID;
if (($max_depth == 0 || $max_depth > $depth+1) && isset($children_elements[$id])) {
foreach ($children_elements[$id] as $child) {
if (!isset($newlevel)) {
$newlevel = true;
//start the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array($this, 'start_lvl'), $cb_args);
}
parent::display_element($child, $children_elements, $max_depth, $depth + 1, $args, $output);
}
unset($children_elements[$id]);
}
if (isset($newlevel) && $newlevel) {
//end the child delimiter
$cb_args = array_merge(array(&$output, $depth), $args);
call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
}
}
}
It is being called from here, which renders the menu container even if there are no submenu items :(
<div class="main-submenu-navbar navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button"
class="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#main-submenu-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<?php Menu::submenus(); ?>
Share Improve this question edited Jan 23, 2015 at 5:39 fuxia♦ 107k39 gold badges255 silver badges459 bronze badges asked Jan 23, 2015 at 3:13 emilyemily 1513 bronze badges
1 Answer
Reset to default 0Yesterday I had the same kind of problem and I decided to ditch the walker
alltogether and use the wp_get_nav_menu_object
and wp_get_nav_menu_items
functions instead.
If you var_dump($menu_items)
you can see which properties are available.
Here's a snippet of my code that builds the menu named 'main' for my twitter bootstrap menu:
$menu_name = 'main'; // name of your menu
$menu = wp_get_nav_menu_object($menu_name);
$menu_items = wp_get_nav_menu_items($menu->term_id);
$tmpWPMenu = ""; // string variable where the menu is stored
// collect the menu-items (if any) and store them temporarily in
// the $tmpChildren array with the $key = id of parent
$tmpChildren = array();
foreach ( (array) $menu_items as $key => $menu_item ) {
if (intval($menu_item->menu_item_parent) > 0) {
$tmpChildren[$menu_item->menu_item_parent][] = $menu_item;
}
}
// Now loop again and build it,
// when a matching ID is encountered in the $tmpChildren array, build the submenu:
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
if (intval($menu_item->menu_item_parent) == 0) {
// Does $tmpChildren contain a $key that is the id of this menu-item?
if (array_key_exists($menu_item->ID, $tmpChildren)) {
$tmpWPMenu .= '<li class="dropdown">';
$tmpWPMenu .= ' <a href="#" class="dropdown-toggle" data-toggle="dropdown"></i> '.$title.' <b class="caret"></b></a>';
$tmpWPMenu .= ' <ul class="dropdown-menu">';
foreach ($tmpChildren[$menu_item->ID] as $subMenuItem) {
$tmpWPMenu .= '<li><a href="/ik/"><!--<i class="glyphicon glyphicon-user"></i>--> ' . $subMenuItem->title . '</a></li>';
}
$tmpWPMenu .= ' </ul>';
$tmpWPMenu .= '</li>';
} else {
$tmpWPMenu .= '<li>';
$tmpWPMenu .= '<a href="#"></i> '.$title.' </a>';
$tmpWPMenu .= '</li>';
}
}
}
// Do something with the $tmpWPMenu, in my case I pass it
// to the Smarty template engine that I use
$tmpNavBarFindAndReplace['wp_menu'] = $tmpWPMenu;
print $gBSOManager->pPageO->mRender($tmpNavBarFindAndReplace, 'mijn/navbar.html',true);
I hope this might help (or provide insight) :) Cheers, T