0

I have this code in my functions.php to add new attribute data-content="" to all my <li> items in the wordpress menu. The value of each data-content has to be different: I would like that each value corresponds to the inside text (in slug format) of the <a> tag.

function add_attribute( $items, $args ) {
    $dom = new DOMDocument();
    $dom->loadHTML($items);
    $find = $dom->getElementsByTagName('li');

    foreach ($find as $item ) :
        $item->setAttribute('data-content','');

    endforeach;

    return $dom->saveHTML();

}
add_filter('wp_nav_menu_items', 'add_attribute', 10, 2);

Here's how the final result (in html) should be:

<ul>
  <li class="menu-item" data-content="about">
    <a href="#">About</a>
  </li>

  <li class="menu-item" data-content="my-services">
    <a href="#">My services</a>
  </li>

  <li class="menu-item" data-content="contact-me">
    <a href="#">Contact me</a>
  </li>
</ul>

For the moment the PHP code just creates the attribute but does not add any value inside data-content. I'm struggling to find the way how do it... Any help is much appreciated, thanks!

Upadate: I tried the PHP function nav_menu_link_attributes. Unfortunately it doesn't work on <li> elements. The function add a new attribute and its value on each <a> elements of the menu.

add_filter( 'nav_menu_link_attributes', 'cfw_add_data_atts_to_nav', 10, 4 );
function cfw_add_data_atts_to_nav( $atts, $item, $args )
{
    $atts['data-content'] = sanitize_title($item->title);
    return $atts;
}
6
  • How is PHP supposed to know what to fill inside the data-content attribute?
    – kero
    Commented Jan 14, 2020 at 13:03
  • That's the point. I don't know of it should be done in PHP or in javascript. Commented Jan 14, 2020 at 13:05
  • "each value corresponds to the inside text (in slug format)" - sorry, I overread that earlier. Why do you need that values there? Depending on that, I'd use a JS solution or create a custom nav walker (instead of filtering as you currently do).
    – kero
    Commented Jan 14, 2020 at 13:10
  • If I use a JS solution, I can add the value but I don't find the way to convert it in slug format. About the custom nav walker, do you know any tutorial which could help how to do this? Thanks. Commented Jan 14, 2020 at 13:24
  • Would it be possible to have the data-content on the <a> or does it need to be on the <li>?
    – kero
    Commented Jan 14, 2020 at 15:49

1 Answer 1

1

I already had this need, I found this code somewhere in the web. up to you to customize it with your needs. I tested it on the Twenty Nineteen theme:enter image description here

Put this in functions.php :

class themeslug_walker_nav_menu extends Walker_Nav_Menu {

 // add classes to ul sub-menus
function start_lvl(&$output, $depth) {
    // depth dependent classes
    $indent = ( $depth > 0 ? str_repeat("\t", $depth) : '' ); // code indent
    $display_depth = ( $depth + 1); // because it counts the first submenu as 0
    $classes = array(
        'sub-menu',
        ( $display_depth % 2 ? 'menu-odd' : 'menu-even' ),
        ( $display_depth >= 2 ? 'sub-sub-menu' : '' ),
        'menu-depth-' . $display_depth
    );
    $class_names = implode(' ', $classes);

    // build html
    $output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
}

// add main/sub classes to li's and links
function start_el(&$output, $item, $depth, $args) {
    global $wp_query;
    $indent = ( $depth > 0 ? str_repeat("\t", $depth) : '' ); // code indent
    // depth dependent classes
    $depth_classes = array(
        ( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
        ( $depth >= 2 ? 'sub-sub-menu-item' : '' ),
        ( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
        'menu-item-depth-' . $depth
    );
    $depth_class_names = esc_attr(implode(' ', $depth_classes));

    // passed classes
    $classes = empty($item->classes) ? array() : (array) $item->classes;
    $class_names = esc_attr(implode(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item)));

    // build html
    $output .= $indent . '<li data-content="'.$item->title.'"  id="nav-menu-item-' . $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';

    // link attributes
    $attributes = !empty($item->attr_title) ? ' title="' . esc_attr($item->attr_title) . '"' : '';
    $attributes .=!empty($item->target) ? ' target="' . esc_attr($item->target) . '"' : '';
    $attributes .=!empty($item->xfn) ? ' rel="' . esc_attr($item->xfn) . '"' : '';
    $attributes .=!empty($item->url) ? ' href="' . esc_attr($item->url) . '"' : '';
    $attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';

    $item_output = sprintf('%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s', $args->before, $attributes, $args->link_before, apply_filters('the_title', $item->title, $item->ID), $args->link_after, $args->after
    );

    // build html
    $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
    }

}

And in header.php :

wp_nav_menu( array(
   'theme_location'    => 'menu-1',
   'container'     => 'div',
   'container_id'      => 'top-navigation-primary',
   'conatiner_class'   => 'top-navigation',
   'menu_class'        => 'menu main-menu menu-depth-0 menu-even', 
   'echo'          => true,
   'items_wrap'        => '<ul id="%1$s" class="%2$s">%3$s</ul>',
   'depth'         => 10, 
   'walker'        => new themeslug_walker_nav_menu
) ); // thanks nick

So adapt the code to your needs. good luck

1
  • 1
    Thank you so much your solution. It works perfectly! I adapted the code to my menu. I only modified the following line of code because I needed the value of data-content as a slug format: <li data-content="'.$item->title." To: <li data-content="'.sanitize_title($item->title)." Commented Jan 14, 2020 at 16:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.