WordPress set active color for all menu items if links contain anchors on current page

Interesting thing happens with WordPress menu, when you have landing page, though not must be necessarily one-page website, bug will be on any WordPress site on the page where menu has link who is contain anchors and current page contain these elements. In this case WordPress will be mark them as active links.

Problem: When using anchor links out of the box, WordPress will mark them as active links when browsing the page that contains those elements.

Wrong active menu items color on a one-page WordPress website

Solution: I found solution based on jQuery:

$(document).ready(function () {
	var menu_items_links = $(".nav li a");
	menu_items_links.each(function () {
		if ($(this).is('[href*="#"')) {
			$(this).parent().removeClass('current-menu-item current-menu-ancestor');
			$(this).click(function () {
				var current_index = $(this).parent().index(),
					parent_element = $(this).closest('ul');
					parent_element.find('li').not(':eq(' + current_index + ')').removeClass('current-menu-item current-menu-ancestor');
				$(this).parent().addClass('current-menu-item current-menu-ancestor');
			})
		}
	})
});

but this way has a number of shortcomings:

  1. This code need added to the section of website.
  2. This script work based on jQuery library and it need added before our script, in section too.
  3. Enqueue scripts in the section it's bad way, because page speed download gets lows.

Yes, sure we can added scripts to footer, but we'll have blink effect because, right after download page WordPress set active class for all menu items whois anchors, and in a moment our script disable active class. It looks not really good. I offer more a more graceful solution used backend.

First Way. If you don't use custom Walker menu, you can use WP hook nav_menu_css_class for change classes:

add_filter( 'nav_menu_css_class', 'change_menu_item_css_classes', 10, 2 );
	
function change_menu_item_css_classes( $classes, $item ) {
	$rename_classes = [];
	foreach ( $classes as $class ) {
		$rename_classes[] = ( strpos( esc_attr( $item->url ), '#' ) ) ? str_replace( ' current-menu-item current-menu-ancestor', '', $class ) : $class;
	}
	return $rename_classes;
}

Second Way. If you use custom Walker menu you may dispense would suffice just one code string. Sure your Walker menu may be different from the current example, but I think you can handle this:

<?php
class Custom_Walker_Nav_Menu extends Walker_Nav_Menu {
...
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
	    global $wp_query;
	    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

	    $class_names = $value = '';

	    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
	    $classes[] = 'menu-item-' . $item->ID;

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

        $class_names = ( strpos( esc_attr( $item->url ), '#' ) ) ? str_replace( ' current-menu-item current-menu-ancestor', '', $class_names ) : $class_names; // These we remove classes "current-menu-item current-menu-ancestor" from <li> that contain link with anchor
        ...
    }
...
}

Note: in both cases need use string ' current-menu-item current-menu-ancestor' and space in the start it's not a bug, but it's a feature 🙂

Source:

  1. https://intercom.help/elegantthemes/en/articles/2833965-wrong-active-menu-items-color-on-a-one-page-website

Leave Comment

Your email address will not be published. Required fields are marked *