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.

link|improve this question

feedback

3 Answers

up vote 13 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 ) {
            // ...
        }
    }
link|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 at 22:18
feedback

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.

link|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
feedback

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.

link|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
feedback

Your Answer

 
or
required, but never shown

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