I’ve used the menu walker below to display dynamic submenus with great effect in the past.
It displays 2nd- or lower-level menu items IF the current page is a parent, sibling, or descendant of the page.
For example if the menu hierarchy is:
- a
- b
- 1
- i
- ii
- 1
It will show, 1, i, and ii if on pages B, 1, i, or ii. What I want to do is add the parent item (B in the example) to that so that the top-level parent also appears.
I’ve read up on walkers, tried to make sense of this code, but am still stuck even on where to begin.
// Show only the child pages of a menu
class child_menu_walker extends Walker_Nav_Menu {
var $found_parents = array();
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
if( $wp_query->is_single && !in_array( get_option('page_for_posts'), $this->found_parents ) ) {
$this->found_parents[] = get_option('page_for_posts');
}
//this only works for second level sub navigations
$parent_item_id = 0;
$indent = ($depth) ? str_repeat("t", $depth) : '';
$class_names = '';
$classes = empty($item->classes) ? array() : (array) $item->classes;
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item));
$class_names = ' class="'.esc_attr($class_names).'"';
#current_page_item
// Checks if the current element is in the current selection
if(
strpos($class_names, 'current-menu-item') ||
strpos($class_names, 'current-menu-parent') ||
strpos($class_names, 'current-menu-ancestor') ||
( is_array($this->found_parents) &&
in_array($item->menu_item_parent, $this->found_parents) )
) {
// Keep track of all selected parents
$this->found_parents[] = $item->ID;
//check if the item_parent matches the current item_parent
$item_output = '';
if ($item->menu_item_parent != $parent_item_id ) {
$output .= $indent.'<li'.$class_names.'>';
$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).'"' : '';
$attributes .= !empty($item->url) ? ' href="'.esc_attr($item->url).'" rel="nofollow noreferrer noopener"' : '';
$item_output = $args->before;
$item_output .= '<a'.$attributes.'>';
$item_output .= $args->link_before.apply_filters('the_title', $item->title, $item->ID).$args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
}
$output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
}
}
function end_el(&$output, $item, $depth) {
$parent_item_id = 0;
$class_names = '';
$classes = empty($item->classes) ? array() : (array) $item->classes;
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item));
$class_names = ' class="'.esc_attr($class_names).'"';
if(
strpos($class_names, 'current-menu-item') ||
strpos($class_names, 'current-menu-parent') ||
strpos($class_names, 'current-menu-ancestor') ||
(is_array($this->found_parents) &&
in_array($item->menu_item_parent, $this->found_parents))
) {
// Closes only the opened li
if (is_array($this->found_parents) && in_array($item->ID, $this->found_parents) && $item->menu_item_parent != $parent_item_id) {
$output .= "</li>n";
}
}
}
function end_lvl(&$output, $depth) {
$indent = str_repeat("t", $depth);
// If the sub-menu is empty, strip the opening tag, else closes it
if (substr($output, -22) == "<ul class="sub-menu">n") {
$output = substr($output, 0, strlen($output) - 23);
} else {
$output .= "$indent</ul>n";
}
}
}
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
You can try to skip the following if-condition in the start_el() method in your child_menu_walker class:
if ($item->menu_item_parent != $parent_item_id ) {
//...
}
which is equal to:
if ($item->menu_item_parent != 0 ) {
//...
}
since you have $parent_item_id = 0.
So it looks like this condition is filtering out your top-level parent.
You might also want to reconsider this condition:
&& $item->menu_item_parent != $parent_item_id
in the end_el() method.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0