How to add Class in <li> using wp_nav_menu() in Wordpress?

194.3k Views Asked by At

I am using wp_nav_menu($args) and I want to add my_own_class CSS classname to the <li> element.

I'd like to get the following result:

<li class='my_own_class'><a href=''>Link</a>

How to do that?

16

There are 16 best solutions below

5
On BEST ANSWER

You can't add a class directly to the LIs very easily, but is there any reason not to target them in a slightly different but equally specific way (by their parent ul)?

You can set the class or ID of the menu with the menu_class and menu_id parameters (affixed to the UL parent of the LIs) and then target the li's via CSS that way, like so:

<?php wp_nav_menu('menu_id=mymenu'); ?>

And for CSS:

ul#mymenu li {
    /* your styles here */
}

Edit: At the time of writing in 2013 this was the easiest way to add it, but updates since then have added the feature to add CSS classes directly in the admin navigation editor. See more recent answers for details.

0
On

I added a class to easily implement menu arguments. So you can customize and include in your function like this:

include_once get_template_directory() . DIRECTORY_SEPARATOR . "your-directory" . DIRECTORY_SEPARATOR . "Menu.php";

<?php $menu = (new Menu('your-theme-location'))
            ->setMenuClass('your-menu')
            ->setMenuID('your-menu-id')
            ->setListClass('your-menu-class')
            ->setLinkClass('your-menu-link anchor') ?>
    
            // Print your menu
            <?php $menu->showMenu() ?>
<?php

class Menu
{
    private $args = [
        'theme_location' => '',
        'container' => '',
        'menu_id' => '',
        'menu_class' => '',
        'add_li_class' => '',
        'link_class' => ''
    ];

    public function __construct($themeLocation)
    {
        add_filter('nav_menu_css_class', [$this,'add_additional_class_on_li'], 1, 3);
        add_filter( 'nav_menu_link_attributes', [$this,'add_menu_link_class'], 1, 3 );

        $this->args['theme_location'] = $themeLocation;
    }

    public function wrapWithTag($tagName){
        $this->args['container'] = $tagName;
        return $this;
    }

    public function setMenuID($id)
    {
        $this->args['menu_id'] = $id;
        return $this;
    }

    public function setMenuClass($class)
    {
        $this->args['menu_class'] = $class;
        return $this;
    }

    public function setListClass($class)
    {
        $this->args['add_li_class'] = $class;
        return $this;
    }

    public function setLinkClass($class)
    {
        $this->args['link_class'] = $class;
        return $this;
    }

    public function showMenu()
    {
        return wp_nav_menu($this->args);
    }

    function add_additional_class_on_li($classes, $item, $args) {
        if(isset($args->add_li_class)) {
            $classes[] = $args->add_li_class;
        }
        return $classes;
    }

    function add_menu_link_class( $atts, $item, $args ) {
        if (property_exists($args, 'link_class')) {
            $atts['class'] = $args->link_class;
        }
        return $atts;
    }
}
0
On

// Remove translation from Main Menu

function wpdocs_channel_nav_class($classes, $item, $args){
{

if ('primary' === $args->theme_location) {
    $classes[] = "notranslate";
}
    return $classes;
}
add_filter('nav_menu_css_class', 'wpdocs_channel_nav_class', 10, 4);

This is how you easily add the new class to existing class array of you Menu wrapp

0
On

You could simply use wp_nav_menu_items to Filters the HTML list content for navigation menus.

Display nav menu

wp_nav_menu( array(
   'theme_location' => 'parimary',
   'container' => 'ul',
   'menu_class'=> 'nav col-12 col-md-auto mb-2 justify-content-center mb-md-0',
   'add_li_class'  => 'your-class-name1 your-class-name-2',
) );

Menu Registration

function thesportworship_register_menus(){
    register_nav_menus( array(
        'primary'  => __( 'Main Menu', 'thesportworship' ),
    ) );
}
add_action( 'after_setup_theme', 'thesportworship_register_menus', 0 );

Apply filter

function add_additional_class($classes, $item, $args){
    if(isset($args->add_li_class)){
        $classes[] = $args->add_li_class;
    }
    return $classes;
}

add_filter('nav_menu_css_class', 'add_additional_class', 1, 3);
6
On

No need to create custom walker. Just use additional argument and set filter for nav_menu_css_class.

For example:

$args = array(
    'container'     => '',
    'theme_location'=> 'your-theme-loc',
    'depth'         => 1,
    'fallback_cb'   => false,
    'add_li_class'  => 'your-class-name1 your-class-name-2'
    );
wp_nav_menu($args);

Notice the new 'add_li_class' argument.

And set the filter on functions.php

function add_additional_class_on_li($classes, $item, $args) {
    if(isset($args->add_li_class)) {
        $classes[] = $args->add_li_class;
    }
    return $classes;
}
add_filter('nav_menu_css_class', 'add_additional_class_on_li', 1, 3);
0
On

None of these responses really seem to answer the question. Here's something similar to what I'm utilizing on a site of mine by targeting a menu item by its title/name:

function add_class_to_menu_item($sorted_menu_objects, $args) {
    $theme_location = 'primary_menu';  // Name, ID, or Slug of the target menu location
    $target_menu_title = 'Link';  // Name/Title of the menu item you want to target
    $class_to_add = 'my_own_class';  // Class you want to add

    if ($args->theme_location == $theme_location) {
        foreach ($sorted_menu_objects as $key => $menu_object) {
            if ($menu_object->title == $target_menu_title) {
                $menu_object->classes[] = $class_to_add;
                break; // Optional.  Leave if you're only targeting one specific menu item
            }
        }
    }

    return $sorted_menu_objects;
}
add_filter('wp_nav_menu_objects', 'add_class_to_menu_item', 10, 2);
0
On

This is how I added the MainMenu of the WordPress and class to li.

<?php
        $defaults = array( 'menu' => 'mainmenu', 
        'container' => false, 
        'fallback_cb' => 'wp_page_menu', 
        'items_wrap' => '<ul class="navbar-nav" id="myTab">%3$s</ul>', 
        'add_li_class'  => 'nav-item',
       'theme_location' => 'mainmenu' );
        wp_nav_menu( $defaults ); ?>
   

Use this code in functions.php

function li_new_class($classes, $item, $args) {
if(isset($args->add_li_class)) {
    $classes[] = $args->add_li_class;
}
return $classes;
}
add_filter('nav_menu_li_class', 'li_new_class', 1, 3);
0
On

Adding Class to <li> tag without editing functions.php file:

  1. Go to Appearance -> Menu -> Screen Options -> CSS Classes
  2. You will get CSS Class option enabled in Menu Items Window

enter image description here

2
On

use this filter nav_menu_css_class as shown below

function add_classes_on_li($classes, $item, $args) {
    $classes[] = 'nav-item';
    return $classes;
}
add_filter('nav_menu_css_class','add_classes_on_li',1,3);

UPDATE

To use this filter with specific menu

if ( 'main-menu' === $args->theme_location ) { //replace main-menu with your menu
    $classes[] = "nav-item"; 
}
4
On

HERE WordPress add custom class in wp_nav_menu links

OR you can add class <li class='my_own_class'><a href=''>Link</a></li> from admin panel:

  1. Go to YOURSITEURL/wp-admin/nav-menus.php

  2. open SCREEN OPTIONS

  3. make checked CSS CLASSES, then you will see CSS Classes (optional) field in each menu link.
0
On

This is a very simple way to call "li" calss and "any class" replace easily. Just follow the instructions.

Use this code in the nav area.

<?php
            $consult_menu = wp_nav_menu(array(
                    'theme_location' => 'topmenu',
                    'menu_id' => 'menu',
                    'menu_class' => 'navbar-nav m-auto',
                    'echo' => false
                )
            );
            $consult_menu = str_replace('menu-item', 'nav-item', $consult_menu);
            echo $consult_menu;
            ?>

Then inspect your code on the browser. find wp default class and than replace "str_replace("default_class_here","new_li_class_here",$consult_menu); | Note: $consult_menu here is my theme name, you can use any name here.

0
On

Create a custom walker class

class Custom_Menu_Walker extends Walker_Nav_Menu {

    function start_lvl( &$output, $depth = 0, $args = null ) {
        // Add custom class to the <ul> at this level
        $indent = str_repeat("\t", $depth);
        $output .= "\n$indent<ul class=\"sub-menu-level-$depth\">\n";
    }

    function start_el( &$output, $item, $depth = 0, $args = null ) {
        // Add custom class to each <li> item
        $indent = ($depth) ? str_repeat("\t", $depth) : '';
        $class_names = $value = '';

        $classes = empty($item->classes) ? array() : (array) $item->classes;

        $class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args));
        $class_names = ' class="'.esc_attr($class_names).'"';

        $output .= $indent.'<li id="menu-item-'.$item->ID.'"'.$value.$class_names.'>';

        $atts = array();
        $atts['title']  = ! empty( $item->title ) ? esc_attr( $item->title ) : '';
        $atts['target'] = ! empty( $item->target ) ? esc_attr( $item->target ) : '';
        $atts['rel']    = ! empty( $item->xfn ) ? esc_attr( $item->xfn ) : '';
        $atts['href']   = ! empty( $item->url ) ? esc_attr( $item->url ) : '';

        $atts = apply_filters('nav_menu_link_attributes', $atts, $item, $args);

        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                $value = ('href' === $attr) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }

        $item_output = $args->before;
        $item_output .= '<a' . $attributes . '>';
        $item_output .= $args->link_before . apply_filters('the_title', $item->title, $item->ID) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);

        // You can add more customizations or classes as needed
    }

    function end_lvl( &$output, $depth = 0, $args = null ) {
        // Add custom closing tag for the <ul> at this level
        $indent = str_repeat("\t", $depth);
        $output .= "$indent</ul>\n";
    }

    // Add this method to fix the compatibility issue
    function end_el( &$output, $item, $depth = 0, $args = null ) {
        // Add custom closing tag for the <li> item
        $output .= "</li>\n";
    }
}

then use it

 <?php wp_nav_menu(array('theme_location' => 'main-menu', 'walker' => new Custom_Menu_Walker())) ?>

This custom walker also indicates deep level of menu list e.g "sub-menu-level-0" and so on...

enter image description here

1
On

How about just using str_replace function, if you just want to "Add Classes":

<?php
    echo str_replace( '<li class="', '<li class="myclass ',
        wp_nav_menu(
            array(
                'theme_location'    => 'main_menu',
                'container'         => false,
                'items_wrap'        => '<ul>%3$s</ul>',
                'depth'             => 1,
                'echo'              => false
            )
        )
    );
?>

Tough it is a quick fix for one-level menus or the menus that you want to add Classes to all of <li> elements and is not recommended for more complex menus

0
On
<?php
    echo preg_replace( '#<li[^>]+>#', '<li class="col-sm-4">',
            wp_nav_menu(
                    array(
                        'menu' => $nav_menu, 
                        'container'  => false,
                        'container_class'   => false,
                        'menu_class'        => false,
                        'items_wrap'        => '%3$s',
                                            'depth'             => 1,
                                            'echo'              => false
                            )
                    )
            );
?>
4
On

You can add a filter for the nav_menu_css_class action in your functions.php file.

Example:

function atg_menu_classes($classes, $item, $args) {
  if($args->theme_location == 'secondary') {
    $classes[] = 'list-inline-item';
  }
  return $classes;
}
add_filter('nav_menu_css_class', 'atg_menu_classes', 1, 3);

Docs: https://developer.wordpress.org/reference/hooks/nav_menu_css_class/

0
On

The correct one for me is the Zuan solution. Be aware to add isset to $args->add_li_class , however you got Notice: Undefined property: stdClass::$add_li_class if you haven't set the property in all yours wp_nav_menu() functions.

This is the function that worked for me:

function add_additional_class_on_li($classes, $item, $args) {
    if(isset($args->add_li_class)) {
      $classes[] = $args->add_li_class;
    }
    return $classes;
}
add_filter('nav_menu_css_class', 'add_additional_class_on_li', 1, 3);