Disclaimer
Technically menu content isn't a theming issue per se, but this chapter seems like the best fit for the topic.
The Problem
Unfortunately, it's impossible to create a Drupal menu item that doesn't link to a page. Consider a hierarchical menu like ours:
- Home
- How to Begin
- Recreational
- The Aerobatic Box
- Aerobatic Schools
- etc.
- Programs
- Local Chapters
- Chapter Locator
- Chapter Resources
- Judges Schools
- Calendar
- Courses
- Exams
- etc.
- etc.
- Local Chapters
- etc.
What should the user see when they click on How to Begin? We could (and did) create a general page about how to get started in aerobatics. Unfortunately such pages are easily overlooked by users who don't expect a top- or mid-level menu item to be associated with a page. Many other web sites present a page consisting of links to the various sub-pages (Recreational, The Aerobatic Box, etc.), and that's the approach we've decided to take.
The Solution
I created a "Basic Page" node named menu-links that automatically reads the menu contents and builds a corresponding page of sub-links. It takes a URL parameter in the form m=<Menu Item Title>, where <Menu Item Title> must exactly match the menu item itself, e.g. http://www.iac.org/menu-links?m=How to Begin. Important: No two menu top- or mid-level menus may have the same title because the PHP code displays the sub-links for the first match it finds. However it's OK to duplicate titles for menu items that have no children (aka "leaf nodes".)
Here's the PHP code. I'll let the embedded comments speak for themselves.
<?php // Do nothing unless URL parameter 'm' is supplied, e.g. www.iac.org/menu-links?m=Programs if (!isset($_GET['m'])) return; // Get the menu link ID associated with the menu named in the 'm' URL parameter // Note: We could error-check here, but we don't $res = db_query("SELECT mlid FROM menu_links WHERE menu_name = 'main-menu' AND link_title = :title LIMIT 1", array(':title' => $_GET['m']))->fetchObject(); // Get the paths to the menu items whose parent is the menu link ID we extracted in the previous query, // sorted by weight (so the order of the bullet list items will match the menu) $r2 = db_query("SELECT link_path, link_title FROM menu_links WHERE plid = :mlid ORDER BY weight", array(':mlid' => $res->mlid)); // Modify the page ititle drupal_set_title("Menu: " . $_GET['m']); // Start the bullet list print "<ul>\n"; // Loop through the menu items foreach ($r2 as $item) { // Link paths are in the form "node/nnnn", where nnnn is a node number (nid). // Split the path at the slash $pes = explode('/', $item->link_path); // Find the node title if ($pes[0] == "node") { // internal link, use node title $t = db_query("SELECT title FROM node WHERE nid = :nid LIMIT 1", array(':nid' => $pes[1]))->fetchObject(); $t = $t->title; } else { // external link, use menu title $t = $item->link_title; } // Find the node alias $a = db_query("SELECT alias FROM url_alias WHERE source = :path LIMIT 1", array(':path' => $item->link_path))->fetchObject(); // Generate a bullet item consisting of the node title, which is hyperlinked to the page // Note that some links (e.g. external pages) don't have an alias, hence the "ternary if" statement print "<li><a href='" . ($a ? $a->alias : $item->link_path) . "'>" . $t . "</a></li>\n"; } // Close the bullet list print "</ul>\n"; ?>