diff --git a/tests/src/Kernel/MenuTest.php b/tests/src/Kernel/MenuTest.php new file mode 100644 index 0000000..4b1f01a --- /dev/null +++ b/tests/src/Kernel/MenuTest.php @@ -0,0 +1,161 @@ +menuLinkManager = $this->container->get('plugin.manager.menu.link'); + $this->aliasStorage = $this->container->get('path.alias_storage'); + + $this->installEntitySchema('menu_link_content'); + $this->installEntitySchema('node'); + $this->installEntitySchema('user'); + + Menu::create(array( + 'id' => 'token_test', + 'label' => 'Test menu', + 'description' => 'Description text', + ))->save(); + + $node_type = NodeType::create([ + 'type' => 'page', + 'name' => 'Basic page', + 'description' => "Use basic pages for your static content, such as an 'About us' page.", + ]); + $node_type->save(); + } + + /** + * Creates a node. + */ + protected function addNode($title) { + Node::create([ + 'title' => $title, + 'type' => 'page', + ])->save(); + } + + /** + * Create a simple hierarchy of links. + */ + protected function createLinkHierarchy() { + // First remove all the menu links in the menu. + $this->menuLinkManager->deleteLinksInMenu('token_test'); + + // Then create a simple link hierarchy: + // - parent + // - child-1 + // - child-1-1 + // - child-1-2 + // - child-2 + $base_options = array( + 'title' => 'Menu link test', + 'provider' => 'token', + 'menu_name' => 'token_test', + ); + + $parent = $base_options + array( + 'link' => ['uri' => 'entity:node/1'], + ); + $link = MenuLinkContent::create($parent); + $link->save(); + $links['parent'] = $link->getPluginId(); + $this->aliasStorage->save('/node/1', '/parent'); + + $this->addNode('one'); + $child_1 = $base_options + array( + 'link' => ['uri' => 'entity:node/2'], + 'parent' => $links['parent'], + ); + $link = MenuLinkContent::create($child_1); + $link->save(); + $links['child-1'] = $link->getPluginId(); + $this->aliasStorage->save('/node/2', '/child'); + + $this->addNode('two'); + $child_1_1 = $base_options + array( + 'link' => ['uri' => 'entity:node/3'], + 'parent' => $links['child-1'], + ); + $link = MenuLinkContent::create($child_1_1); + $link->save(); + $links['child-1-1'] = $link->getPluginId(); + $this->aliasStorage->save('/node/3', '/grandchild'); + + $this->addNode('three'); + $child_1_2 = $base_options + array( + 'link' => ['uri' => 'entity:node/4'], + 'parent' => $links['child-1'], + ); + $link = MenuLinkContent::create($child_1_2); + $link->save(); + $links['child-1-2'] = $link->getPluginId(); + $this->aliasStorage->save('/node/4', '/grandchild2'); + + $this->addNode('four'); + $child_2 = $base_options + array( + 'link' => ['uri' => 'entity:node/5'], + 'parent' => $links['parent'], + ); + $link = MenuLinkContent::create($child_2); + $link->save(); + $links['child-2'] = $link->getPluginId(); + $this->aliasStorage->save('/node/5', '/child2'); + + return $links; + } + + /** + * Tests menu tokens. + */ + public function testMenuTokens() { + $links = $this->createLinkHierarchy(); + + /* @var \Drupal\Core\Menu\MenuLinkInterface $menu_link_plugin */ + $menuLinkPlugin = $this->menuLinkManager->createInstance($links['child-1-2']); + $tokens = [ + 'title' => $menuLinkPlugin->getTitle(), + 'parents:join:/' => 'Menu link test/Menu link test', + 'parents-paths:join:/' => 'parent/child', + ]; + $this->assertTokens('menu-link', array('menu-link' => $menuLinkPlugin), $tokens); + } + +} diff --git a/token.module b/token.module index 6470a25..87522f7 100644 --- a/token.module +++ b/token.module @@ -510,15 +510,24 @@ function token_render_cache_set(&$markup, $elements) { * The menu link plugin ID. * @param string $langcode * The language code. + * @param string $property + * The property to extract. Defaults to title. * * @return string[] * List of menu link parent titles. */ -function token_menu_link_load_all_parents($plugin_id, $langcode) { +function token_menu_link_load_all_parents($plugin_id, $langcode, $property = 'title') { $cache = &drupal_static(__FUNCTION__, array()); - if (!isset($cache[$plugin_id][$langcode])) { - $cache[$plugin_id][$langcode] = array(); + if (!isset($cache[$plugin_id][$langcode][$property])) { + $property_extractors = [ + 'title' => 'token_menu_link_translated_title', + 'path' => 'token_menu_link_translated_path', + ]; + /** @var callable $extractor Function extracting value from menu link object. */ + $extractor = $property_extractors[$property]; + + $cache[$plugin_id][$langcode][$property] = array(); /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */ $menu_link_manager = \Drupal::service('plugin.manager.menu.link'); $parent_ids = $menu_link_manager->getParentIds($plugin_id); @@ -526,11 +535,11 @@ function token_menu_link_load_all_parents($plugin_id, $langcode) { unset($parent_ids[$plugin_id]); foreach ($parent_ids as $parent_id) { $parent = $menu_link_manager->createInstance($parent_id); - $cache[$plugin_id][$langcode] = array($parent_id => token_menu_link_translated_title($parent, $langcode)) + $cache[$plugin_id][$langcode]; + $cache[$plugin_id][$langcode][$property] = array($parent_id => $extractor($parent, $langcode)) + $cache[$plugin_id][$langcode][$property]; } } - return $cache[$plugin_id][$langcode]; + return $cache[$plugin_id][$langcode][$property]; } /** @@ -562,6 +571,31 @@ function token_menu_link_translated_title(MenuLinkInterface $menu_link, $langcod } /** + * Returns the translated path of a menu link. + * + * If the underlying entity is a content menu item, load it to get the + * translated menu item title. + * + * @todo Remove this when there is a better way to get a translated menu + * item title in core: https://www.drupal.org/node/2795143 + * + * @param \Drupal\Core\Menu\MenuLinkInterface $menu_link + * The menu link. + * @param string|null $langcode + * (optional) The langcode, defaults to the current language. + * + * @return string + * The menu link path (aliased). + */ +function token_menu_link_translated_path(MenuLinkInterface $menu_link, $langcode = NULL) { + /** @var \Drupal\Core\Path\AliasManager $aliasManager */ + $aliasManager =\Drupal::service('path.alias_manager'); + $path = '/' . $menu_link->getUrlObject()->getInternalPath(); + $alias = $aliasManager->getAliasByPath($path, $langcode); + return trim($alias, '/'); +} + +/** * Loads all the parents of the term in the specified language. * * @param int $tid diff --git a/token.tokens.inc b/token.tokens.inc index 0bf2fd5..3b7d68f 100644 --- a/token.tokens.inc +++ b/token.tokens.inc @@ -262,10 +262,15 @@ function token_token_info() { 'type' => 'menu-link', ); $info['tokens']['menu-link']['parents'] = array( - 'name' => t('Parents'), + 'name' => t('Parents titles'), 'description' => t("An array of all the menu link's parents, starting with the root."), 'type' => 'array', ); + $info['tokens']['menu-link']['parents-paths'] = array( + 'name' => t('Parents\' paths'), + 'description' => t("An array of all paths to the menu link's parents, starting with the root."), + 'type' => 'array', + ); $info['tokens']['menu-link']['root'] = array( 'name' => t('Root'), 'description' => t("The menu link's root."), @@ -721,6 +726,11 @@ function token_tokens($type, array $tokens, array $data = array(), array $option $replacements += \Drupal::token()->generate('array', $parents_tokens, array('array' => $parents), $options, $bubbleable_metadata); } } + if ($parent_paths_tokens = \Drupal::token()->findWithPrefix($tokens, 'parents-paths')) { + if ($parent_paths = token_menu_link_load_all_parents($link->getPluginId(), $langcode, 'path')) { + $replacements += \Drupal::token()->generate('array', $parent_paths_tokens , array('array' => $parent_paths), $options, $bubbleable_metadata); + } + } if (($root_tokens = \Drupal::token()->findWithPrefix($tokens, 'root')) && $link->getParent() && $parent_ids = array_keys(token_menu_link_load_all_parents($link->getPluginId(), $langcode))) { $root = $menu_link_manager->createInstance(array_shift($parent_ids)); $replacements += \Drupal::token()->generate('menu-link', $root_tokens, array('menu-link' => $root), $options, $bubbleable_metadata);