wp_nav_menu change sub-menu class name?

Solution 1:

There is no option for this, but you can extend the 'walker' object that WordPress uses to create the menu HTML. Only one method needs to be overridden:

class My_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_lvl(&$output, $depth) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent<ul class=\"my-sub-menu\">\n";
  }
}

Then you just pass an instance of your walker as an argument to wp_nav_menu like so:

'walker' => new My_Walker_Nav_Menu()

Solution 2:

This is an old question and I'm not sure if the solution I'm going to mention was available by the time you asked, but I think it's worth mentioning. You can achieve what you want by adding a filter to nav_menu_submenu_css_class. See the example below - you can replace my-new-submenu-class by the class(es) you want:

function my_nav_menu_submenu_css_class( $classes ) {
    $classes[] = 'my-new-submenu-class';
    return $classes;
}
add_filter( 'nav_menu_submenu_css_class', 'my_nav_menu_submenu_css_class' );

Solution 3:

Choice of options.

  1. Switch the 'echo' argument to false and you can replace the class names.
    echo str_replace('sub-menu', 'menu menu_sub', wp_nav_menu( array(
        'echo' => false,
        'theme_location' => 'sidebar-menu',
        'items_wrap' => '<ul class="menu menu_sidebar">%3$s</ul>' 
      ) )
    );
  1. Since WP 4.8 we can use the nav_menu_submenu_css_class filter.
add_filter( 'nav_menu_submenu_css_class', 'my_custom_submenu_classnames', 10, 3 );
/**
 * Filters the CSS class(es) applied to a menu list element.
 *
 * @param string[] $classes Array of the CSS classes that are applied to the menu `<ul>` element.
 * @param stdClass $args    An object of `wp_nav_menu()` arguments.
 * @param int      $depth   Depth of menu item. Used for padding.
 * @return string[]
 */
function my_custom_submenu_classnames( $classes, $args, $depth ) {
    // Here we can additionally use menu arguments.
    if ( 'header-menu' === $args->theme_location ) {
        $default_class_name_key = array_search( 'sub-menu', $classes );
        if ( false !== $default_class_name_key ) {
            unset( $classes[ $default_class_name_key ] );
        }
        $classes[] = 'header-submenu';
        $classes[] = "depth-{$depth}";
    }

    return $classes;
}
  1. Custom Menu walker:
class My_Nav_Menu_Walker extends Walker_Nav_Menu {
    /**
     * Starts the list before the elements are added.
     *
     * @see Walker::start_lvl()
     *
     * @param string   $output Used to append additional content (passed by reference).
     * @param int      $depth  Depth of menu item. Used for padding.
     * @param stdClass $args   An object of wp_nav_menu() arguments.
     */
    public function start_lvl( &$output, $depth = 0, $args = null ) {
        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
            $t = '';
            $n = '';
        } else {
            $t = "\t";
            $n = "\n";
        }
        $indent = str_repeat( $t, $depth );

        // ! You default class names.
        $classes = array( 'sub-menu', 'my-class' );
        // ! Example of using arguments.
        if ( 'header-menu' === $args->theme_location ) {
            $default_class_name_key = array_search( 'sub-menu', $classes );
            if ( false !== $default_class_name_key ) {
                unset( $classes[ $default_class_name_key ] );
            }
            $classes[] = 'header-submenu';
            $classes[] = "depth-{$depth}";
        }

        /**
         * Filters the CSS class(es) applied to a menu list element.
         *
         * @since 4.8.0
         *
         * @param string[] $classes Array of the CSS classes that are applied to the menu `<ul>` element.
         * @param stdClass $args    An object of `wp_nav_menu()` arguments.
         * @param int      $depth   Depth of menu item. Used for padding.
         */
        $class_names = implode( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

        $output .= "{$n}{$indent}<ul{$class_names}>{$n}";
    }
}

It remains to include the file with an custom walker and point it to the menu:

wp_nav_menu(
    array(
        'theme_location' => 'header-menu',
        'walker'         => new My_Nav_Menu_Walker()
    )
);

Solution 4:

You can use WordPress preg_replace filter (in your theme functions.php file) example:

function new_submenu_class($menu) {    
    $menu = preg_replace('/ class="sub-menu"/','/ class="yourclass" /',$menu);        
    return $menu;      
}

add_filter('wp_nav_menu','new_submenu_class'); 

Solution 5:

Here's an update to what Richard did that adds a "depth" indicator. The output is level-0, level-1, level-2, etc.

class UL_Class_Walker extends Walker_Nav_Menu {
  function start_lvl(&$output, $depth) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent<ul class=\"level-".$depth."\">\n";
  }
}