Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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

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).'"' : '';

                $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";
        }
    }
}
share|improve this question
1  
It's not clear to me what you're looking to accomplish. Can you elaborate on this, "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.", perhaps with a few examples? –  Matthew Boynes Nov 4 '13 at 16:13
    
Have you seen this question: wordpress.stackexchange.com/questions/2802/…? –  ialocin Nov 4 '13 at 16:34
    
in this answer I give a solution for almost exactly what you want. However don't use walker and I show: (1 all the parent items + (2 all the ancestors of the current page + (3 sibligs of the current page + (4 direct children of the current page. –  G. M. Nov 4 '13 at 16:44
    
@ialocin, the code snippet I provide would answer that question. To use that example, I'm looking to add "About Us" to my output. –  mrwweb Nov 4 '13 at 17:53
    
I wonder if you get your top level parent if you skip this check: if ($item->menu_item_parent != $parent_item_id ) { ? –  birgire Nov 4 '13 at 18:07

1 Answer 1

up vote 1 down vote accepted
+100

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.

share|improve this answer
    
This worked like a charm. Thanks, @birgire! –  mrwweb Nov 6 '13 at 19:37
    
Happy to hear it's working for you, cheers –  birgire Nov 7 '13 at 8:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.