Question

I'm building a site with a mega menu. Here's what the structure looks like:

<ul>
  <li class="active-grandparent">Grandparent
    <ul>
      <li>Parent</li>
      <li>Parent</li>
      <li>Parent</li>
      <li>Parent
        <ul>
          <li>Child</li>
          <li>Child</li>
          <li>Child</li>
          <li>Child</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Grandparent</li>
  <li>Grandparent</li>
  <li>Grandparent</li>
</ul>

I'd like to add the class "active-grandparent" to the top level Grandparent <li> if you are on that page or a parent / child page.

WordPress gives each active <li> item a class of current-menu-item, but I need to specifically target the grandparent <li> only so I can add some styles for when it's active.

How is this achieved?

Updated As pointed out in the the comments, I could use current-menu-ancestor. However, this is only being generated on the Grandparent <li> when you're on a parent or child page.

To clarify, if you're on the top level Grandparent page (/grandparent), these are the classes which are being generated within the <li>:

.menu-item
.menu-item-type-post_type
.menu-item-object-page 
.current-menu-item 
.page_item page-item-12 
.current_page_item 
.menu-item-has-children 
.menu-item-203

If you're on a parent (/grandparent/parent) or child page (/grandparent/parent/child), these are the classes which are being generated within the Grandparent <li>:

.menu-item 
.menu-item-type-post_type 
.menu-item-object-page 
.current-page-ancestor 
.current-menu-ancestor 
.current-menu-parent 
.current-page-parent 
.current_page_parent 
.current_page_ancestor 
.menu-item-has-children 
.menu-item-203

If it helps, here are how my menus are generated within the template file:

<nav class="sidebar-navigation">
  <ul>
    <?php
      $menu = array( 'container' => false, 'menu_class' => false, 'items_wrap' => '%3$s' );
      // Left
      wp_nav_menu( array_merge(
        array( 'theme_location'  => 'left' ),
        $menu
      ) );
      // Right
      wp_nav_menu( array_merge(
        array( 'theme_location'  => 'right' ),
        $menu
      ) );
    ?>
  </ul>
</nav>
Was it helpful?

Solution

Styling the top-level item if it's active or a child is active is possible with pure CSS. Use the child selector, >, from the top:

.sidebar-navigation > ul > .current-menu-item,
.sidebar-navigation > ul > .current-menu-ancestor {}

If you want to add a new class, you can use the nav_menu_css_class filter. One of its parameters is $depth, which you can use to affect only top-level items. To tell if it's child is active you can just check for the existence of the current-menu-item or current-menu-ancestor classes:

function wpse_310629_nav_menu_css_class( $classes, $item, $args, $depth ) {
    if ( $depth === 0 ) {
        if ( 
            in_array( 'current-menu-item', $classes ) || 
            in_array( 'current-menu-ancestor', $classes ) 
        ) {
            $classes[] = 'active-grandparent';
        }
    }

    return $classes;
}
add_filter( 'nav_menu_css_class', 'wpse_310629_nav_menu_css_class', 10, 4 );
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top