You are here

Tertiary menu block

Submitted by cafuego on 2 October, 2010 - 09:10

… or "how I re-invented the wheel". Again

I found myself needing a tertiary menu in Drupal yesterday, which sadly it doesn't provide by default. There is a primary menu and a secondary menu that can auto-populate based on the primary menu selection, but sadly that's the level at which it stops.

Google helped me find a few blogs that show how to easily generate an arbitrary level sub-menu, though most are for D5 and not D6. Ignacio Segura amended code on this blog that makes it all work for D6:

<?php
$links = menu_navigation_links('primary-links', 2);
$menu = theme('links', $links, array('class' => 'links tertiary-links'));
?>

Yay, that works. If I click on a secondary menu link with children, the $menu variable now contains themed third level menu items.

However, I really want them to be in a block and I want that block to have a title based on the menu item that is the second level menu parent of whatever node or view I'm looking at right now, rather than a hardcoded title or even a third row of links around the top of a page.

I did some searching though the menu API docs, but I couldn't find any particularly useful API calls for accomplishing this. However, when I asked online I was pointed at the {menu_links} table, which contains all menus, paths and their tree structure.

With that information in hand, it was pretty easy to write a function that loops through menu parents until it finds the second level one and returns the title. I can then set this as block title. It looks to be generic-able, so I might work this into a module that provides a Nth level menu blocks at some point in the future. For now, here's the tertiary menu block code:

<?php
/**
* Implementation of hook_block()
*/
function thirdmenu_block($op = 'list', $delta = 0, $edit = array()) {
switch($op) {
case 'list':
$blocks = array();
$blocks[0] = array(
'info' => 'Tertiary Menu',
);
return $blocks;
break;

case 'view':
if ($delta == 0) {
$block = thirdmenu_tertiary_menu();
}
return $block;
break;
}
}

/**
* Function to create a tertiary menu.
* See http://mybesinformatik.com/content/tertiary-menus-drupal
*/
function thirdmenu_tertiary_menu() {
// Grab the menu router entry for the current path.
$item = menu_get_item();

// Grab the menu parent for the current path.
$object = db_fetch_object(db_query("SELECT plid, link_title, depth FROM {menu_links} WHERE link_path = '%s' AND depth > 1", $item['href']));

// Load parents until we've found the item at depth 2, that's the one we want.
while (($object->depth > 1) && !empty($object->plid)) {
$parent = $object;
$result = db_query("SELECT plid, link_title, depth FROM {menu_links} WHERE mlid = %d AND depth > 1", $object->plid);
$object = db_fetch_object($result);
}

// If we found a parent item, produce a tertiary menu block
// and set the block title to the title of the parent item.
if (!empty($parent) && $parent->plid) {
$links = menu_navigation_links('primary-links', 2);
$menu = theme('links', $links, array('class' => 'links tertiary-links'));
$block = array(
'subject' => $parent->link_title,
'content' => $menu,
);
}
// Otherwise, return nothing.
else {
$block = array();
}
return $block;
}
?>

Note: I've since found that the menu_block module also does this. So never mind.