Tertiary menu in Drupal 6

Short URL: http://fsmsh.com/2817


By default, Drupal allows you to set a "primary" menu and a "secondary" menu. At this point you should know that if you go to admin-> menus -> settings and pick the same menu for both primary and secondary links, the secondary links menu will contain the sub-menu of the selected item in the primary menu.

What happens if you have three levels of menus?

Problem: the lack of a tertiary menu

What happens if you have three levels of menus? For example, what happens if your menu looks like this:

  • One
    • One one
    • --One one A
    • --One one B
    • --One one C
    • One two
    • --One two A
    • --One two B
    • One three
    • --One three A
    • --One three B
  • Two
    • Two one
    • --Two one A
    • --Two one B

...ecc.? PHPTemplate will create a two nice variables for you, $primary_links and secondary_links. Also, $secondary_links will contain the "right" entries if you set the primary menu and the secondary menu the same. What about $tertiary_links? Nowhere to be seen.

Searching for a solution

If you search the forums about this topic, you will find the most diverse solutions. They all take considerable efforts. The first question you want to ask is: how does the template generate those links? If you look at themes/engines/phptemplate/phptemplate.engine, and look for the string primary_links, you will find:

'primary_links'       => menu_primary_links(),
'secondary_links'     => menu_secondary_links(),

If you search Drupal's codebase for those functions:

# grep -il menu_primary_links `find .`

Ah! Menu.inc seems to be the way to go. The first function you find is:

 * Returns an array containing the primary links.
 * Can optionally descend from the root of the Primary links menu towards the
 * current node for a specified number of levels and return that submenu.
 * Used to generate a primary/secondary menu from different levels of one menu.
function menu_primary_links($start_level = 1, $pid = 0) {

This is probably a little complex for a non-programmer. However, menu_secondary_links() really gives everything away:

 * Returns an array containing the secondary links.
 * Secondary links can be either a second level of the Primary links
 * menu or generated from their own menu.
function menu_secondary_links() {
  $msm = variable_get('menu_secondary_menu', 0);
  if ($msm == 0) {
    return NULL;

  if ($msm == variable_get('menu_primary_menu', 0)) {
    return menu_primary_links(2, $msm);

  return menu_primary_links(1, $msm);

The second if is obviously checking if primary and secondary links come from the same menu. If they are, then it just prints them out.

So, you can assume that this:

menu_primary_links(3, variable_get('menu_primary_menu', 0) );

Will return the "tertiary" menu!

The last piece of the puzzle is the rendering. FOr that, just see what any theme does:

<?php print theme('links', $primary_links, array('class' => 'links primary-links')) ?>

The solution

At this point, the solution should be clear. Just type:

$m=menu_primary_links(3, variable_get('menu_primary_menu', 0) );
print theme('links', $m, array('class' => 'links tertiary-links'));

Anywhere, and you will get your "tertiary links"! You can place this code in a block, or in the template directly.


  • Make sure that the secondary menus are "expanded"
  • Make sure you have <?php and ?> around the code


xiffy's picture
Submitted by xiffy on

Thanks for the clear explanation. Unfortunatly, every new drupal version needs revision of almost any hacks. No exception for this one.
To get the tertiary links in Drupal 6 you would do
$m = menu_navigation_links(variable_get('menu_primary_links_source', 'primary-links'), 2);
because menu_primay_links() has lost it's footprint in Drupal 6

theneemies@drupal.org's picture

This site looks like a great Drupal implementation - have you considered submitting a case study for drupal.org?

Also, a usability tip - if you're posting code http://drupal.org/project/geshifilter might be of use.

dener's picture
Submitted by dener on

tnx for the explanation. But I've encountered the following problem; the script seems to place the entire tertiary menu under the secondary instead of placing it in between the chosen menu-items. anyone any idea what might be the reason?

Author information

Tony Mobily's picture


Tony is the founder and the Editor In Chief of Free Software Magazine