John Russell Blog

WordPress Custom Sectional Menu

WordPress Menus

With the release of WordPress 3.0 menus were introduced as a visually editable element within the dashboard, dramatically improving WordPress’ CMS capabilities. However, many large websites require menu systems that are a bit more flexible and dynamic that what the built-in menu system provides. For instance, have you ever needed to create a primary navigation menu that resolved to top-level sections of the website and a series of secondary navigation menus that resolved to sub-pages related to each top-level section? Sure, you can create one menu for the top-level primary navigation and another menu for each sub-section of the website and then create a page template corresponding to each of the sub-section menus. The problem with this approach is that you have to create and maintain so many different menus and page templates, not to mention if you’re planning to turn the site over to a client upon completion it requires them to learn and follow certain steps with each page that they create. What if, instead, we could create one master menu and use the regular page template? This is where a custom sectional menu comes in by use of the wp_nav_menu_objects filter hook.

Custom Sectional Menus

To do this we need to create a large nested menu, resembling something similar to the list below, and then set it to be the active menu for the primary and secondary theme locations.

  • top-level-menu-item1
    • sub-section-menu-item1
    • sub-section-menu-item2
    • sub-section-menu-item3
      • nested-sub-section-menu-item1
  • top-level-menu-item2
  • top-level-menu-item3
    • sub-section-menu-item1
    • sub-section-menu-item2
      • nested-sub-section-menu-item1
      • nested-sub-section-menu-item2
      • nested-sub-section-menu-item3

Using the nested menu example from above the primary navigation menu would always show the top-level-menu-items. However, when viewing a sub-section page, such as the page associated with “nested-sub-section-menu-item3” the secondary menu would only show the menu items that are nested under “top-level-menu-item3”. The only remaining question is, how exactly do we do this?

The Solution

I’ve put together a fairly simple function snippet that can be copied and pasted into your themes functions.php file.

function lb_sectional_menu($items, $args) {
	// theme_locations to filter
	$locations = array('secondary');
	// include the root parent menu item in the menu (true) or not (false)
	$display_parent_menu_item = false;
	
	if (in_array($args->theme_location, $locations)) {
		$allow_menu_items = false;
		
		foreach ($items as $key => $item) {
			if ((int)$item->menu_item_parent === 0) $allow_menu_items = false;
			if ((int)$item->menu_item_parent === 0 && ($item->current || $item->current_item_parent || $item->current_item_ancestor)) $allow_menu_items = true;
			if ($allow_menu_items === false || ((int)$item->menu_item_parent === 0 && $display_parent_menu_item === false)) unset($items[$key]);
		}
	}
	
	return $items;
}
add_filter('wp_nav_menu_objects', 'lb_sectional_menu', 10, 2);

Update September 17, 2014 – I’ve updated the lb_sectional_menu filter function to be much more efficient and less prone to error. The wp_nav_menu_objects filter is applied after all menu_items have been sorted/ordered so instead we can just look for menu_items with a menu_item_parent that is equal to zero (meaning that it’s a root parent menu_item) and allow menu_items until the next menu_item_parent equal to zero is encountered. This means the menu will work even if it’s a page, post, tag, custom link, etc. It will also work no matter how many menu items are nested.

This function allows you to build a single, nested, menu and then reuse it across the entire website, where it will dynamically display the necessary menu items for the section being viewed.


Posted

in

,

by

Tags:

Comments

Leave a Reply

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