如何为菜单项添加访问条件?


17

如何在确定菜单项是否可见的现有条件之上添加新条件?这些条件不应限于权限设置。

作为一个示例用例(不一定是这个问题的原因):假设我有一个内容类型,其中只允许用户创建一个节点。我有一个菜单项用于添加该类型的内容。但是,如果用户已经创建了该内容类型的节点,那么我想隐藏菜单项。我的第一个想法是运行查询以检查当前用户创建的特定内容类型的节点是否存在。如果存在,请隐藏菜单项。

我认为这种功能应该加入其中hook_menu_alter()并添加所需的逻辑。但是我不确定在不绕过现有检查的情况下如何做到这一点,例如检查用户是否有权创建该类型的内容。我是否必须在自己的情况下包括该逻辑?还是可以在不覆盖现有访问逻辑的情况下添加它?


编辑:有些人似乎专注于回答“如何限制用户创建内容类型的一个节点”。这不是这里的问题。问题是如何向菜单项添加自定义访问条件。

Answers:


11

您需要做的是通过hook_menu_alter()添加回调,然后在回调内部简单地执行逻辑,然后通过原始回调返回数据。

为了确保您不会覆盖任何其他hook_menu_alter()更改,您应该通过access参数将先前的回调传递给您的回调。

这完全是理论上的,但是代码应该是这样的:

MYMODULE_menu_alter(&$items) {
  $items['menu']['access arguments'] = array_merge(array($items['menu']['access callback']), $item['menu']['access arguments']);
  $items['menu']['access callback'] = 'MYMODULE_access_callback';
}

MYMODULE_access_callback() {
  $args = func_get_args();

  // Do Stuff.
  if ($something == FALSE) {
    return FALSE;
  }

  $function = array_shift($args);
  return call_user_func_array($function, $args);
}

因此,如果我分配一个新的访问回调函数,那肯定会覆盖原始回调吗?
Chaulky 2011年

是的,每个菜单项只能有一个访问回调,因此请确保您返回原始回调。我看过一个模块,它执行类似这样的操作,其中一个权限很重的模块却无法记住哪个模块。
Decipher

$ args上的array_shift是做什么的?
2011年

它从“访问参数”中取出第一个参数,我们将其制成旧的“访问回调”。因此,如果旧的回调是“ MYMODULE2_access_callback”,则这是array_shift返回的内容。它还会将其从数组中删除,以便我们仅传递回调期望的参数。
解密,

1

针对以上评论,D7中的解决方案将使用:

/**
 * Implements hook_node_access().
 */
function mymodule_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if ($op == 'create' && $type == 'mynodetype' && db_query("SELECT 1 FROM {node} WHERE type = :type AND uid = :uid", array(':type' => $type, ':uid' => $account->uid))->fetchField()) {
    // If the user has already created a node of a specific type, they cannot
    // create any more.
    return NODE_ACCESS_DENY;
  }

  // Otherwise do not affect any node access.
  return NODE_ACCESS_IGNORE;
}

1
这似乎与菜单项没有任何关系。我对D7不太熟悉,但是看起来这是特定于节点创建的。问题主要集中在菜单项上。
Chaulky 2011年

哦,我知道了...这是对我的评论的回应,该评论要求您在答案中建议的有关D7解决方案的更多详细信息,该解决方案指向“节点限制”模块。仍然没有话题,但赞赏。
Chaulky 2011年

因为创建mynodetype链路的可见性由node_access()函数,该函数将调用此钩在Drupal 7控制
戴夫里德

1

您正在寻找Chain Menu Access API模块。

链接菜单访问API允许您的模块将其自己的菜单访问回调函数链接到其他模块的菜单路由器条目中。

在Drupal Stack Exchange上至少有一个有关如何使用它的示例


-1

一种选择是创建一个对您的内容类型具有创建内容权限的新角色。用户创建该类型的节点后,取消该角色,他们将无法再创建任何角色。


-1

也许您应该尝试“ 节点限制”模块。

从项目页面:

节点限制模块允许管理员限制角色或用户可以创建的特定类型的节点数量。例如,如果站点具有可以创建“广告”节点的“广告商”角色,则节点限制管理员可以将该角色中的所有用户限制为特定数目的节点。他还可以基于每个用户限制用户。


限制为一个节点只是添加自定义访问回调方法的一个示例用例。另外,“节点限制”不会删除菜单项,而只是阻止用户添加该内容类型的另一个节点。
Chaulky 2011年

现在,我再次查看模块描述,这是事实。如果在Drupal 7上使用,则实际上很容易,因为您可以使用hook_node_access($ node,'create',$ account),这会影响create node type链接本身的可见性。
Dave Reid

那很有意思。我确实打算尽快移至D7。您介意更详细地编写并发布答案吗?
Chaulky 2011年

D7版本的答案贴出来了。
Dave Reid
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.