21

I am making my first custom walker to build an accordion menu. To start with I used this example: http://bitacre.com/2025/custom-nav-menu-walker-for-wordpress-themes

There are two functions. First start_lvl and then start_el.

In start_el the ID get's implemented by $item->ID. Does anybody know how I can do this in start_lvl as well? I need to give the (surrounding lower level navigation) an ID so I can trigger it to collapse in the accordion menu.

What I'm trying to generate is something like this:

<a href="#collapse2">Titel 2</a>
<ul id="collapse2">Lower Level Menu 2</ul>
<a href="#collapse3">Titel 3</a>
<ul id="collapse3">Lower Level Menu  3</ul>

My code for the start_lvl function:

// add id's and classes to ul sub-menus
function start_lvl( &$output, $depth, $item ) {
    // depth dependent classes
    $indent = ( $depth > 0  ? str_repeat( "\t", $depth ) : '' ); // code indent
    $display_depth = ( $depth + 1); // because it counts the first submenu as 0
    $pgid = ; // How to get ID in here??
    $classes = array(
        'sub-menu',
        ( $display_depth == 1  ? 'accordion-body collapse' : '' ),
        ( $display_depth % 2  ? 'menu-odd' : 'menu-even' ),
        ( $display_depth >=2 ? 'sub-sub-menu' : '' ),
        'menu-depth-' . $display_depth
        );
    $ids = array(
        'collapse' . $pgid
        );
    $class_names = implode( ' ', $classes );
    $id_name = implode( ' ', $ids );

    // build html
    $output .= "\n" . $indent . '<ul id="' . $id_name . '" class="' . $class_names . '">' . "\n";
}

3 Answers 3

52

I just had to do this in one of my themes... Since you don't have access to the $item variable at that stage of the Walker, you would want to store your current item in a more global scope at the moment you do have access to it. The following code will make more sense... note: I've stripped everything but the relevant code.

class ThemeTruck_Nav_Walker extends Walker_Nav_Menu {
   private $curItem;

  // retrieve the curItem
  function start_lvl(&$output, $depth = 0, $args = array()) {
    var_dump($this->curItem );
  }

  // store the curItem
  function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    $this->curItem = $item;
  }

 }
7
  • 5
    This is the most elegant solution presented in this thread. Thanks Lane!
    – Kevin C.
    Commented May 31, 2013 at 22:05
  • 1
    Indeed a very clean approach that works well. Many thanks. Commented Jun 1, 2015 at 17:08
  • 2
    Im not sure but do i have to add the whole default code to start_el to make it work?
    – GDY
    Commented Feb 7, 2017 at 7:27
  • 5
    Ok you can just use parent::start_el($output,$item,$depth,$args,$id); in the start_el ...
    – GDY
    Commented Feb 7, 2017 at 7:37
  • Brilliant, been meaning to figure this out for ages and this worked right away. Thank you.
    – cfx
    Commented Jun 21, 2018 at 1:55
2

You can use the following filter in your start_el function and grub your argument in start_lvl function.

apply_filters( 'walker_nav_menu_start_lvl', $item_output, $item, $depth, $args->myarg=$item->title );

Please let me know know if it works.

2
  • Thanks for posting! I hope to find some time to work it out in the next few days but I am really busy with my study just now. I will get back to you with the result! Commented Sep 17, 2012 at 20:09
  • 1
    Not sure if this filter used to exist, but there's no such filter in WP 5.5 that I can see Commented Oct 28, 2020 at 19:11
-1

You can simply add $page to the argument of the custom walker:

class My_Custom_Walker extends Walker_page {
    function start_el(&$output, $page, $depth, $args, $current_page) {
        if ( $depth )
            $indent = str_repeat("\t", $depth);
        else
            $indent = '';

        extract($args, EXTR_SKIP);

        $output .= $indent . 
            '<li>
            <a style="color:red" href="' . get_page_link($page->ID) . '" title="' . 
            esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . 
            $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';

Try the above and then before you call wp_list_pages(), add the custom walker class:

$MyWalker = new My_Custom_Walker();

Then, in the arguments for wp_list_pages:

wp_list_pages('walker' => $MyWalker)

Check and see if the output of the walker is red.

11
  • That is in function start_el, but it's apparently different in start_lvl because I can't put the same variables in there. Or at least not the same order. Commented Aug 16, 2012 at 20:38
  • What are you trying to do with start_lvl?
    – AlxVallejo
    Commented Aug 16, 2012 at 20:40
  • I am trying to give the <ul> an id="collapse102" with 102 the generated page ID. This way I can trigger it to collapse it in my accordion menu. Commented Aug 16, 2012 at 20:50
  • Adding the id="collapse" works, but I can't get it to work to add the pageID as well. Commented Aug 16, 2012 at 20:51
  • Do you mean that you want only specific IDs to be collapsed? I have an accordion tree for wp_list_pages and I don't need to alter start_lvl at all.
    – AlxVallejo
    Commented Aug 16, 2012 at 20:54

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.