hook_menu_alter()使用MENU_NORMAL_ITEM覆盖LOCAL_TASK

时间:2011-02-16 09:44:57

标签: drupal drupal-6 drupal-modules

我想覆盖显示在用户个人资料上的标签,并将其作为主要链接中的菜单项。

例如,我正在使用Invite模块来定义一些菜单项,包括......

function invite_menu() {

  // bunch of menu items...

  // User profile tabs
  $items['user/%user/invites'] = array(
    'title' => 'Invitations',
    'page callback' => 'invite_user_overview',
    'access callback' => 'invite_user_access',
    'access arguments' => array('track invitations', 1),
    'type' => MENU_LOCAL_TASK,
    'file' => 'invite_admin.inc',
  );
}

因为我想覆盖那个MENU_LOCAL_TASK,所以我定义了一个 hook_menu_alter()如下,将项目设置为a 而是主链接中的MENU_NORMAL_ITEM。

function mymod_menu_alter(&$items) {

  if (!empty($items['user/%user/invites'])) {
    $items['user/%user/invites']['title'] = 'My Override';
    $items['user/%user/invites']['type'] = MENU_NORMAL_ITEM;
    $items['user/%user/invites']['menu_name'] = 'primary-links';
  }
}

到目前为止一切都很好......我重建了menu_router以查看更改,而项目确实如此 不出现在主链接中。

单步执行代码,我发现重建menu_router后,我的新代码 菜单项通过menu_link_save()(menu.inc)运行。我的菜单项进入 此主要链接的功能设置为“menu_name”。但这会被覆盖 以下列方式进入“导航”菜单。

function menu_link_save(&$item) {
  // ...
  // do some stuff
  // ...

    // -----------------------------------------------------------
    // THIS FAILS
    // -----------------------------------------------------------
    if (isset($item['plid'])) {
    $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid']));
  }

我的项目没有plid。如果确实如此,我们以后会成为金子......

  else {
    // Find the parent - it must be unique.
    $parent_path = $item['link_path'];
    $where = "WHERE link_path = '%s'";
    // Only links derived from router items should have module == 'system', and
    // we want to find the parent even if it's in a different menu.

    // -----------------------------------------------------------
    // THIS PASSES, SO ...
    // -----------------------------------------------------------
    if ($item['module'] == 'system') {
      $where .= " AND module = '%s'";
      $arg2 = 'system';
    }
    else {
      // If not derived from a router item, we respect the specified menu name.
      $where .= " AND menu_name = '%s'";
      $arg2 = $item['menu_name'];
    }
    do {

      // -----------------------------------------------------------
      // WE FIND THE PARENT ("user/%")
      // -----------------------------------------------------------
      $parent = FALSE;
      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
      $result = db_query("SELECT COUNT(*) FROM {menu_links} ". $where, $parent_path, $arg2);
      // Only valid if we get a unique result.
      if (db_result($result) == 1) {
        $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} ". $where, $parent_path, $arg2));
      }
    } while ($parent === FALSE && $parent_path);
  }

所以,现在我们有一个父母,它是'user /%',其“menu_name”是“导航”。好的,但这对我想要住在主链接的菜单项来说并不好。接下来会发生的是覆盖......

  if ($parent !== FALSE) {
    $item['menu_name'] = $parent['menu_name'];
  }

我的问题是,我该如何做到这一点?从我可以收集的东西,我需要一个plid,或创建一个plid的东西。这似乎不应该是超级难的。我错过了什么?

1 个答案:

答案 0 :(得分:2)

正如你所说:“我需要一个plid,或者创建一个plid的东西” - 所以如果你想让你的项目出现在主链接菜单的顶层,你可以尝试添加一个0的plid( hook_menu_alter条目中的==无父==顶级条目:

function mymod_menu_alter(&$items) {

  if (!empty($items['user/%user/invites'])) {
    $items['user/%user/invites']['title'] = 'My Override';
    $items['user/%user/invites']['type'] = MENU_NORMAL_ITEM;
    $items['user/%user/invites']['menu_name'] = 'primary-links';
    $items['user/%user/invites']['plid'] = 0;
  }
}

这可能会成功。如果您希望项目显示在主链接菜单的现有项目下,您显然需要获得该现有项目的mlid。

注意/免责声明:明确设置类似的plid没有记录hook_menu(),并且菜单系统在调用menu_link_save()之前对items数组进行了一些数据按摩,因此:

  • 这可能不会起作用,因为在途中会丢失。
  • 即使这有效,也可能不可靠和/或产生意想不到的副作用。

因此,您可能希望考虑使用hook_menu_alter创建所需主要链接条目的替代方法,而是单独使用menu_link_maintain()(应允许使用通配符路径)。