Filtering WordPress Navigation Menus

WordPress 3 introduced native navigation menus, usually created via the wp_nav_menu theme function and the built-in Custom Menu widget.  If you have a menu with a deep hierarchy, you may want to display only the active branch and the submenu directly below the active item (given class “current-menu-item” by WordPress). You can see this menu behavior on the left in the UF College of Education Faculty site.

This is sadly not doable with CSS. I originally did it with Javascript, but the requirements of progressive enhancement required that the whole menu be output before attacking the DOM. Depending on the page, this caused a distracting collapse of the menu during the layout.

The class Coewp_MenuFilter does this menu filtering server-side. Until I wrap this in a plugin, just put it in your theme folder:

// in functions.php
require dirname(__FILE__) . '/MenuFilter.php';
Coewp_MenuFilter::add();

How it works

add() attaches a filter to the “wp_nav_menu” hook, so WordPress passes menu HTML through the class’s filter() method before returning it in wp_nav_menu(). In filter(), the HTML is converted to a DOMDocument object, which is edited using DOM methods (with XPath available, this version was almost a direct port of the jQuery version). After cutting it down, the DOM tree is re-serialized to HTML.

I was really hoping this filtering could be done before the HTML was created, say by subclassing WP’s Walker_Nav_Menu class, but this proved difficult to debug.