diff --git a/core/modules/navigation/navigation.api.php b/core/modules/navigation/navigation.api.php index 0a595da8cb37b34e853fcf7d261650a9b119686f..92bc62ca2a400617207d36c943406af52e34c956 100644 --- a/core/modules/navigation/navigation.api.php +++ b/core/modules/navigation/navigation.api.php @@ -88,6 +88,30 @@ function hook_navigation_defaults(): array { return $blocks; } +/** + * Alter the content of a given Navigation menu link tree. + * + * @param array &$tree + * The Navigation link tree. + * + * @see \Drupal\navigation\Menu\NavigationMenuLinkTree::transform() + */ +function hook_navigation_menu_link_tree_alter(array &$tree): void { + foreach ($tree as $key => $item) { + // Skip elements where menu is not the 'admin' one. + $menu_name = $item->link->getMenuName(); + if ($menu_name != 'admin') { + continue; + } + + // Remove unwanted Help menu link. + $plugin_id = $item->link->getPluginId(); + if ($plugin_id == 'help.main') { + unset($tree[$key]); + } + } +} + /** * @} End of "addtogroup hooks". */ diff --git a/core/modules/navigation/navigation.services.yml b/core/modules/navigation/navigation.services.yml index 5393be82b14ed1e84ff622776fd01cf492d72ad7..88b6826409a242b3bc74be8a1dcd84eb8b6832ed 100644 --- a/core/modules/navigation/navigation.services.yml +++ b/core/modules/navigation/navigation.services.yml @@ -28,6 +28,7 @@ services: '@router.route_provider', '@menu.active_trail', '@callable_resolver', + '@module_handler', ] navigation.entity_route_helper: diff --git a/core/modules/navigation/src/Hook/NavigationHooks.php b/core/modules/navigation/src/Hook/NavigationHooks.php index 8b2cd686bdcdc6368bc390b75d8ab671c9c90629..11bf1773dfe365b9b410c9995bc5adea6a8ae1a0 100644 --- a/core/modules/navigation/src/Hook/NavigationHooks.php +++ b/core/modules/navigation/src/Hook/NavigationHooks.php @@ -152,8 +152,6 @@ public function menuLinksDiscoveredAlter(&$links): void { $navigation_links = \Drupal::classResolver(NavigationContentLinks::class); assert($navigation_links instanceof NavigationContentLinks); $navigation_links->addMenuLinks($links); - $navigation_links->removeAdminContentLink($links); - $navigation_links->removeHelpLink($links); } /** @@ -291,4 +289,24 @@ public function modulesInstalled(array $modules, bool $is_syncing): void { } } + /** + * Implements hook_navigation_menu_link_tree_alter(). + */ + #[Hook('navigation_menu_link_tree_alter')] + public function navigationMenuLinkTreeAlter(array &$tree): void { + foreach ($tree as $key => $item) { + // Skip elements where menu is not the 'admin' one. + $menu_name = $item->link->getMenuName(); + if ($menu_name != 'admin') { + continue; + } + + // Remove unwanted Help and Content menu links. + $plugin_id = $item->link->getPluginId(); + if ($plugin_id == 'help.main' || $plugin_id == 'system.admin_content') { + unset($tree[$key]); + } + } + } + } diff --git a/core/modules/navigation/src/Menu/NavigationMenuLinkTree.php b/core/modules/navigation/src/Menu/NavigationMenuLinkTree.php index e01f5748edfcacc40144feaf357589c8c9e2e7ad..ca45eb581d94a6aae837dd65b48bf70195103062 100644 --- a/core/modules/navigation/src/Menu/NavigationMenuLinkTree.php +++ b/core/modules/navigation/src/Menu/NavigationMenuLinkTree.php @@ -4,7 +4,13 @@ namespace Drupal\navigation\Menu; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Menu\MenuActiveTrailInterface; +use Drupal\Core\Menu\MenuLinkManagerInterface; use Drupal\Core\Menu\MenuLinkTree; +use Drupal\Core\Menu\MenuTreeStorageInterface; +use Drupal\Core\Routing\RouteProviderInterface; +use Drupal\Core\Utility\CallableResolver; /** * Extends MenuLinkTree to add specific theme suggestions for the navigation. @@ -13,6 +19,33 @@ */ final class NavigationMenuLinkTree extends MenuLinkTree { + /** + * Constructs a \Drupal\navigation\Menu\NavigationMenuLinkTree object. + * + * @param \Drupal\Core\Menu\MenuTreeStorageInterface $treeStorage + * The menu link tree storage. + * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager + * The menu link plugin manager. + * @param \Drupal\Core\Routing\RouteProviderInterface $routeProvider + * The route provider to load routes by name. + * @param \Drupal\Core\Menu\MenuActiveTrailInterface $menuActiveTrail + * The active menu trail service. + * @param \Drupal\Core\Utility\CallableResolver $callableResolver + * The callable resolver. + * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler + * The module handler. + */ + public function __construct( + MenuTreeStorageInterface $treeStorage, + MenuLinkManagerInterface $menuLinkManager, + RouteProviderInterface $routeProvider, + MenuActiveTrailInterface $menuActiveTrail, + CallableResolver $callableResolver, + protected ModuleHandlerInterface $moduleHandler, + ) { + parent::__construct($treeStorage, $menuLinkManager, $routeProvider, $menuActiveTrail, $callableResolver); + } + /** * {@inheritdoc} */ @@ -47,4 +80,13 @@ public function build(array $tree): array { return $build; } + /** + * {@inheritdoc} + */ + public function transform(array $tree, array $manipulators) { + $tree = parent::transform($tree, $manipulators); + $this->moduleHandler->alter('navigation_menu_link_tree', $tree); + return $tree; + } + } diff --git a/core/modules/navigation/src/NavigationContentLinks.php b/core/modules/navigation/src/NavigationContentLinks.php index b22091bc2c45f9b166181b0aba9b17638b3202b5..7e7d00cb4e5d1c67d7037548029d0e38cd80e5c7 100644 --- a/core/modules/navigation/src/NavigationContentLinks.php +++ b/core/modules/navigation/src/NavigationContentLinks.php @@ -94,36 +94,6 @@ public function addMenuLinks(array &$links): void { ], $links); } - /** - * Remove the admin/content link, and any direct children. - * - * @param array $links - * The array of links being altered. - */ - public function removeAdminContentLink(array &$links): void { - unset($links['system.admin_content']); - - // Also remove any links that have set admin/content as their parent link. - // They are unsupported by the Navigation module. - foreach ($links as $link_name => $link) { - if (isset($link['parent']) && $link['parent'] === 'system.admin_content') { - // @todo Do we need to make this recursive, and unset children of these - // links too? - unset($links[$link_name]); - } - } - } - - /** - * Remove the help link as render it outside any menu. - * - * @param array $links - * The array of links being altered. - */ - public function removeHelpLink(array &$links): void { - unset($links['help.main']); - } - /** * Add create links for an entity type. * diff --git a/core/modules/navigation/tests/navigation_test/src/Hook/NavigationTestHooks.php b/core/modules/navigation/tests/navigation_test/src/Hook/NavigationTestHooks.php index 7071cee422ce9b97f3fb2591de9dfac40e29d8a5..d0c4006e6662bb91aad30faf7177f17b1266f959 100644 --- a/core/modules/navigation/tests/navigation_test/src/Hook/NavigationTestHooks.php +++ b/core/modules/navigation/tests/navigation_test/src/Hook/NavigationTestHooks.php @@ -84,4 +84,24 @@ public function navigationContentTopAlter(&$content_top): void { } } + /** + * Implements hook_navigation_menu_link_tree_alter(). + */ + #[Hook('navigation_menu_link_tree_alter')] + public function navigationMenuLinkTreeAlter(array &$tree): void { + foreach ($tree as $key => $item) { + // Skip elements where menu is not the 'admin' one. + $menu_name = $item->link->getMenuName(); + // Removes all items from menu1. + if ($menu_name == 'menu1') { + unset($tree[$key]); + } + + // Updates title for items in menu2 + if ($menu_name == 'menu2') { + $item->link->updateLink(['title' => 'New Link Title'], FALSE); + } + } + } + } diff --git a/core/modules/navigation/tests/src/Kernel/NavigationContentLinksTest.php b/core/modules/navigation/tests/src/Kernel/NavigationContentLinksTest.php index 6b30a6b5c6ceb4c99f8ca0e788ce562261afe9ff..9afc7df8973f11beae7a19a1bbb8fa96d846435b 100644 --- a/core/modules/navigation/tests/src/Kernel/NavigationContentLinksTest.php +++ b/core/modules/navigation/tests/src/Kernel/NavigationContentLinksTest.php @@ -37,7 +37,6 @@ class NavigationContentLinksTest extends KernelTestBase { 'media_test_source', 'image', 'text', - 'help', ]; /** @@ -119,12 +118,6 @@ public function testNavigationContentLinks(): void { $this->assertEquals('view.files.page_1', $links['navigation.files']['route_name']); $this->assertEquals('Files', $links['navigation.files']['title']); - // Assert that the "Help" link is removed from the menu. - $this->assertArrayNotHasKey('help.main', $links); - - // Assert that the "Content" link is removed from the menu. - $this->assertArrayNotHasKey('system.admin_content', $links); - // Assert that "Blocks" link is not added. $this->assertArrayNotHasKey('navigation.blocks', $links); diff --git a/core/modules/navigation/tests/src/Kernel/NavigationMenuLinkTreeTest.php b/core/modules/navigation/tests/src/Kernel/NavigationMenuLinkTreeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b03f0f6b1f253793a59145da3ea9287b373eb1e9 --- /dev/null +++ b/core/modules/navigation/tests/src/Kernel/NavigationMenuLinkTreeTest.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\navigation\Kernel; + +use Drupal\Core\Menu\MenuTreeParameters; +use Drupal\KernelTests\KernelTestBase; +use Drupal\navigation\Menu\NavigationMenuLinkTree; + +/** + * Tests \Drupal\navigation\Menu\NavigationMenuLinkTree. + * + * @group navigation + * + * @see \Drupal\navigation\Menu\NavigationMenuLinkTree + */ +class NavigationMenuLinkTreeTest extends KernelTestBase { + + /** + * The tested navigation menu link tree. + * + * @var \Drupal\navigation\Menu\NavigationMenuLinkTree + */ + protected NavigationMenuLinkTree $linkTree; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'field', + 'layout_builder', + 'layout_discovery', + 'link', + 'menu_link_content', + 'menu_test', + 'navigation', + 'navigation_test', + 'system', + 'user', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $this->installEntitySchema('user'); + $this->installEntitySchema('menu_link_content'); + + $this->linkTree = $this->container->get('navigation.menu_tree'); + } + + /** + * Tests the hook_navigation_menu_link_tree_alter logic. + */ + public function testNavigationMenuLinkTreeAlter(): void { + /** @var \Drupal\system\MenuStorage $storage */ + $storage = \Drupal::entityTypeManager()->getStorage('menu'); + $storage->create(['id' => 'menu1', 'label' => 'Menu 1'])->save(); + $storage->create(['id' => 'menu2', 'label' => 'Menu 2'])->save(); + + \Drupal::entityTypeManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save(); + \Drupal::entityTypeManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save(); + \Drupal::entityTypeManager()->getStorage('menu_link_content')->create(['link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content', 'title' => 'Link test'])->save(); + + $output = $this->linkTree->load('menu1', new MenuTreeParameters()); + $this->assertCount(2, $output); + $output = $this->linkTree->transform($output, []); + $this->assertCount(0, $output); + $output = $this->linkTree->load('menu2', new MenuTreeParameters()); + $this->assertCount(1, $output); + $output = $this->linkTree->transform($output, []); + $this->assertCount(1, $output); + $item = reset($output); + $this->assertSame('New Link Title', $item->link->getTitle()); + } + +}