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'm writing a customised walker class for wp_nav_menu and want to be able to specify if an li contains a submenu. So I want my markup to be:

<li class="has_children [other-wordpress-classes]">
    <a class="parent-link">Some item</a>
    <ul class="sub-menu">

I know how to add and remove the classes fine, I just cant find anything to tell me if the current item has children items.

Any ideas?

Thanks in advance.

share|improve this question

4 Answers 4

up vote 18 down vote accepted

start_el() should get this information in its $args parameter, but it appears WordPress only fills this in if $args is an array, while for the custom navigation menus it is an object. This is reported in a Trac ticket. But no problem, you can fill this in yourself, if you also override the display_element() method in your custom walker (because this is the easiest place to access the child element array):

class WPSE16818_Walker extends Walker_Nav_Menu
{
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output )
    {
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
        }
        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            // ...
        }
    }
share|improve this answer
    
Hello Jan, Can you help me with this question? I tried your code but i couldn't make it work. Can you give me some more sample code? –  Giri Feb 3 '12 at 22:18
    
Refer to the complete implementation example further down on this page. –  rjb Mar 6 '13 at 20:41
    
Thanks a lot @Jan fabry.. I was held up with my custom walker.. Atlast your snippet helped me. –  Harish Chinju May 5 at 10:12

For a complete solution for anybody in a hurry (credit to Jan Fabry's previous answer), see the full implementation below.

Output the navigation in your theme's template:

wp_nav_menu( array(
    'theme_location' => 'navigation-primary',
    'container' => false,
    'container_class' => '',
    'container_id' => '',
    'menu_class' => '',
    'menu_id' => '',
    'walker' => new Selective_Walker(),
    'depth' => 2
    )
);

Then, include the following in your theme's functions.php:

class Selective_Walker extends Walker_Nav_Menu {
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
        $id_field = $this->db_fields['id'];

        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = !empty( $children_elements[$element->$id_field] );
        }

        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            $item->classes[] = 'has_children';
        }

        parent::start_el(&$output, $item, $depth, $args);
    }
}

The resulting HTML output will resemble the following:

<ul>
    <li><a href="#">Home</a></li>
    <li class="has_children"><a href="#">About</a>
        <ul class="sub-menu">
            <li><a href="#">Our Mission</a></li>
        </ul>
    </li>
    <li><a href="#">Services</a></li>
    <li class="has_children"><a href="#">Products</a>
        <ul class="sub-menu">
            <li><a href="#">Lorem Ipsum</a></li>
            <li><a href="#">Lorem Ipsum</a></li>                
        </ul>
    </li>
    <li><a href="#">Contact Us</a></li>
</ul>

For more information on using WordPress' walker class, see Understanding the Walker Class.

Enjoy!

share|improve this answer
    
Fatal error: Call-time pass-by-reference has been removed in D:\www\wordpress\wp-content\themes\wpt_theme\functions.php on line 44 –  Tahir Yasin Jul 14 at 19:43
    
Line#44 is parent::start_el(&$output, $item, $depth, $args); –  Tahir Yasin Jul 14 at 19:44

This function is exactly what you want to have. It also shows you a pretty effective way to modify nav menu items. Furthermore you can open it for more advanced (eg. child theme) functions via the item-filter:

/**
 * Classes for a navigation named "Topnav" in the nav location "top".
 * Shows examples on how to modify the current nav menu item
 * 
 * @param (object) $items
 * @param (object) $menu
 * @param (object) $args
 */
function wpse16818_nav_menu_items( $items, $menu, $args )
{
    # >>>> start editing

    // examples for possible targets
    $target['name'] = 'Topnav';
    // The targeted menu item/s
    $target['items'] = array( (int) 6 );

    # <<<< stop editing

    // filter for child themes: "config_nav_menu_topnav"
    $target = apply_filters( 'config_nav_menu_'.strtolower( $target['name'] ), $target );

    // Abort if we're not with the named menu
    if ( $menu->name !== $target['name'] ) 
        return;

    foreach ( $items as $item )
    {
        // Check what $item contains
        echo '<pre>'; print_r($item); echo '</pre>';

        // First real world example:
        $item->classes = 'span-4';

        // Second real world example:
        // Append this class if we are in one of the targeted items
        if ( in_array( (int) $item->menu_order, $target['items'] ) )
            $item->classes .= ' last';
    }

    return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse16818_nav_menu_items', 10, 3 );

And yes, there's - in nearly every case - no need for a custom walker.

share|improve this answer
    
Thanks, I need the walker for now but will have a look at this for next time round! –  patnz May 10 '11 at 23:50

if you want to make drop down, you can do it with css only. make custom nav in WP with children, WordPress automatically assigns class .sub-menu to child ul. Try this CSS

    nav li {position:relative;}
   .sub-menu {display:none; position:absolute; width:300px;}
    nav ul li:hover ul {display:block;}

You may want to add some jQuery to spice it up a little, but this should give you a working drop down menu.

share|improve this answer
    
Thanks, its for a multilevel collapsible tree menu that I'm inserting control elements into as well, but definitely good to do as much with css as possible! –  patnz May 10 '11 at 23:49

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.