hook_menu_alter() 用 MENU_NORMAL_ITEM 覆盖 LOCAL_TASK

发布于 2024-10-17 09:34:04 字数 3175 浏览 1 评论 0原文

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

例如,我正在使用 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() 如下,将项目设置为 改为主链接中的 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']));
  }

我的商品没有 ppli。如果确实如此,我们以后就会成为黄金……

  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”是“navigation”。好的,但这对于我想要住在主链接中的菜单项来说没有什么好处。接下来发生的是覆盖...

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

我的问题是,我该如何实现这一点?据我所知,我需要一个 plid,或者创建 plid 的东西。看来这不应该太难。我缺少什么?

I want to override a tab that shows up on the user profile, and make it a menu item in primary links instead.

For example, I'm using the Invite module which defines some menu items, including...

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',
  );
}

Since I want to override that MENU_LOCAL_TASK, I define a
hook_menu_alter() as follows, setting the item to be a
MENU_NORMAL_ITEM in primary links instead.

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';
  }
}

All good so far... I rebuild the menu_router to see the change, and the item does
not appear in primary links.

Stepping through the code, I've discovered that after rebuilding the menu_router, my new
menu item gets run through menu_link_save() (menu.inc). My menu item comes into
this function with primary links set as it's "menu_name". But that gets overwritten
to the "navigation" menu in the following way.

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']));
  }

My item has no plid. If it did, we'd be gold later on...

  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);
  }

So, now we've got a parent, and it's 'user/%', whose "menu_name" is "navigation". Okay, but that's no good for my menu item who wants to live in primary links. What happens next is the overwriting...

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

My question is, how do I accomplish this? From what I can gather, I need a plid, or something that creates a plid. Seems like this shouldn't be super hard. What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

待"谢繁草 2024-10-24 09:34:04

正如您所说:“我需要一个 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。

注意/免责声明:在 hook_menu() 中没有记录明确设置这样的 plid,并且菜单系统在 menu_link_save() 获取之前对 items 数组进行相当多的数据处理被称为,所以:

  • 这可能一开始就行不通,因为 pld 在途中迷路了。
  • 即使这有效,它也可能不可靠和/或有意想不到的副作用。

因此,您可能需要考虑另一种选择,即不通过 hook_menu_alter 创建所需的主链接条目,而是单独使用 menu_link_maintain() (应允许通配符路径)。

As you said: "I need a plid, or something that creates a plid" - So if you want your item to appear at the top level of the primary-links menu, you could try to add a plid of 0 (== no parent == top level entry) in your hook_menu_alter entry:

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;
  }
}

This might do the trick. If you want your item to appear under an existing item of the primary-links menu, you'd obviously need to get the mlid of that existing item fist.

NOTE/DISCLAIMER: Explicitly setting a plid like that is not documented for hook_menu(), and the menu system does quite some data massaging on the items array before menu_link_save() gets called, so:

  • This might not work in the first place, due to the plid getting lost on the way.
  • Even if this works, it might not be reliable and/or have unintended side effects.

So you might want to consider the alternative of creating your desired primary-links entry not by means of hook_menu_alter, but separately using menu_link_maintain() (should allow wildcard paths).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文