How to add class to link in wp_nav_menu?
Asked Answered
M

7

34

I am trying to out a wp menu without ul and li and have a class added to the element.

I have tried adding this in my function.php

function add_menuclass($ulclass) {
  return preg_replace('/<a /', '<a class="list-group-item"', $ulclass, 1);
}
add_filter('wp_nav_menu','add_menuclass');

And in my template I have:

<?php
 $menuParameters = array(
   'menu'  => 'Videos',
   'container'       => false,
   'echo'            => false,
   'items_wrap'      => '%3$s',
   'depth'           => 0,
);

  echo strip_tags(wp_nav_menu( $menuParameters ), '<a>' );
?>

But the output only applies the class to the first item and not all of the <a>s as expected.

<div class="list-group">
   <a class="list-group-item" href="#">First item</a>
   <a href="#">Second item</a>
</div>

I am trying to achieve this, basically to apply that class to ALL my item (not sure why it applies it to only one) - No jQuery please.

<div class="list-group">
   <a class="list-group-item" href="#">First item</a>
   <a class="list-group-item" href="#">Second item</a>
</div>
Mandell answered 3/10, 2014 at 14:17 Comment(6)
php.net/manual/en/function.preg-replace.php - fourth parameter, $limit. You are setting it to 1. Read the docs. Very very clear why this is happening when you explicitly request it to work like that.Mckenzie
To clarify, you want to add an additional class to each <a> within the menu?Duffer
@Duffer yes exactlyMandell
@SergiuParaschiv ok didn't know about it. WIll check it outMandell
@SergiuParaschiv thanks to your comment I made my own answer solutionMandell
if you are going to integrate wp theme with bootstrap you can use this ready to use walkerLoving
M
39

Thanks to Sergiu Paraschiv comment the issue was in regards of limiting to 1.

Therefore it should be in function.php:

function add_menuclass($ulclass) {
   return preg_replace('/<a /', '<a class="list-group-item"', $ulclass);
}
add_filter('wp_nav_menu','add_menuclass');

UPDATE

There is a better way actually which gives us much more control and the piece of code is provided by Jeff Starr on this post

NOTE: this isn't adding the current class tho

Create your menu on wp, then remember to click the location in the menu editor then in your function you'd do:

// custom menu example @ https://digwp.com/2011/11/html-formatting-custom-menus/
function clean_custom_menus() {
    $menu_name = 'nav-primary'; // specify custom menu name
    if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name])) {
        $menu = wp_get_nav_menu_object($locations[$menu_name]);
        $menu_items = wp_get_nav_menu_items($menu->term_id);

        $menu_list = '<nav>' ."\n";
        $menu_list .= "\t\t\t\t". '<ul>' ."\n";
        foreach ((array) $menu_items as $key => $menu_item) {
            $title = $menu_item->title;
            $url = $menu_item->url;
            $menu_list .= "\t\t\t\t\t". '<li><a href="'. $url .'">'. $title .'</a></li>' ."\n";
        }
        $menu_list .= "\t\t\t\t". '</ul>' ."\n";
        $menu_list .= "\t\t\t". '</nav>' ."\n";
    } else {
        // $menu_list = '<!-- no list defined -->';
    }
    echo $menu_list;
}

Finally we can call our menu:

<?php if (function_exists(clean_custom_menus())) clean_custom_menus(); ?>

The code above is taken from the post linked above, I thought to include this answer as it appears this question has many visits.

UPDATE 2

Another solution would be (maybe the best):

header.php:

    <?php
      wp_nav_menu( array(
        'theme_location'  => 'topnav',
        'menu'            =>'topnav',
        'container'       => 'div', 
        'container_class' => 'collapse navbar-collapse', 
        'container_id'    => 'navbarCollapse',
        'menu_class'      => 'menu', 
        'echo'            => true,
        'fallback_cb'     => 'wp_page_menu',
        'items_wrap'      => '<ul class="nav justify-content-end w-100 %2$s">%3$s</ul>',
        'depth'           => 0
      ) );
    ?>

function.php:

 // register the nav
 function register_my_menu() {
  register_nav_menu('topnav',__( 'topnav' ));
 }
 add_action( 'init', 'register_my_menu' );

// let's add "*active*" as a class to the li

add_filter('nav_menu_css_class' , 'special_nav_class' , 10 , 2);
function special_nav_class($classes, $item){
     if( in_array('current-menu-item', $classes) ){
             $classes[] = 'active ';
     }
     return $classes;
}

// let's add our custom class to the actual link tag    

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

function add_menuclass($ulclass) {
   return preg_replace('/<a /', '<a class="nav-link"', $ulclass);
}
add_filter('wp_nav_menu','add_menuclass');
Mandell answered 3/10, 2014 at 14:57 Comment(1)
Thanks for updating with your answer.Duffer
A
54

Taking a hint from this answer which I found was the most concise about adding classes to the list items of the menus, I used nav_menu_link_attributes filter which does work well for adding classes.

In your functions.php, add:

function add_menu_link_class( $atts, $item, $args ) {
  if (property_exists($args, 'link_class')) {
    $atts['class'] = $args->link_class;
  }
  return $atts;
}
add_filter( 'nav_menu_link_attributes', 'add_menu_link_class', 1, 3 );

Optionally, you may want to add the option to add classes to list items:

function add_menu_list_item_class($classes, $item, $args) {
  if (property_exists($args, 'list_item_class')) {
      $classes[] = $args->list_item_class;
  }
  return $classes;
}
add_filter('nav_menu_css_class', 'add_menu_list_item_class', 1, 3);

Now, in your template, to build a menu you just add two new arguments, e.g.:

wp_nav_menu([
    'theme_location'=> 'primary_navigation',
    'menu_class'    => 'navbar-nav ml-auto flex-nowrap',
    'list_item_class'  => 'nav-item',
    'link_class'   => 'nav-link m-2 menu-item nav-active'
]);

Works well with themes with multiple menus which have different appearance.

Aswan answered 7/10, 2018 at 13:24 Comment(3)
how to set class only for main menu items, not for submenu?Lindyline
@DaVoDHoseiny try using css to change appearance of submenu itemsAswan
best ever answerAlice
M
39

Thanks to Sergiu Paraschiv comment the issue was in regards of limiting to 1.

Therefore it should be in function.php:

function add_menuclass($ulclass) {
   return preg_replace('/<a /', '<a class="list-group-item"', $ulclass);
}
add_filter('wp_nav_menu','add_menuclass');

UPDATE

There is a better way actually which gives us much more control and the piece of code is provided by Jeff Starr on this post

NOTE: this isn't adding the current class tho

Create your menu on wp, then remember to click the location in the menu editor then in your function you'd do:

// custom menu example @ https://digwp.com/2011/11/html-formatting-custom-menus/
function clean_custom_menus() {
    $menu_name = 'nav-primary'; // specify custom menu name
    if (($locations = get_nav_menu_locations()) && isset($locations[$menu_name])) {
        $menu = wp_get_nav_menu_object($locations[$menu_name]);
        $menu_items = wp_get_nav_menu_items($menu->term_id);

        $menu_list = '<nav>' ."\n";
        $menu_list .= "\t\t\t\t". '<ul>' ."\n";
        foreach ((array) $menu_items as $key => $menu_item) {
            $title = $menu_item->title;
            $url = $menu_item->url;
            $menu_list .= "\t\t\t\t\t". '<li><a href="'. $url .'">'. $title .'</a></li>' ."\n";
        }
        $menu_list .= "\t\t\t\t". '</ul>' ."\n";
        $menu_list .= "\t\t\t". '</nav>' ."\n";
    } else {
        // $menu_list = '<!-- no list defined -->';
    }
    echo $menu_list;
}

Finally we can call our menu:

<?php if (function_exists(clean_custom_menus())) clean_custom_menus(); ?>

The code above is taken from the post linked above, I thought to include this answer as it appears this question has many visits.

UPDATE 2

Another solution would be (maybe the best):

header.php:

    <?php
      wp_nav_menu( array(
        'theme_location'  => 'topnav',
        'menu'            =>'topnav',
        'container'       => 'div', 
        'container_class' => 'collapse navbar-collapse', 
        'container_id'    => 'navbarCollapse',
        'menu_class'      => 'menu', 
        'echo'            => true,
        'fallback_cb'     => 'wp_page_menu',
        'items_wrap'      => '<ul class="nav justify-content-end w-100 %2$s">%3$s</ul>',
        'depth'           => 0
      ) );
    ?>

function.php:

 // register the nav
 function register_my_menu() {
  register_nav_menu('topnav',__( 'topnav' ));
 }
 add_action( 'init', 'register_my_menu' );

// let's add "*active*" as a class to the li

add_filter('nav_menu_css_class' , 'special_nav_class' , 10 , 2);
function special_nav_class($classes, $item){
     if( in_array('current-menu-item', $classes) ){
             $classes[] = 'active ';
     }
     return $classes;
}

// let's add our custom class to the actual link tag    

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

function add_menuclass($ulclass) {
   return preg_replace('/<a /', '<a class="nav-link"', $ulclass);
}
add_filter('wp_nav_menu','add_menuclass');
Mandell answered 3/10, 2014 at 14:57 Comment(1)
Thanks for updating with your answer.Duffer
P
6

I have solution to add class to anchor tag.

1: Step: add this in functions.php

function add_additional_class_on_a($classes, $item, $args)
{
    if (isset($args->add_a_class)) {
        $classes['class'] = $args->add_a_class;
    }
    return $classes;
}

add_filter('nav_menu_link_attributes', 'add_additional_class_on_a', 1, 3);

2: Then use it like this in your theme

<?php
        // Show Menu here
        wp_nav_menu(array(
            'theme_location' => 'my-footer-menu',
            'container_id'    => '',
            'menu_class'      => 'footer-top list-unstyled',
            'menu_id'         => '',
            'add_a_class'     => 'box-link text-dark',
        ));
?>
Pectize answered 6/6, 2021 at 13:16 Comment(2)
@LarsFlieger looks a lot like my answer on the other post where you are advertising this post. #42994656 At least give credits ;)Arcanum
@LarsFlieger common bro, It has lot of differnce. Sorry but I did not copied it from your code.Pectize
M
1

I want add 'item' class to li should write this code:

add_filter('nav_menu_css_class' , 'nav_class' , 10 , 2);
function nav_class($classes, $item){
    $classes[] = 'item';
    return $classes;
}
Mooned answered 7/1, 2019 at 7:17 Comment(0)
G
0

One mroe solution with Java Script:

const allLIItems = document.querySelectorAll(".menu-item");

for (let i = 0; i < allLIItems.length; i++) {
    allLIItems[i].classList.add("nav-item");
    var aHref = allLIItems[i].innerHTML.split(" ");
    const newAHref = `${aHref[0]} class="nav-link" ${aHref[1]}`;
    allLIItems[i].innerHTML = newAHref;
  }
Gavel answered 24/7, 2022 at 5:3 Comment(0)
D
0

The answer @stol helped me! Thank you so much!

For example (This is my situation):

functions.php

function add_menu_link_class( $atts, $item, $args ) {
  if (property_exists($args, 'link_class')) {
    $atts['class'] = $args->link_class;
  }
  return $atts;
}
add_filter( 'nav_menu_link_attributes', 'add_menu_link_class', 1, 3 );

header.php

                <?php
                    wp_nav_menu(
                        array(
                            'theme_location'  => 'primary',
                            'items_wrap'      => '<ul class="%2$s">%3$s</ul>',
                            'fallback_cb'     => false,
                            'link_class'   => 'nav-header hidden'
                        )
                    );
                ?>
Darondarooge answered 12/12, 2022 at 10:41 Comment(1)
Please don't add "thank you" as an answer. Once you have sufficient reputation, you will be able to vote up questions and answers that you found helpful. - From ReviewTragopan
A
-8

My solution is simple, use our friend jquery

in the menu inject a custom menu_id

<?php 
   wp_nav_menu(array(
     'theme_location'=>'primary', 
     'container'=>false,
     'menu_class'=>'navbar-nav mr-auto',
     'menu_id'=>'customAclassInWp_nav_menu'
    )
  ); 
?>

then use jquery to inject the missing class.

$( "#customAclassInWp_nav_menu li a" ).addClass( "nav-link" );

tadammmm :)

enjoy

Adlare answered 29/6, 2018 at 17:58 Comment(2)
The question specifically stated No jQuery please..Varden
@Derek preciselyMandell

© 2022 - 2024 — McMap. All rights reserved.