0

WordPress doesn't add parent class to menu items that have submenus. Therefore this is required to extend this:

function add_parent_css( $classes, $item ) {
    global $have_children;
    if( $have_children ) {
        $classes[] = 'parent';
    }
    return $classes;
}
add_filter( 'nav_menu_css_class', 'add_parent_css', 10, 2 );

class custom_walker extends Walker_Nav_Menu {
  function display_element($element, &$children_elements, $max_depth, $depth=0, $args, &$output){
    $GLOBALS['have_children'] = (isset($children_elements[$element->ID]))? 1:0;
    parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
  }
  [...]
}

The code will insert parent class to all menu items that have sub-menus and this can be then used in CSS like:

.parent:after { content: ">"; }

I'm wondering though, if there is a way to do that without custom menu walker? Just with filters? The reason I'm asking this is because some plugins like WPML ignore custom menu walkers for menu items and their "language switcher" in the menu doesn't get parent class even if has sub-items. Instead of waiting for WPML to fix that I would prefer to just update the menu in a theme to do it in a simpler way.

2
  • Do you know which related function WPML uses? wp_list_pages, wp_nav_menu etc. Commented Jun 26, 2013 at 11:00
  • They add new items to wp_nav_menu but I would prefer to get rid of theme custom menu walker anyway. I would prefer it to have parent class via filter only.
    – Atadj
    Commented Jun 26, 2013 at 11:01

2 Answers 2

3

I'm using the following code to achieve this. Doesn't need any walkers or anything else, just insert this into your functions.php and the items with sub-menu will get "menu-parent-item" added as class.

add_filter( 'wp_nav_menu_objects', 'add_menu_parent_class' );
function add_menu_parent_class( $items ) {
    $parents = array();
    foreach ( $items as $item ) {
        //Check if the item is a parent item
        if ( $item->menu_item_parent && $item->menu_item_parent > 0 ) {
            $parents[] = $item->menu_item_parent;
        }
    }

    foreach ( $items as $item ) {
        if ( in_array( $item->ID, $parents ) ) {
            //Add "menu-parent-item" class to parents
            $item->classes[] = 'menu-parent-item'; 
        }
    }

    return $items;    
}

I've been using this for a long time. Unfortunately I can't remember where I found it, so can't give credits to the one who came up with it.

3
  • 2020 this still working for me. Thank you Commented Dec 14, 2020 at 20:09
  • 2023 tested and it does work. I am now looking to modify it to add a new back button element for sub-level menus that I will only use for mobile devices.
    – Sambuxc
    Commented Jul 26, 2023 at 10:16
  • Where can I see the list of $item-> methods available?
    – Sambuxc
    Commented Jul 26, 2023 at 10:20
1
function wpse_104316_nav_menu_css_class( $classes, $item ) {
    if ( ! empty( $item->current_item_parent ) || ! empty( $item->current_item_ancestor ) ) 
        $classes[] = 'parent';
    return $classes;
}

add_filter( 'nav_menu_css_class', 'wpse_104316_nav_menu_css_class', 10, 2 );

Update: Seems you can't achieve it with the above approach. But you can however "force" the custom walker by hooking onto wp_nav_menu_args:

function wpse_104316_wp_nav_menu_args( $args ) {
    $args['walker'] = new custom_walker;
    return $args;
}

add_filter( 'wp_nav_menu_args', 'wpse_104316_wp_nav_menu_args', 100 );

Use this in addition to your current code.

5
  • It raises an error: FATAL ERROR: CANNOT USE OBJECT OF TYPE STDCLASS AS ARRAY IN ...
    – Atadj
    Commented Jun 26, 2013 at 11:12
  • Sorry, try update. Commented Jun 26, 2013 at 11:17
  • Both $item->current_item_parent and $item->current_item_ancestor have false for parent and children menu items when I'm viewing parent menu item so it doesn't add parent class to anything unfortunately.
    – Atadj
    Commented Jun 26, 2013 at 11:24
  • Check revision. Commented Jun 26, 2013 at 11:43
  • Thanks! This is a good solution to my issue but I'll go with something that doesn't require custom walker. If I may suggest something for anyone trying to do this: do it with jQuery. You'll save time and you'll maintain the code without custom walker which is usually better. WordPress is likely to update their code with "parent-menu-item" class that is added for items that have children: core.trac.wordpress.org/ticket/20191 Hopefully they will also add "description" support and ability to set custom "data-*" attributes or custom classes for more items than just parent wrapper or LI.
    – Atadj
    Commented Jun 26, 2013 at 13:10

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.