Blog

06 Aug
2013

WordPress Icon Logo

Navigation item stays highlighted when tag or category selected


I recently had a problem relating to the main menu with a WordPress site which used the e-shop plugin. The main navigation menu had three buttons - 'Contact Us', 'Useful Links' and 'Shop'. I wanted the 'Shop' button to stay highlighted even when the user selected a Shop Category or Shop Tag.

Here is the scenario:

I have a shop with sells several cloths items. The categories would be 't-shirts' and 'shorts'. The tags would be the 'brands', 'colours' and 'sizes'. When choosing the 'Shop' button it takes me to a landing page which shows the top 10 items. Now when choosing a Shop Category it takes me to a page listing all the items for that category. If I then choose a Shop Tag it shows a page listing all the products that use that tag. So how did I make the Shop button stay highlighted all the time?

Well I had to extend the WordPress built in class/functions Walker_Nav_Menu. In order to do this I first added the following to my themes (Appearance->Editor) functions.php file, which replaces WordPress's default menu output.

class example_walker extends Walker_Nav_Menu
{
    function start_el(&$output, $item, $depth, $args)
    {
        global $wp_query;
        $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 ) );
        $class_names = ' class="'. esc_attr( $class_names ).'"';
        $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names.'>';
        $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        ) .'"' : '';

        $prepend = '<strong>';
        $append = '</strong>';
        $description  = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : '';
        if($depth != 0)
        {
            $description = $append = $prepend = "";
        }
        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append;
        $item_output .= $description.$args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

Then in my themes header.php (Appearance->Editor) file I add the new menu class.

<?php 
wp_nav_menu( array(
    'theme_location' => 'primary',
    'container' =>false,
    'menu_class' => 'nav-menu',
    'echo' => true,
    'before' => '',
    'after' => '',
    'link_before' => '',
    'link_after' => '',
    'depth' => 0,
    'walker' => new example_walker())
);
?>

In order to sort the issue I amended the extended 'Walker_Nav_Menu' as below.

class example_walker extends Walker_Nav_Menu
{
    function start_el(&$output, $item, $depth, $args)
    {
        global $wp_query;
        $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 ) );
        $class_names = ' class="'. esc_attr( $class_names ); 

        if (is_tag() && $item->ID == '35' || is_category() && $item->ID == '35' || is_single() && $item->ID == '35' || is_search() && $item->ID == '35')
        {
            $class_names .= ' current-menu-item ';

        }
        $class_names .= '"';
        $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names.'>';
        $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        ) .'"' : '';

        $prepend = '<strong>';
        $append = '</strong>';
        $description  = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : '';
        if($depth != 0)
        {
            $description = $append = $prepend = "";
        }
        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append;
        $item_output .= $description.$args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

The part that changed was this...

$class_names = ' class="'. esc_attr( $class_names ).'"';

... to this.

$class_names = ' class="'. esc_attr( $class_names );    
    if (is_tag() && $item->ID == '35' || is_category() && $item->ID == '35' || is_single() && $item->ID == '35' || is_search() && $item->ID == '35')
    {
        $class_names .= ' current-menu-item ';
    }
$class_names .= '"';

What it's doing is looping through each of the navigation menu items as it outputs them to see if the current one is the 'Shop' button ($item->ID == '35'), but also at the same time is checking to see if:

  • we are on a tag link page
  • we are on a category link page
  • we are on a single product landing page
  • we are on a search results page

And then adding the WordPress default css 'current-menu-item' class to the 'Shop' menu item to make it stay highlighted. I found the $item->ID number by viewing the html source code of the menu. It contained something like this.

id="menu-item-(ID_NUMBER)"
Posted in: < CMS >
me@grafxflow avatar

me@grafxflow


I am a Full-stack Developer who also started delving into the world of UX/UI Design a few years back. I blog and tweet to hopefully share a little bit of knowledge that can help others around the web. Thanks for stopping by!

Visitors also viewed these posts


Add comment

Add comment