Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I don't want to have the parent menu items of my site's nav menus linking to a separate page. For one thing I don't want to have a superfluous page. For another these links hobble site navigation for mobile users who can't "hover" over a link (to bring up the child items).

The best solution would be to disable the parent menu item links. But how do I do that, especially now that with WordPress 3.5 the Disable Parent Menu Item plugin has stopped working?

One possible solution is here.

share|improve this question
add comment

3 Answers 3

Do not create fake URLs (#). This would be very bad for users with a screen reader: the are using a list of available links to browse your site. The same is true for javascript: links, they are not exactly elegant markup anyway.

You need two steps:

  1. Mark the items with children before the walker starts.
  2. Replace the markup for the top parents.

I will use an empty <a> element here to make it easy to get the cursor. You will probably need something like this in your stylesheet:

.menu > .has-children {
    cursor: pointer;
}

The filter to mark parent items is taken from this answer. The second function just checks for that property and it tests if the item is itself not a child item.

add_filter( 'wp_nav_menu_objects',      't5_add_has_children_to_nav_items' );
add_filter( 'walker_nav_menu_start_el', 't5_unlink_parent_item', 10, 4 );

/**
 * Add aproperty 'has_children' to menu items
 *
 * @wp-hook wp_nav_menu_objects
 * @param   array $items
 * @return  array
 */
function t5_add_has_children_to_nav_items( $items )
{
    $parents = wp_list_pluck( $items, 'menu_item_parent' );
    $out     = array ();

    foreach ( $items as $item )
    {
        in_array( $item->ID, $parents ) && $item->has_children = TRUE;
        $out[] = $item;
    }
    return $items;
}
/**
 * Replace top parent element markup.
 *
 * @wp-hook walker_nav_menu_start_el
 * @param   string $item_output
 * @param   object $item
 * @param   int    $depth
 * @param   object $args
 * @return  string
 */
function t5_unlink_parent_item( $item_output, $item, $depth, $args )
{
    // not first level parent item
    if ( empty ( $item->has_children ) or 0 != $item->menu_item_parent )
        return $item_output;

    $title = apply_filters(
        'the_title',
        $item->title,
        $item->ID
    );
    $id = apply_filters(
        'nav_menu_item_id',
        'menu-item-'. $item->ID,
        $item, $args
    );
    $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;
    $classes[] = 'has-children';
    $class_names = join(
        ' ',
        apply_filters(
            'nav_menu_css_class',
            array_filter( $classes ),
            $item,
            $args
        )
    );
    $class_names = $class_names
        ? ' class="' . esc_attr( $class_names ) . '"'
        : '';

    return "<li$id>$args->before<a class='menu-item has-children'>$title</a>$args->after";
}
share|improve this answer
    
This is a better answer than mine but it indicates a fundamental flaw in WordPress menus that this much code is needed to achieve what should be a simple thing :) –  JCL1178 Jan 18 '13 at 6:23
    
@JCL1178 I guess not many authors use a href-less top level. And most custom themes use a custom walker anyway. I see the native implementation as a starting guide that works in most cases but isn’t forced onto the developer. –  toscho Jan 18 '13 at 6:27
    
Thanks for your lengthy reply, toscho. You put a lot of work into it I can see. Actually, the answer in the link I posted says to remove the hash symbol, so there's no hash symbol in the link that appears in the menu: it becomes a link without an href, i.e., no URL, fake or otherwise. Since your solution seems to depend on evacuating the href as well, I wonder how it is better for screen-readers. Is your walker worthwhile? –  JohnK Mar 24 '13 at 1:44
    
@JohnK The plugin from that thread is probably the worst possible attempt to solve that issue. You will get conflicts with other plugins with that, because it calls wp_print_scripts a second time. This should never have passed the plugin review … Anyway, use the PHP solution here; it is free of side effects, except when you use a plugin that comes with its own custom walker. –  toscho Mar 24 '13 at 1:57
    
The link wasn't to the plug-in, toscho, but to a simple, 'by-hand' way to replace it in making a non-clickable menu item. Seems to produce the same effect as your code. I'd like to give you credit for your work, but I can only choose yours as the correct answer if you somehow justify its superiority over the simple way. –  JohnK Mar 24 '13 at 2:25
show 1 more comment

I would simply create custom menu items with a javascript:void(0) as the href whenever a parent item is needed.

share|improve this answer
    
Good answer, and a much better solution than using hash symbol as the link as indicated in the posters link. –  gteh Jan 18 '13 at 5:38
    
Actually if you read carefully, that solution says to remove the hash symbol, so there's no hash symbol in the link. –  JohnK Mar 24 '13 at 1:31
add comment

Works with WordPress 3.5:

  1. Add a Link entry with the name you want and a # URL
  2. Edit the menu entry you just created and remove the #

You have to do both steps, as you can't add a menu entry with an empty URL.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.