Então, acabei descobrindo algum código que me permitia fazer isso, criando um bloco personalizado e, no método build, exibindo o menu com os transformadores adicionados a ele. Este é o link que eu usei para descobrir como obter o menu no bloco e adicionar transformadores a ele: http://alexrayu.com/blog/drupal-8-display-submenu-block . Meu build()
acabou ficando assim:
$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'),
),
);
O transformador é um serviço, então adicionei um intranet.services.yml
ao meu módulo da intranet, apontando para a classe que acabei definindo. A classe tinha três métodos: removeInactiveTrail()
chamado getCurrentParent()
para obter o pai da página em que o usuário estava atualmente e stripChildren()
que reduzia o menu apenas para os filhos do item de menu atual e seus irmãos (por exemplo: removeu todos os submenus que não estavam ' t na trilha ativa).
Isto é o que parecia:
/**
* 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;
}
Esse é o melhor jeito de fazer isso? Provavelmente não. Mas pelo menos fornece um ponto de partida para pessoas que precisam fazer algo semelhante.
O Drupal 8 tem a funcionalidade do Bloco de menus integrada no núcleo. O que você precisa fazer é criar um novo bloco de menus na interface do usuário do bloco e configurá-lo.
Isso acontece por:
fonte
Definir a raiz no link atual pode fazer os truques:
fonte
Bloco de menu Irmãos
Com a ajuda da resposta do @Icubes
MenuLinkTreeInterface::getCurrentRouteMenuTreeParameters
, podemos simplesmente obter a trilha do menu ativo da rota atual. Tendo isso, também temos o item de menu principal. Definir isso como ponto de partidaMenuTreeParameters::setRoot
para criar uma nova árvore fornece o menu de irmãos desejado.fonte