Building a Dynamic Secondary Menu

I recently redeveloped the Texas 4-H website (go ahead, check it out!), and one of the unique features is its dynamic secondary menu.

This website has lots of deep content; most of its content is three levels deep. We added a secondary menu both to indicate the user’s current location in the site and to simplify browsing these sub-sections. I didn’t want the client managing two separate menus since they would invariably get out of sync when someone updates the primary menu but forgets to update the secondary menu.

Creating a Dynamic Secondary Menu

I created one menu and assigned it to both the ‘header’ and ‘secondary’ theme locations. The code below only affects the ‘secondary’ theme location. It first finds the active section by looking for a class of ‘current-menu-item’ or ‘current-menu-ancestor’ on one of the top level menu items. If no active section is found, it returns false, which removes the secondary menu. If an active section is found, it gathers all the menu items that are within that section and displays them in the secondary menu.

This is somewhat similar to my plugin Genesis Subpages as Secondary Menu. The difference is this code below generates the secondary menu based on the submenu items (managed in Appearance > Menus). That plugin generates the submenu based on page items (managed in Pages).

The benefit to this approach is you can include non-pages in the menu and the secondary menu will still work just fine. In this case, “Projects” is a custom post type, the submenu items are terms in the “project category” taxonomy, and the third level items are posts in the “projects” post type. This code will also ensure your secondary menu is “in sync” with the primary menu. So if you exclude a subpage from the menu, it won’t appear in the secondary menu.

<?php
/**
* Submenu items in secondary menu
*
* Assign the same menu to 'header' and 'secondary'.
* This will display the current section's subpages in 'secondary'
*
* @author Bill Erickson
* @link http://www.billerickson.net/building-dynamic-secondary-menu
*
* @param array $menu_items, menu items in this menu
* @param array $args, arguments passed to wp_nav_menu()
* @return array $menu_items
*
*/
function be_submenu_items_in_secondary( $menu_items, $args ) {
// Only run on 'secondary' menu location.
if( 'secondary' !== $args->theme_location )
return $menu_items;
// Find active section
$active_section = false;
foreach( $menu_items as $menu_item ) {
if( ! $menu_item->menu_item_parent && array_intersect( array( 'current-menu-item', 'current-menu-ancestor' ), $menu_item->classes ) )
$active_section = $menu_item->ID;
}
if( ! $active_section )
return false;
// Gather all menu items in this section
$sub_menu = array();
$section_ids = array( $active_section );
foreach( $menu_items as $menu_item ) {
if( in_array( $menu_item->menu_item_parent, $section_ids ) ) {
$sub_menu[] = $menu_item;
$section_ids[] = $menu_item->ID;
}
}
return $sub_menu;
}
add_filter( 'wp_nav_menu_objects', 'be_submenu_items_in_secondary', 10, 2 );
view raw functions.php hosted with ❤ by GitHub

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. CGO says

    Hello, i’m french developper and your tutorial is perfect for me. But i have a problem, i doesn’t work this.

    I’m creating two emplacement menu location : header and secondary (i don’t work with genesis theme)

    how to use it ?