WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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(
        ( $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";
share|improve this question

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 when 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;

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

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

share|improve this answer
This is the most elegant solution presented in this thread. Thanks Lane! – Kevin C. May 31 '13 at 22:05
Indeed a very clean approach that works well. Many thanks. – Isaac Gregson Jun 1 '15 at 17:08

I had a similar problem and solved it by using a static variable inside the class:

static protected $menu_lvl; 

And then in the "display_element" I incremented the variable:


In my code I then referenced in the start_lvl function something like this:

$output .= "<ul id='level". self::$menu_lvl ."'>";

This doesn't use the page ID, but it does use a unique ID for UL statements that can be referenced by the javascript.

BTW - This is really just useful for nested accordions, or clickable nested dropdowns in the Roots Theme using Bootstrap for mobile apps.

share|improve this answer

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.

share|improve this answer
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! – Robert Bouten Sep 17 '12 at 20:09

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);
            $indent = '';

        extract($args, EXTR_SKIP);

        $output .= $indent . 
            <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.

share|improve this answer
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. – Robert Bouten Aug 16 '12 at 20:38
What are you trying to do with start_lvl? – AlxVallejo Aug 16 '12 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. – Robert Bouten Aug 16 '12 at 20:50
Adding the id="collapse" works, but I can't get it to work to add the pageID as well. – Robert Bouten Aug 16 '12 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 Aug 16 '12 at 20:54

Your Answer


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.