• I’m working on a WordPress website where I have a menu. In this menu I need a different submenu output based on the url/page id (or any other parameter) of a menu item. If it’s possible, I don’t like to do it on the order of the menu (for example, the second and last menu item).

    The output I’m looking for is:

    <nav class="nav">
        <ul>
            <li>
                <a href="#">Campers<span class="js-trigger-dropdown"><i class="fas fa-sort-down"></i></span></a>
                <div class="dropdown">
                    <ul>
                        <li>
                            <a href="#">
                                <div class="dropdown__image"><img src="assets/images/temp/dropdown-img-1@2x.png" alt=""></div>                                          
                                <div class="dropdown__content">
                                    <h6>Volkswagen T2b</h6>                                         
                                    <p>Rood</p>
                                </div>
                            </a>
                        </li>                   
                    </ul>
                </div>
            </li>
            <li><a href="#">Over evan</a></li>      
            <li><a href="#">Blog</a></li>       
            <li>
                <a href="#">
                    Help<span class="js-trigger-dropdown"><i class="fas fa-sort-down"></i></span>
                </a>
                <div class="dropdown dropdown--secondary">
                    <ul>
                        <li><i class="fas fa-arrow-right"></i><a href="#">Contact</a></li>
                        <li><i class="fas fa-arrow-right"></i><a href="#">Routebeschrijving</a></li>
                        <li><i class="fas fa-arrow-right"></i><a href="#">FAQ</a></li>
                    </ul>
                </div>
            </li>
        </ul>
    </nav>
    

    You can see that the two submenu levels have a slightly different output.

    The Walker class i’m currently working with is:

    class CSS_Menu_Maker_Walker extends Walker {
    
      var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
    
      function start_lvl( &$output, $depth = 0, $args = array(), $top_level_elements = array() ) {
    
        $indent = str_repeat( "\t", $depth );
        if ($args->walker->has_children) {
            $output .= "\n$indent<div class=\"dropdown\"><ul>\n";
        } else {
            $output .= "\n$indent<ul>\n";
        }
    
      }
    
      function end_lvl( &$output, $depth = 0, $args = array() ) {
        $indent = str_repeat("\t", $depth);
    
        if ($args->walker->has_children) {
            $output .= "$indent</div></ul>\n";      
        } else {
            $output .= "$indent</ul>\n";
        }
        
      }
    
      function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    
        global $wp_query;
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
        $class_names = $value = '';        
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    
        /* Add active class */
        if(in_array('current-menu-item', $classes)) {
          $classes[] = 'active';
          unset($classes['current-menu-item']);
        }
    
        /* Check for children */
        $children = get_posts(array('post_type' => 'nav_menu_item', 'nopaging' => true, 'numberposts' => 1, 'meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $item->ID));
        if (!empty($children)) {
          $classes[] = 'has-sub';
        }
    
        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        //$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        $class_names = $class_names ? '' : '';
    
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = $id ? ' id="' . esc_attr( $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;
        if ($args->walker->has_children) {
            $item_output .= '<span class="js-trigger-dropdown"><i class="fas fa-sort-down"></i></span></a>';
        } else {
            $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 = 0, $args = array() ) {
        $output .= "</li>\n";
      }
    }

    Looking forward to getting some help 🙂

Viewing 3 replies - 1 through 3 (of 3 total)
  • Moderator bcworkz

    (@bcworkz)

    That’s kind of a lot of code to digest for volunteers here without further guidance. What specific issue are you struggling with?

    Thread Starter ivohagoort

    (@ivohagoort)

    I understand what you are saying.

    Basically what i would like is to fetch a menu slug or menu id and based on that slug or id, output a different html for the submenu.

    Something like this.
    If menu_id = campers -> html output 1
    Else if menu_id = help -> html output 2
    Else -> html output 3

    Hope this helps.

    Moderator bcworkz

    (@bcworkz)

    I’m not so sure the nav walker is the best approach, though I understand the temptation. The walker sort of runs on “auto-pilot” based on the menu objects that are passed to it. As a recursive algorithm, it doesn’t have control of the overall menu structure. It deals with one menu object at a time, while knowing where it is within the menu structure. It does not control the structure, it responds to it.

    I recommend manipulating the object structure through the ‘wp_nav_menu_objects’ filter before the walker even starts working. The nav menu system works by querying for all menu items within a particular taxonomy term related to the menu being requested (Primary, Secondary, etc.). Which sub menus go under which parent item are already defined through the UI. Your example doesn’t deviate from this concept, so I’m still unsure of what you’re after that’s different from default.

    I suspect you want some sort of dynamic assignment of sub menus based on some condition, but being based on the parent ID doesn’t make sense as that’s how the nav menus work anyway. Through the mentioned filter, you can remove and add other menu items, but I’m unsure where they’d be coming from. All menu items belong to a specific menu. I suppose you could have a number of menus that aren’t true menu locations, rather those items get swapped in under a particular parent items based on some condition. It’d be a matter of placing the items in the right place in the array of objects, while altering the added items’ parent property to reflect their new parent.

Viewing 3 replies - 1 through 3 (of 3 total)
  • The topic ‘WP Menu Walker’ is closed to new replies.