I tried looking for info about how to exclude/remove nav menu items from custom menus, and the only thread I found did not have any answers that were useful to me.
1. Background:
I put together a Dock menu using WP custom menus (wp_nav_menu) and jqDock on my site. Since jqDock needs continuous images or image links to work its magic, I' using a custom walker so the nav menu HTML output looks smth like this:
<div id="menu-first" class="nav">
<a><img src="http://path/to/image-1.png"/></a>
<a><img src="http://path/to/image-2.png"/></a>
<a><img src="http://path/to/image-3.png"/></a>
etc...
</div>
The code for my custom walker is:
class custom_nav_walker extends Walker_Nav_Menu
{
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
function start_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu\">\n";
}
function end_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
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;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
//$output .= $indent . '<li' . $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 ) .'"' : '';
$description = ! empty( $item->description ) ? esc_attr( strtolower( $item->description )) : '';
$item_title = ! empty( $item->attr_title ) ? esc_attr( $item->attr_title ) : '';
if ( strpos($description, ';') !== false ) {
$description_array = explode (';', $description);
$image_name = $description_array[0];
$image_alt = $description_array[1];
} else {
$image_name = $description;
$image_alt = $item_title;
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before .'<img src="'.get_bloginfo('template_url').'/images/skin1/'.$image_name.'" alt="'.$image_alt.'" title="'.$item_title.'" />'.$args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
function end_el(&$output, $item, $depth) {
$output .= "";
}
}
The jqDock script then catches the menu ID ('menu-first') and replaces the wp_nav_menu output with the Dock menu's. The Dock menu's HTML output changes based on the options specified when loading jqDock.
2. The Question:
I would like to not display (i.e., exclude) certain menu items according to where the user is on the site. For example, I would like to only show the Home item when the user is not in the Home, and the Random post item only when he is.
3. Discarded solutions:
a. Muliple menus: Registering and creating multiple menus and then calling them conditionally could work; however, I don't think this is an ideal nor a clean solution at all for many reasons. Also, multiple menus are not easy to maintain or update.
b. Regex Search and Replace: This might force me to change the needle parameter every time I change the jqDock options because the HTML output is modified.
c. CSS 'display' property: Hiding the items through the CSS display property works, but since it has to be applied to the jqDock menu output, it affects the visual rendering of the menu.
4. Failed Solutions:
a. Filter to wp_nav_menu_items: I tried catching the '$items' variable (string) and assigning it different values through conditional tags with the following code:
function userf_dynamic_nav_menu ($items) {
$items_array_home = explode('<a', $items);
$items_array_nothome = $items_array_home;
unset($items_array_home[1]);
unset($items_array_nothome[2]);
$items_home = implode('<a', $items_array_home);
$items_nothome = implode('<a', $items_array_nothome);
if ( is_home() ) {
$items = $items_home;
} else {
$items = $items_nothome;
}
return $items;
}
add_filter('wp_nav_menu_first_items', 'userf_dynamic_nav_menu');
This works only partially, because the menu items do change, but the conditional tags are ignored. I guess this makes sense because of the moment in which the filter is applied.
b. Custom nav menu function: I tried creating my own custom nav menu function to be able to add an exclude argument to the $defaults array and to use this slightly modified code from wp_list_pages
to populate the additional argument:
$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );
Any ideas?
exclude
argument too, but, contrary towp_list_pages
and many other WP functions,wp_nav_menu
does not include one. So even if I do specify one when calling the menu or in the walker, it wouldn't get picked up insidewp_nav_menu
, would it?