36

I'm building a horizontal menu and some of the entries on that menu will have dropdowns (sub-menus), and some won't. Those that have sub-menus are not actually pages. They're just meant to be guides for the dropdowns.

For instance, say the the horizontal menu is like follows:

Home | About Us | Products | Directions | Contact

And the "products" li item is meant to have 3 pages linked in a vertical dropdown list below it, so "products" itself doesn't actually represent a page, how can I do that in WP?

(I use WP as a CMS, with static home and inside pages. I build my own templates, style the menus in CSS, then register the menus in the functions.php and call them in the templates.) In WP you add entries to the menus via the list of pages, or by the custom links. But I don't want "products" to be linked. If I don't add a link to the custom link it won't let me add it to the menu.

Is this doable through the menus admin or do I have to approach it some other way?

Thank you for any help!

4
  • 1
    heres the solution works great go check it wordpress.org/support/topic/no-page-menu-item
    – user48746
    Commented Mar 10, 2014 at 9:30
  • You can do this by using js. try this article. kvcodes.com/2014/07/…
    – Kvvaradha
    Commented Feb 16, 2016 at 4:50
  • 1
    In the URL box, leave it blank.
    – AMY WANG
    Commented Jul 11, 2018 at 17:03
  • Nobody mentioned the WP_NAV_MENU_WALKER Class, you could write your own walker that spits out what you want. Commented Sep 18, 2018 at 19:24

18 Answers 18

15

I have a few ideas:

  1. Set the custom link to # which won't return anything
  2. Add a custom class to the items and then use jQuery to remove the links.
  3. Use a PHP equivalent to the jQuery method
  4. Use the Disable Parent Menu Link plugin (or take it apart and write your own)
4
  • 1
    Thank You for the tips and links! As Gavin suggested, using a # for a custom link "works"; the other options may work better, though aren't as easy. Well, the plugin is probably easy but I hate to use plugins if I can accomplish the same thing more directly. I'll have to decide the best approach. Thanks again!
    – PVA
    Commented Oct 5, 2011 at 21:17
  • If you plan to use it in tactile devices, be careful with using empty href=""because most tactile device users won't be able to see dropdown menu without using JS
    – Simon
    Commented Nov 21, 2013 at 15:05
  • Links break. You might want to work a few of these ideas into your answer
    – shea
    Commented May 13, 2015 at 1:33
  • Also, #2 and #3 refer to wp_list_pages(), not wp_nav_menu()
    – shea
    Commented May 13, 2015 at 1:34
35

The easiest way to do it without a plugin or anything is to use the "Menus" function of WordPress. Here are the instructions for WordPress 4.8:

  1. From your WordPress dashboard, go to "Appearance -> Menus"
  2. In the "Edit Menus" tab, select "Custom Links"
  3. For the URL, Enter "#" (no quotes)
  4. For the link text, enter your desired text for the top level of your drop-down menu
  5. Click the "Add to Menu" button
  6. Drag the menu item to its desired position within your menu
  7. For the menu item you just added, click the down arrow to the right of the item (it will read "custom link" to the left of the item)
  8. Remove the "#" from the URL. This - in all browsers - will convert the link to plain text.
  9. Click on the "Save Menu" button
6
  • Thank You for that tip. It's ez, though not perfect in that the Labels still look like "links" when you mouseover, but they don't go anywhere. So it can work in a pinch.
    – PVA
    Commented Oct 5, 2011 at 21:15
  • 1
    Did you read the whole comment? After the link is added, click the dropdown arrow by the link's name, and remove the "#" from the URL textbox. This, in all browsers, will cause the link to not be clickable.
    – GavinR
    Commented Oct 6, 2011 at 13:10
  • 2
    Yes, thank you, I did read the whole comment. I went back through and tried again and realized my problem. When I leave the #, the word appears in the navbar but as a "dead link". When I removed the # the word didn't appear in the navbar unless I hovered over it and it would appear in a hover state. So I assume that means I have to apply CSS to the word so that it appears without being linked. I'm not sure why the hover state shows up...
    – PVA
    Commented Oct 6, 2011 at 22:13
  • This still in 4.9.5, however I'm not sure as it 'feels' like a hack tacking advantage of a bug. If not.. it's going to save people a lot of headaches... This is kind of like the fact that Wordpress considers "1 2 3 4 5 6" a strong password...still. Commented May 22, 2018 at 16:52
  • 1
    FYI, if you do Step 8 (for whatever good reason), then your cursor won't be a pointer when you hover over the custom link. In that case, you could style it with pointer:cursor.
    – Kalnode
    Commented Nov 17, 2018 at 2:57
10

The simplest method I came up with was to create a Custom Link item with the Link URL value of #. This is sending the user to an empty hash on the same page, so basically links nowhere.

However, there are some side-effects of using empty hashes for placeholder links. The link will still appear and behave like a link, so it could confuse a user when they are clicking on what appears to be a link but nothing happens. The other effect is that clicking on an empty hash link will override any existing hash, sending the user to the top of the page. This might not be so worrying for a menu which is at the top of the page anyway, but it is quite jarring when the page unexpectedly jumps when you are not expecting it, especially if this is for a footer menu.

The solution is to combine the empty hash method with a piece of code to detect when empty hash links are used in the menu and to remove the href attribute from that link entirely. An a element without a href attribute is the correct HTML 5 method of creating an placeholder link.

/**
 * Remove the href from empty links `<a href="#">` in the nav menus
 * @param string $menu the current menu HTML
 * @return string the modified menu HTML
 */
add_filter( 'wp_nav_menu_items', function ( $menu ) {
    return str_replace( '<a href="#"', '<a', $menu );
} );
1
  • You can even change the whole a tag: <?php add_filter( 'wp_nav_menu_items', function ( $menu ) { return str_replace( ['<a href="#"', '/a>'], ['<span', '/span>'], $menu ); } ); ?>. Just don't forget to add the dropdown by css or js.
    – quasi
    Commented Apr 2, 2020 at 12:54
3

This worked for me:

I activated CSS Classes in Menus > Screen Options > CSS Classes Then I gave the menu element that I wanted to deactivate the class ".nolink" and added this piece of code to my custom CSS panel:

.nolink {
   pointer-events: none;
   cursor: default;
}
2
  • This kills dropdown too.
    – user385917
    Commented Jun 28, 2017 at 18:06
  • Using # as the link target and then applying a custom CSS class for styling purposes, is the least hacky solution in my opinion. However, setting pointer-events: none does not make a lot of sense for me, since it will break sub menus. Could you elaborate on why you set that attribute? Commented Jul 4, 2019 at 9:32
2

Using the PHP approach I added this code to functions.php:

function remove_link_contact_menu($item_output, $item) {
    if ($item->post_name == 'contact')
        return '<span>' . $item->title . '</span>';

    return $item_output;
}
add_filter('walker_nav_menu_start_el', 'remove_link_contact_menu', 20, 2);
add_filter('megamenu_walker_nav_menu_start_el', 'remove_link_contact_menu', 20, 2);

This will replace the link with a span element for the item menu with the post_name == "contact", which is what I was looking for. You can easily change that to check for the menu title or the ID, or add some code to check if it has any child menu items etc.

0
2

Appreciate this is an old thread, but for a quick and dirty way of having a link in Wordpress is by making the link URL as:

#_

Notice the underscore after the hashtag. This way if your menu scrolls down the page (ie. fixed), you don't get a jump to the top of the page when clicking on it and doesn't require any plugins/script.

2

Create "Custom Links" menu item and add javascript:; to the URL field. This is better way than using the # because it won't scroll your page to the top when clicked.

1
  1. Set the custom link to # which won't return anything List item
  2. Add this filter:

    add_filter( 'wp_nav_menu_items', 'wpse_remove_empty_links' );
    
    function wpse_remove_empty_links( $menu ) {
    
        return preg_replace("/<a href=\"#\">(.+?)<\/a>/is", "<span>$1</span>", $menu);
    
    }
    
  3. Edit span CSS to get same style as <a>, don't forget cursor: context-menu;.

0

I solved this way: in header.php (of your theme) I searched for:

'link_before'     => '',
'link_after'      => '',

and replaced with:

'link_before'     => '<script>var scriptTag=document.getElementsByTagName("script");scriptTag=scriptTag[scriptTag.length-1];if(scriptTag.parentNode.href)if(scriptTag.parentNode.href.slice(-1)=="#")document.write("<span onclick=\"return false\">")</script>',
'link_after'      => '<script>var scriptTag=document.getElementsByTagName("script");scriptTag=scriptTag[scriptTag.length-1];if(scriptTag.parentNode.href)if(scriptTag.parentNode.href.slice(-1)=="#")document.write("</span>")</script>',

In simple words, this script checks if its parent link ends with "#", in this case it adds a span element around the content of the A tag, that disables the click.

Hope it helps :-)

1
  • Hi, I know this is an old answer but for future reference, I wouldn't just go in and change your themes header file because when it updates next all your code will be overwritten. The best solution for this is to create a child theme with your custom code.
    – Scott
    Commented Mar 21, 2017 at 14:29
0

As others here have suggested you can create a custom link menu item with the # as its url. Then erase the # once it is added to the menu. And finally, you can use this simple regex to strip the actual tag from those links.

preg_replace('/<a>([^<]+)<\/a>/i', '<span class="no-link">$1</span>', $navHTML);
0

This will remove the click (and unstyle the item). This way, you dont have to use the custom # links in your menu.

add_action( 'wp_footer', function(){
    ?>
    <script>
    (function( $ ) {
        var itemm = $('#main-menu .menu-item-has-children > a');
        itemm.click(function(){
            document.activeElement && document.activeElement.blur();
            return false;
        });
    })(jQuery);
    </script>
<?php
 }, 1, 0 );
0

I realize I'm late in the game, but these are the two methods I use:

1) Make the parent menu item a duplicate of the first sub-item, and change its label. For example, if the first item under "Products" is "Product 1", use "Product 1" as the parent menu item, then change its label to "Products". That way, both "Products" and "Product 1" will lead to the page Product 1.

2) Add a redirect so that the Products page is redirected to Product 1. The benefit of this option is that it allows you to create a blank Products page to create a hierarchical listing in Pages, but if anyone tries to go to the blank Products page, they will be redirected.

0

Go to Appearance, then click on menus. In this section go under menu structure and click on the arrow down to expand the page and you'll see a box that says disable link. Check that box and save.

2
  • 1
    This functionality is not provided by core. Perhaps a theme or plugin is adding it to your setup? Commented Jan 26, 2018 at 21:58
  • I've seen this before too, I wish I knew which plugin or theme did this.
    – DavGarcia
    Commented Jan 15, 2019 at 12:53
0

Writing from 1/2019, the solution that produces proper HTML5 is to do the following.

  1. Add a Custom Link with the URL set to #, and whatever name you'd like. Both fields are required.
  2. Edit the newly added Custom Link so that the URL is empty.
  3. Save the changes.

This will produce a top level nav that is <a>Menu</a> which is the correct way to represent a non-clickable link.

0

Create a custom link menu as other as said. View the source code and look for the href of the submenu, for example: #mm-1. Paste this into the URL of the custom link and save the menu. This will make the mobile version work as well when you tap the menu text.

0

My version looks like this:

first, in the menu in the admin panel in the desired link in the href field put # or leave it empty, and then in function.php themes are added:

function replace_empty_menu_links( $item_output, $item, $depth, $args ) {
  if ( $item->url == '#' || $item->url == '' ) {
    $item_output = sprintf( '%1$s<' . 'div' . '%2$s>%3$s%4$s%5$s</' . 'div' . '>%6$s',
      $args->before,
      $attributes,
      $args->link_before,
      apply_filters( 'the_title', $item->title, $item->ID ),
      $args->link_after,
      $args->after
    );
  }
  return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'replace_empty_menu_links', 10, 4 );

You can replace 'div' with any element that suits you.

This works for version 5.3.2 (tested in this version, but should work in others too).

In this form, the work of all arguments 'before', 'after', 'link_before', 'link_after', etc. from wp_nav_menu() is preserved.

Also, this works for sub-menus too.

-1

Much easier solution can be found on another question:

Admin Menu - Highlight top-level menu when on a sub-menu page (without showing sub-menu)

Look for Askelon's answer. Work's perfectly, without needing to do any preg_replaces or jquery.

-1

You may disable the events on the <a> tag for all first level menu items using pure css. .main-menu class may have another name according to your menu naming.

/* disable parent menu items */
ul.main-menu > li > a {
    pointer-events: none;
}

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