Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Drupal Menu Hell(p)

Parent Feed: 

I recently had to implement what seemed like a very simple feature for a client, moving several of the local tasks located on a user's profile page into the site's primary menu. The menu paths in question are dynamic, E.g, /user/%/edit, /user/%/orders, /user/%/notifications, etc., which at first seemed like slight complication. So how to tackle this? At first blush, one might think that you can just use the Menu module to add a dynamic menu item though the GUI or menu API. Well, that won't work. You can only create a menu item that way for an existing path that you have access to. Luckily, Drupal provides a hook that seems like the perfect solution,

<?php
function hook_menu_alter(&$items) {
 
// Example - disable the page at node/add
 
$items['node/add']['access callback'] = FALSE;
}
?>

Great, so I can change the type of the menu items I want to alter by doing something like the code below and problem solved!

<?php
function mymodule_menu_alter(&$items) {
 
$items['user/%user/edit']['type'] = MENU_NORMAL_ITEM;
}
?>

WRONG! At least that's what I realized after much trial and error. Turns out that menu items with wildcards will NOT now show up in the menu tree, and there are no warnings or explanations to that effect. I never found that documented anywhere, only came across it in my trusty copy of Pro Drupal Development, along with following some trails in the code and on another blog post. But that's not where the confusion ends, because menu items with wildcards can appear in the menu tree if the wildcard is a function name that ends with to_arg, e.g., user/%user_uid_optional, and user_uid_optional_to_arg() can be found in user.module. So I'm getting closer, but how do I change those menu items since they don't have one of those nifty to_arg() wildcards? Well, I couldn't think of a way, so in the end, I created my own menu items using user_uid_optional_to_arg() as the placeholder. The code looks something like this,

<?php
function mymodule_menu() {
 
$items['mymodule/orders/%user_uid_optional'] = array(
   
'title' => 'My Orders',
   
'page callback' => '_mymodule_reroute',
   
'page arguments' => array(2, 1),
   
'access callback' => '_mymodule_access_account',
   
'access arguments' => array(2),
   
'type' => MENU_NORMAL_ITEM,
   
'menu_name' => 'primary-links'
 
);
 
$items['mymodule/notifications/%user_uid_optional'] = array(
   
'title' => 'Notifications',
   
'page callback' => '_mymodule_reroute',
   
'page arguments' => array(2, 1),
   
'access callback' => '_mymodule_access_account',
   
'access arguments' => array(2),
   
'type' => MENU_NORMAL_ITEM,
   
'menu_name' => 'primary-links'
 
);
 
$items['mymodule/recurring-fees/%user_uid_optional'] = array(
   
'title' => 'Recurring Fees',
   
'page callback' => '_mymodule_reroute',
   
'page arguments' => array(2, 1),
   
'access callback' => '_mymodule_access_account',
   
'access arguments' => array(2),
   
'type' => MENU_NORMAL_ITEM,
   
'menu_name' => 'primary-links'
 
); 
}function
_mymodule_util_reroute($user, $tab) {
 
drupal_goto('user/'. $user->uid .'/'. $tab, NULL, NULL);
}
?>

Notice the simple and, in my opinion, hack-ish reroute function that actually directs users to the correct destination. In many ways, this is duplicate code, not resilient in the face of changes in other modules, and the href on the new links doesn't match the final destination. Since in this case these links are only available for authenticated users, I'm not worried about SEO implications. So that's my solution to the simple problem of adding some account related links to the primary menu, and I don't like it one bit (even though I burned way too much time on it!). Are there better approaches? I hope so, feedback welcome!

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web