hook_menu_alter() 用 MENU_NORMAL_ITEM 覆盖 LOCAL_TASK
我想覆盖用户个人资料上显示的选项卡,并将其作为主链接中的菜单项。
例如,我正在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如您所说:“我需要一个 plid,或者创建 plid 的东西” - 因此,如果您希望您的项目出现在主链接菜单的顶层,您可以尝试添加 0 的 plid(== 否)父==顶级条目)在您的
hook_menu_alter
条目中:这可能会起作用。如果您希望您的项目出现在主链接菜单的现有项目下,则显然需要先获取该现有项目的 mlid。
注意/免责声明:在
hook_menu()
中没有记录明确设置这样的 plid,并且菜单系统在menu_link_save()
获取之前对 items 数组进行相当多的数据处理被称为,所以:因此,您可能需要考虑另一种选择,即不通过
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: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 beforemenu_link_save()
gets called, so:So you might want to consider the alternative of creating your desired primary-links entry not by means of
hook_menu_alter
, but separately usingmenu_link_maintain()
(should allow wildcard paths).