Community Documentation

Menu items that are not links

Last updated November 29, 2012. Created by keesje on May 11, 2007.
Edited by batigolix, amontero, jonhattan, joachim. Log in to edit this page.

Drupal's menu system lets you define an arbitrary number of menu items in a hierarchy, each of which is a link to somewhere in the site (or on another site). That's great, unless you want to have a menu tree that has items in it which are not, in fact, links.

This page explains how to add "menu links" that will not actually link anywhere.

Modules

Modules that allow links that are not links:

Theme layer: Drupal 5

Alternatively, this can be accomplished in your theme:

Step 1

We will define the magic value <none> to mean "a path to nowhere", just like <front> means "the home page". The crucial part here is the theme_menu_item_link() function, which we will override. Place the following function in your template.php file.

<?php
function phptemplate_menu_item_link($item, $link_item) {
  if (
$item['path'] == '<none>') {
   
$attributes['title'] = $link['description'];
    return
'<span'. drupal_attributes($attributes) .'>'. $item['title'] .'</span>';
  }
  else {
    return
l($item['title'], $link_item['path'], !empty($item['description']) ? array('title' => $item['description']) : array(), isset($item['query']) ? $item['query'] : NULL);
  }
}
?>

Any menu item whose path is <none> will now become a span rather than a link. Note that because it's not a link you can't click on it, so you can't access sub-menu items unless the no-link menu item has the "Expand" checkbox checked so that its children are always visible. If you need to have access to the sub-menu items for things like dropdown/flyout menus, try using the JavaScript version of this snippet.

This method can also be used as a separator. Simply have a menu item with text "------" or similar, and set its path to <none>. It will then show as text with no link, providing a nice separation of the menu.

Step 2

As a nice extra, we can also add additional help text to the menu item edit page. For that you will need to implement a very small module that implements form_alter. The module itself doesn't need anything more than the following code snippet:

<?php
function example_form_alter($form_id, &$form) {
  if (
'menu_edit_item_form' == $form_id) {
   
$form['path']['#description'] .= ' ' . t('Enter %none to have a menu item that generates no link.', array('%none' => '<none>'));
  }
}
?>

That will modify just the menu item edit form and add additional text to the description (the text that appears below the textfield) describing how to use the <none>.

Drupal 6

In Drupal 6 (and 7) you cannot use the value <none> as the target path. You need to define a valid target first.

Add a node with the path alias "nolink" as a dummy to identify this link isn't a link.

Add this to template.php:

<?php
function YOURTHEMENAME_menu_item_link($link) {
  if (
$link['type'] && $link['href'] == 'nolink') {
    return
'<span class="nolink">'.check_plain($link['title']).'</span>';
  }
}
?>

Now add a menu item with "nolink" as target path. Style the .nolink class to your needs

Drupal 7

For Drupal 7 follow the Drupal 6 approach and use this function in template.php:

<?php
function YOURTHEMENAME_menu_link(array $variables) {
 
$element = $variables['element'];
 
$sub_menu = '';

  if (
$element['#below']) {
   
$sub_menu = drupal_render($element['#below']);
  }
  if (
strpos( $element['#href'], 'nolink')) {
   
$output = '<a href="#" class="nolink">' . $element['#title'] . '</a>';
  } else {
 
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
  }
  return
'<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}
?>

Drupal 8

Related issue for 8.x core:
#1543750: Allow menu items without path

Quick solution

Put the below line in path & put your desire title
http://#

Comments

Drupal 6 + Nice Menus

This is the only version that works for me with Nice Menus module... (I also had strange problems when I tried the dummy node approach, so I used the fake url one - in this case I use http://fake.link for every item I do not want to be linkable)

<?php
function themename_menu_item_link($link) {
  if (empty(
$link['localized_options'])) {
   
$link['localized_options'] = array();
  }

  if (!
$link['page_callback'] && strpos( $link['href'], 'fake.link')) {
    return
'<a href="#" class="nolink">'. $link['title'] .'</a>';
  }
  else {
        return
l($link['title'], $link['href'], $link['localized_options']);
  }
}
?>

Note: class nolink is purely optional, but it's good for adding some useful styling like changing the cursor etc.

This version worked for me

This version worked for me (Great work!)

to avoid having the page scroll to the top when clicking on the fake link,
use
javascript:void(0)

instead of the

#
sign
inside of return '

This works & additional improvement

This solution works for nice menus (and other menu's occasions where dummy link needed [?])

A quick additional improvement: insert


onclick="return false"

to the return code for dummy link to become as follows:

<?php
function themename_menu_item_link($link) {
  if (empty(
$link['localized_options'])) {
   
$link['localized_options'] = array();
  }

  if (!
$link['page_callback'] && strpos( $link['href'], 'fake.link')) {
    return
'<a href="#" onclick="return false" class="nolink">'. $link['title'] .'</a>';
  }
  else {
        return
l($link['title'], $link['href'], $link['localized_options']);
  }
}
?>

so dummy link (#) not causing web browser to search whole page for link anchor #

Another improvement

Thanks digitallica - there was a couple things I wanted to add/share to this improvement. When using nice menus, "menu-path-fake.link" is created as a class in each parent li. I don't believe having a period in the class is good form. I also wanted to utilize javascript:void(0) instead of # so that the current URL isn't read into the href (removing an incorrect URL may be better for SEO?), so I made the below modifications and added a new function from the nice menus module to my sub-theme's template.php file.

<?php
/**
* Creates empty menu item when <a href="http://menu.nolink" title="http://menu.nolink" rel="nofollow">http://menu.nolink</a> is added to the menu path.
*/
function THEMENAME_menu_item_link($link) {
  if (empty(
$link['localized_options'])) {
   
$link['localized_options'] = array();
  }

  if (!
$link['page_callback'] && strpos( $link['href'], 'menu.nolink')) {
    return
'<a href="javascript:void(0)" onclick="return false" class="nolink">'. $link['title'] .'</a>';
  }
  else {
        return
l($link['title'], $link['href'], $link['localized_options']);
  }
}

/**
* Helper function that builds the nested lists of a nice menu.
*
* @param $menu
*   Menu array from which to build the nested lists.
*/
function THEMENAME_nice_menu_build($menu) {
 
$output = '';

  foreach (
$menu as $menu_item) {
   
$mlid = $menu_item['link']['mlid'];
   
// Check to see if it is a visible menu item.
   
if ($menu_item['link']['hidden'] == 0) {
     
// Build class name based on menu path
      // e.g. to give each menu item individual style.
      // Strip funny symbols.
     
$clean_path = str_replace(array('http://', '<', '>', '&', '=', '?', ':', 'menu.'), '', $menu_item['link']['href']);
     
// Convert slashes to dashes.
     
$clean_path = str_replace('/', '-', $clean_path);
     
$path_class = 'menu-path-'. $clean_path;
     
// If it has children build a nice little tree under it.
     
if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below']))) {
       
// Keep passing children into the function 'til we get them all.
       
$children = theme('nice_menu_build', $menu_item['below']);
       
// Set the class to parent only of children are displayed.
       
$parent_class = $children ? 'menuparent ' : '';
       
$output .= '<li id="menu-'. $mlid .'" class="'. $parent_class . $path_class .'">'. theme('menu_item_link', $menu_item['link']);
       
// Build the child UL only if children are displayed for the user.
       
if ($children) {
         
$output .= '<ul>';
         
$output .= $children;
         
$output .= "</ul>\n";
        }
       
$output .= "</li>\n";
      }
      else {
       
$output .= '<li id="menu-'. $mlid .'" class="'. $path_class .'">'. theme('menu_item_link', $menu_item['link']) .'</li>'."\n";
      }
    }
  }
  return
$output;
}
?>

Obviously THEMENAME would be the name of your theme. The second function will remove "http://menu." creating the class "menu-path-nolink".

fixed [I can't make this work in D7 and bartik theme]

I installed nice menus and added the code in bartik's template.php
- I then changed the themename to bartik
- cleared all cache (drush cc)
- but I still could not get the menu.nolink url to change to javascript:void(0) after menu was re-displayed.

I also tried the other sample code, and it did not work for me too.

I must be missing some change that must be done. Help.

Drupal's menu system was saving the link as system paths and not url alias. I changed strpos() search string and it worked.

There's a bit of a wrinkle, the parent menu link which is changed with javascript:void(0) may need to be set to 'expanded' and not collapsed.

Thanks.

Works great with Nice Menus

To help other forum wanderers, I'd like to say that the code provided by tekket works great with Nice Menus. Steps for newbies:
1) Copy and paste the code at the very bottom of your theme's template.php file, but remove the <?php and ?> php tags.
2) notice the function name is themename_menu_item_link... You must replace "themename" with the name of your theme. It could look something like garland_menu_item_link($link) after you're finished.
3) Purge the Drupal cache using the button at the bottom of the /admin/settings/performance page.
4) Enter "http://fake.link" as the link destination for menu items that shouldn't be links.

Special thanks to ...

tekket's php snippet combo attack with Bassplaya CSS code

Fantastic solution

This solution worked for me.
It's a workaround, but it sure save lots of time and hassle, therefore it's a winning one!

CSS to the rescue

I know it's not the best but in the worst case scenario:
you could use css by tricking the user to feel that certain links aren't links..
.certain-links a,
.certain-links a:hover {
cursor: default;
text-decoration: none;
}

jQuery really comes to the rescue.

My client discovered this 'bug' and demanded a fix, I found this thread and spent 45 minute reading and digesting this issue. Every solution presented seems to ignore the power of Drupals Behaviors.

Obviously my solution works for me, but it could work for you too. It's a matter of your comfort level with Drupal Behaviors and Themes.

1) find the js included in your theme

For me:

sites/themes/all/<my_theme>/scripts.js

Yours will possibly be parallel, with your theme insted of "<my_theme>"

2) Using some Dom inspector, find the tightest css rule you need to isolate your troublesome 'A' fathers:

For me:

#headerblocks ul.nice-menu.nice-menu-down > li > a

3) Add a behavior at the end of the javascript file:

Drupal.behaviors.theme_<my_theme> = function ()
{
  $('#headerblocks ' +
    'ul.nice-menu.nice-menu-down > ' +
    'li > ' +
    'a:not(.<my_theme>-processed)').attr('href', '#')
                                   .addClass('<my_theme>-processed');
};

As is, this snipit won't work, replace <my_theme> with the name of your theme. Also note that the css selector from step 2 is incorporated in the javascript string there, but we add the text [':not(.<my_theme>-process)'] after the 'a'.

The Javascript here is selecting the father 'A's that aren't yet processed and replacing their href with '#' and marking them as processed.

Voila, quick, correct, and clear.

Some possible problem you might have:

  • You're not using a theme with javascript
  • (my suggestion is to change to one, or modify your theme to do so)

  • You can't find the css selector for your Father 'A'
  • (ummm, I can't give any direct advice on this, ask someone about your site)

  • You want to make the cursor style to change blah blah css stuff
  • (Well the last line of code there is ".addClass('someclass');" add your own and use css for styling

  • You want a leaf node with no link, or you want some other combination of links and not links
  • (If you want other hard to define, or specific items, I think you can use secondary rules in your javascript Behavior to specify them, Since these aren't really likely to be needed on every site, consider this a per-site customization, that way you really give the client what they want.)

  • Finally, note that some clients fear Javascript, if this is true of your clients, then they may still have sucky menus 0.o

Have Fun and Good Luck

Jeff

For Drupal 7...

This worked for me. Thanks.

Note that for Drupal 7, you'll need to declare the .js file in your theme .info file, e.g.:

scripts[] = js/script.js

.. and wrap the code in your .js file like this (CSS selectors adapted for my needs):

(function($){
Drupal.behaviors.theme_<my_theme> = {
attach: function () {
$('#nice-menu-1 ' +
'li.menuparent > ' +
'a:not(.<my_theme>-processed)').attr('href', '#')
                                   .addClass('<my_theme>-processed');
}
};
})(jQuery);

Thank you, this worked for

Thank you, this worked for me.

Page status

Needs updating

Log in to edit this page

About this page

Drupal version
Drupal 5.x, Drupal 6.x, Drupal 7.x
Level
Beginner
Audience
Designers/themers
Keywords
menu, menus

Theming Guide

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.
nobody click here