获取菜单链接的同级


11

我正在尝试在Drupal 8中创建一个菜单,它只是当前页面的同级链接。因此,如果菜单为:

  • 父母1
    • 子父母1
      • 儿童1
    • 子父母2
      • 儿童2
      • 儿童3
      • 儿童4
  • 父母2

当我在“儿童3”页面上时,我想要一个菜单​​块链接如下所示:

  • 儿童2
  • 儿童3
  • 儿童4

我想我知道如何在D7中做到这一点,但是我很难将这些知识转化为D8。这甚至在D8中可行吗?如果是的话,有人可以为我指出正确的方法吗?

谢谢!

说明:子级别需要可变,以便具有不同深度的菜单项可以显示其同级。因此,例如,除了要为孩子们​​准备菜单外,我还需要为父母父母提供菜单,为父母提供菜单等。我也无法控制/了解菜单的深度以及所有部分的深度。

Answers:


19

因此,我最终通过创建一个自定义块并在build方法中输出带有添加了转换器的菜单的方式,找出了一些可以使我做到这一点的代码。这是我用来弄清楚如何在块中获取菜单并向其中添加转换器的链接:http : //alexrayu.com/blog/drupal-8-display-submenu-block。我build()最终看起来像这样:

$menu_tree = \Drupal::menuTree();
$menu_name = 'main';

// Build the typical default set of menu tree parameters.
$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);

// Load the tree based on this set of parameters.
$tree = $menu_tree->load($menu_name, $parameters);

// Transform the tree using the manipulators you want.
$manipulators = array(
  // Only show links that are accessible for the current user.
  array('callable' => 'menu.default_tree_manipulators:checkAccess'),
  // Use the default sorting of menu links.
  array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
  // Remove all links outside of siblings and active trail
  array('callable' => 'intranet.menu_transformers:removeInactiveTrail'),
);
$tree = $menu_tree->transform($tree, $manipulators);

// Finally, build a renderable array from the transformed tree.
$menu = $menu_tree->build($tree);

return array(
  '#markup' => \Drupal::service('renderer')->render($menu),
  '#cache' => array(
    'contexts' => array('url.path'),
  ),
);

该转换器是一项服务,因此我intranet.services.yml在自己的Intranet模块中添加了一个,指向最终定义的类。该类具有以下三种方法:removeInactiveTrail(),调用该方法getCurrentParent()以获取用户当前所在页面的父级,以及stripChildren(),该方法将菜单剥离为仅当前菜单项及其同级项的子项(即:删除了所有不属于该子菜单的子菜单)。 t在活动路径中)。

看起来像这样:

/**
 * Removes all link trails that are not siblings to the active trail.
 *
 * For a menu such as:
 * Parent 1
 *  - Child 1
 *  -- Child 2
 *  -- Child 3
 *  -- Child 4
 *  - Child 5
 * Parent 2
 *  - Child 6
 * with current page being Child 3, Parent 2, Child 6, and Child 5 would be
 * removed.
 *
 * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
 *   The menu link tree to manipulate.
 *
 * @return \Drupal\Core\Menu\MenuLinkTreeElement[]
 *   The manipulated menu link tree.
 */
public function removeInactiveTrail(array $tree) {
  // Get the current item's parent ID
  $current_item_parent = IntranetMenuTransformers::getCurrentParent($tree);

  // Tree becomes the current item parent's children if the current item
  // parent is not empty. Otherwise, it's already the "parent's" children
  // since they are all top level links.
  if (!empty($current_item_parent)) {
    $tree = $current_item_parent->subtree;
  }

  // Strip children from everything but the current item, and strip children
  // from the current item's children.
  $tree = IntranetMenuTransformers::stripChildren($tree);

  // Return the tree.
  return $tree;
}

/**
 * Get the parent of the current active menu link, or return NULL if the
 * current active menu link is a top-level link.
 *
 * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
 *   The tree to pull the parent link out of.
 * @param \Drupal\Core\Menu\MenuLinkTreeElement|null $prev_parent
 *   The previous parent's parent, or NULL if no previous parent exists.
 * @param \Drupal\Core\Menu\MenuLinkTreeElement|null $parent
 *   The parent of the current active link, or NULL if not parent exists.
 *
 * @return \Drupal\Core\Menu\MenuLinkTreeElement|null
 *   The parent of the current active menu link, or NULL if no parent exists.
 */
private function getCurrentParent($tree, $prev_parent = NULL, $parent = NULL) {
  // Get active item
  foreach ($tree as $leaf) {
    if ($leaf->inActiveTrail) {
      $active_item = $leaf;
      break;
    }
  }

  // If the active item is set and has children
  if (!empty($active_item) && !empty($active_item->subtree)) {
    // run getCurrentParent with the parent ID as the $active_item ID.
    return IntranetMenuTransformers::getCurrentParent($active_item->subtree, $parent, $active_item);
  }

  // If the active item is not set, we know there was no active item on this
  // level therefore the active item parent is the previous level's parent
  if (empty($active_item)) {
    return $prev_parent;
  }

  // Otherwise, the current active item has no children to check, so it is
  // the bottommost and its parent is the correct parent.
  return $parent;
}


/**
 * Remove the children from all MenuLinkTreeElements that aren't active. If
 * it is active, remove its children's children.
 *
 * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
 *   The menu links to strip children from non-active leafs.
 *
 * @return \Drupal\Core\Menu\MenuLinkTreeElement[]
 *   A menu tree with no children of non-active leafs.
 */
private function stripChildren($tree) {
  // For each item in the tree, if the item isn't active, strip its children
  // and return the tree.
  foreach ($tree as &$leaf) {
    // Check if active and if has children
    if ($leaf->inActiveTrail && !empty($leaf->subtree)) {
      // Then recurse on the children.
      $leaf->subtree = IntranetMenuTransformers::stripChildren($leaf->subtree);
    }
    // Otherwise, if not the active menu
    elseif (!$leaf->inActiveTrail) {
      // Otherwise, it's not active, so we don't want to display any children
      // so strip them.
      $leaf->subtree = array();
    }
  }

  return $tree;
}

这是最好的方法吗?可能不是。但这至少为需要执行类似操作的人员提供了起点。


这几乎是footermap所做的。+1用于使用menu.tree服务。
mradcliffe '16

2
您能否告诉应该在service.yml文件中放置什么代码?如何从service.yml文件指向一个类?
siddiq

如何排除上级菜单链接?
Permana

3

Drupal 8具有内置的菜单块功能,您唯一要做的就是在Block Ui中创建一个新的菜单块并进行配置。

发生这种情况的原因是:

  • 放置一个新块,然后选择要为其创建块的菜单。
  • 在块组态中,必须将“初始菜单级别”选择为3。
  • 如果您只想从第三级打印菜单项,则可能还需要将“要显示的最大菜单级别数”设置为1。

不幸的是,我不确定页面将位于哪个级别,因此我不能仅为其创建菜单块。还可能需要将其设置为可变级别,具体取决于站点结构最终的状态。
艾琳·麦克劳克林

Drupal 8的menu_block当前不包含用于跟随当前节点的功能,此处有修补程序;drupal.org/node/2756675
基督教徒

可以静态使用。但是不能像“在每个页面上放置一个块并显示当前页面的同级结构,而不管您当前处于何种级别”中那样动态使用。
leymannx

3

在当前链接上设置根目录可以达到以下目的:

$menu_tree = \Drupal::menuTree();
$menu_name = 'main';

$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
$currentLinkId = reset($parameters->activeTrail);
$parameters->setRoot($currentLinkId);
$tree = $menu_tree->load($menu_name, $parameters);

// Transform the tree using the manipulators you want.
$manipulators = array(
  // Only show links that are accessible for the current user.
  array('callable' => 'menu.default_tree_manipulators:checkAccess'),
  // Use the default sorting of menu links.
  array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
);
$tree = $menu_tree->transform($tree, $manipulators);

不,这仅显示儿童。但不是兄弟姐妹。OP希望有兄弟姐妹。
leymannx

3

兄弟姐妹菜单块

借助@Icubes答案,MenuLinkTreeInterface::getCurrentRouteMenuTreeParameters我们可以简单地获取当前路线的活动菜单轨迹。有了它,我们还有父菜单项。将其设置为开始MenuTreeParameters::setRoot构建新树的起点将为您提供所需的同级菜单。

// Enable url-wise caching.
$build = [
  '#cache' => [
    'contexts' => ['url'],
  ],
];

$menu_name = 'main';
$menu_tree = \Drupal::menuTree();

// This one will give us the active trail in *reverse order*.
// Our current active link always will be the first array element.
$parameters   = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
$active_trail = array_keys($parameters->activeTrail);

// But actually we need its parent.
// Except for <front>. Which has no parent.
$parent_link_id = isset($active_trail[1]) ? $active_trail[1] : $active_trail[0];

// Having the parent now we set it as starting point to build our custom
// tree.
$parameters->setRoot($parent_link_id);
$parameters->setMaxDepth(1);
$parameters->excludeRoot();
$tree = $menu_tree->load($menu_name, $parameters);

// Optional: Native sort and access checks.
$manipulators = [
  ['callable' => 'menu.default_tree_manipulators:checkNodeAccess'],
  ['callable' => 'menu.default_tree_manipulators:checkAccess'],
  ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
];
$tree = $menu_tree->transform($tree, $manipulators);

// Finally, build a renderable array.
$menu = $menu_tree->build($tree);

$build['#markup'] = \Drupal::service('renderer')->render($menu);

return $build;

这个解决方案像一个魅力。:)
Pankaj Sachdeva
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.