1

Say I need to have the same menu item appear in two different menu trees or at two different level of the same menu. How do I properly "duplicate" a menu item using hook_menu()?

To my understanding, if the original item has its path corporate/contact-us, then putting in the hook_menu() the same path will override the original rather than create a copy. Am I right? How do I clone, or should I say: alias, a menu item programmatically?

(And I need to do that for each language defined for my site.)


I have used this piece of code, using hook_menu_alter() which for some reason did not work; once an item has been created it did not change its label and produced buggy, combined paths (/en/polish/path). Hence the attempt to unset the custom item first.

function MYMODULE_menu_alter(&$items) {
  global $language;

  $custom_items = array(
    'pl' => 'firma/kontakt',
    'en' => 'corporate/contact-us',
  );

  foreach($custom_items as $langcode => $path) {
    unset($items[$path]);
  }

  switch ($language->language) {
    case 'en':
      $items['corporate/contact-us'] = array(
        'title' => 'Contact Us',
        'page callback' => 'node_load',
        'page arguments' => array(285),
        'access callback' => TRUE,
        'menu_name' => 'main-menu',
        'type' => MENU_NORMAL_ITEM,
      );
      break;

    case 'pl':
      $items['firma/kontakt'] = array(
        'title' => 'Kontakt',
        'page callback' => 'node_load',
        'page arguments' => array(286),
        'access callback' => TRUE,
        'menu_name' => 'main-menu',
        'type' => MENU_NORMAL_ITEM,
      );
      break;
  }
}

Similarly, the following hook_menu approach did not work for me, with similar problems. This one was even worse in that the 'fake paths' with '2' in the title where visible to the user in the status bar.

function sint_newsnavi_menu() {
  global $language;

  switch($language->language){
  case 'en':
    $items['corporate/contact-us2'] = array(
      'title' => 'Contact Us',
      'page callback' => 'drupal_goto',
      'page arguments' => array('node/285'),
      'access callback' => TRUE,
      'menu_name' => 'main-menu',
      'type' => MENU_NORMAL_ITEM,
    );
    break;
  case 'pl':
    $items['firma/kontakt2'] = array(
      'title' => 'Kontakt',
      'page callback' => 'drupal_goto',
      'page arguments' => array('node/286'),
      'access callback' => TRUE,
      'menu_name' => 'main-menu',
      'type' => MENU_NORMAL_ITEM,
    );
    break;
  }
  return $items;
}
1
  • Giving it a fresh thought, I wonder if having a separate Main Menu for every enabled language would be a good solution. OTOH, if it were, why does the core UI create a menu item's translation within the same menu tree? – Artur Dec 13 '12 at 15:01
1

The code that works in any case, whatever corporate/contact-us is a view, a menu item defined from another module in its hook_menu(), or a path alias for a node, is similar to the following one.

function mymodule_menu() {
  $items['the menu path you prefer'] = array(
    'page callback' => 'mymodule_page_callback',
     // …
  );

  return $items;
}

function mymodule_page_callback() {
  drupal_goto('corporate/about-us');
}

The only problem with this code is that it could redirect users to a page to which they could not have access, and for which they would get an access denied error. If the users don't have access to a menu item, the menu item should be hidden to them, and that can be done by adding the right access callback to the menu item.

function mymodule_menu() {
  $items['the menu path you prefer'] = array(
    'page callback' => 'mymodule_page_callback',
    'access callback' => 'mymodule_access_callback',
     // …
  );

  return $items;
}

function mymodule_page_callback() {
  drupal_goto('corporate/about-us');
}

function mymodule_access_callback() {
  if ($router_item = menu_get_item('corporate/about-us') && !empty($router_item['access'])) {
    return $router_item['access']);
  }

  return FALSE;
}

In this case, the access callback just checks the users have access to the menu item to which they are going to be redirected.

1
  • Thanks for an elaborate answer. I will try your code, adding necessary language switches. Meanwhile I have been trying the code which I'm adding below (so to be able to use code formatting). – Artur Dec 11 '12 at 23:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.