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

16

72

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?

Headset answered 22/1, 2013 at 17:28 Comment(2)
This function is very well documented, but it appears a lot easier to add a class to the ul or wrap the link content with something and change your CSS accordingly (custom walker is you alternative): codex.wordpress.org/Function_Reference/wp_nav_menuNitrogenous
Or..you could create your own Menu Walker ( Codex ) and use it in your wp_nav_menu() function..Arboreous
T
-26

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.

Tedium answered 22/1, 2013 at 20:41 Comment(5)
While I appreciate the attempt to propose a solution this doesn't answer the question. In my case, for example, I need to apply a Bootstrap 4 "col" class.Tellurize
The easiest thing to do is use JS. Otherwise you need to add a filter via PHP that modifies the core function as detailed in one of the other answers.Tedium
I know this is old, but it's equally unhelpful in my situation and doesn't address the original question. In my situation, I'm trying to target a menu item by name, within a network install where the menu list item ID's vary between sites.Bicephalous
This answer is incorrect - see the other upvoted answers for alternative ways to handle this.Ed
This might not be the best way to solve the problem, but its a perfectly valid answer. There are almost always multiple ways to solve any problem and every potential solution has pros and cons. I'm not sure why this answer is getting so much hate.Pincince
L
174

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);
Luggage answered 3/8, 2018 at 4:34 Comment(6)
Nice solution. If I was the OP, I would have accepted this as the answer.Flanch
Best solution IMO, generic and cleanDesorb
Best solution, but I need to modify it to avoid an error "Undefined property: stdClass::$item_class" Solution: if(isset($args->item_class)) { ...etcDekaliter
what is the function of 1 and 3 argument? Please Explain.Baltoslavic
1 is the priority order. Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. 3 is the number of arguments the function accepts. On that case, the filter will accept $classes, $items and $args arguments. Please read developer.wordpress.org/reference/functions/add_filter for more informationLuggage
This didn't work for me. Instead of isset($args->add_li_class) I had to add array_key_exists('add_li_class', $args). And for $classes[] = $args->add_li_class; I had to add $classes[] = $args['add_li_class'];.Aussie
H
77

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/

Hanover answered 7/9, 2016 at 13:25 Comment(4)
I know this answer was published much later than the chosen one, but I feel this should be marked as the correct answer as it does exactly what the question asked.Matzo
I couldn't get this to work, directly copied into my functions.php and it doesn't do anything.Aryan
@SpencerShattuck do you have a menu location 'secondary' in your theme? You may also need something like <code> register_nav_menus( array( 'primary' => __( 'Primary Menu' ), 'secondary' => __( 'Secondary Menu' ) ) ); </code>Hanover
I found a solution that worked for me at: github.com/wp-bootstrap/wp-bootstrap-navwalkerAryan
T
69

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.
Thun answered 19/6, 2013 at 11:42 Comment(4)
This is the answer OP.Kreegar
this has to be done by end user. not a solution to implement in theme.Juxtapose
For dev it's the best and easy one as if they are developing static themes.Meshwork
for huge menus, this is not a practical solutionTriple
C
18

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

Cuticula answered 13/4, 2018 at 4:3 Comment(0)
H
15

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"; 
}
Hyperbola answered 6/7, 2018 at 11:51 Comment(2)
But how to we target specific menus with this approach. I have a menu called main-menu and another called footer-menu.Hesychast
try wrapping $classes[] = "nav-item"; with if ( 'main-menu' === $args->theme_location ) { $classes[] = "nav-item"; }Hyperbola
E
6

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

Eldaelden answered 17/2, 2018 at 13:25 Comment(1)
Good idea for those whom don't use a standard <li> as items.Intramolecular
B
3

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);
Bicephalous answered 4/1, 2018 at 20:14 Comment(0)
B
3

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;
    }
}
Bullis answered 17/12, 2020 at 12:31 Comment(0)
S
2
<?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
                            )
                    )
            );
?>
Septate answered 21/2, 2018 at 12:37 Comment(0)
W
2

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);
Watusi answered 16/3, 2022 at 20:21 Comment(0)
C
1

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.

Curvy answered 21/2, 2022 at 17:5 Comment(0)
J
0

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);
Jesuit answered 13/6, 2019 at 13:35 Comment(0)
M
0

// 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

Ml answered 7/6, 2021 at 6:10 Comment(0)
A
0

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);
Alika answered 8/12, 2021 at 17:18 Comment(0)
U
0

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

Uncircumcision answered 26/1, 2024 at 13:6 Comment(0)
T
-26

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.

Tedium answered 22/1, 2013 at 20:41 Comment(5)
While I appreciate the attempt to propose a solution this doesn't answer the question. In my case, for example, I need to apply a Bootstrap 4 "col" class.Tellurize
The easiest thing to do is use JS. Otherwise you need to add a filter via PHP that modifies the core function as detailed in one of the other answers.Tedium
I know this is old, but it's equally unhelpful in my situation and doesn't address the original question. In my situation, I'm trying to target a menu item by name, within a network install where the menu list item ID's vary between sites.Bicephalous
This answer is incorrect - see the other upvoted answers for alternative ways to handle this.Ed
This might not be the best way to solve the problem, but its a perfectly valid answer. There are almost always multiple ways to solve any problem and every potential solution has pros and cons. I'm not sure why this answer is getting so much hate.Pincince

© 2022 - 2025 — McMap. All rights reserved.