diff --git a/src/Tests/TokenMenuTest.php b/src/Tests/TokenMenuTest.php index 269b755..b9eb920 100644 --- a/src/Tests/TokenMenuTest.php +++ b/src/Tests/TokenMenuTest.php @@ -251,6 +251,38 @@ class TokenMenuTest extends TokenTestBase { ->range(0, 1); $result = $query->execute(); $this->assertTrue($result); + + // Create a node with a menu link and create 2 menu links linking to this + // node after. Verify that the menu link provided by the node has priority. + $node_title = $this->randomMachineName(); + $edit = [ + 'title[0][value]' => $node_title, + 'menu[enabled]' => 1, + 'menu[title]' => 'menu link provided by node', + ]; + $this->drupalPostForm('node/add/page', $edit, t('Save and publish')); + $this->assertText('page ' . $node_title . ' has been created'); + $node = $this->drupalGetNodeByTitle($node_title); + + $menu_ui_link1 = entity_create('menu_link_content', [ + 'link' => ['uri' => 'entity:node/' . $node->id()], + 'title' => 'menu link 1 provided by menu ui', + 'menu_name' => 'main-menu', + ]); + $menu_ui_link1->save(); + + $menu_ui_link2 = entity_create('menu_link_content', [ + 'link' => ['uri' => 'entity:node/' . $node->id()], + 'title' => 'menu link 2 provided by menu ui', + 'menu_name' => 'main-menu', + ]); + $menu_ui_link2->save(); + + $tokens = [ + 'menu-link' => 'menu link provided by node', + 'menu-link:title' => 'menu link provided by node', + ]; + $this->assertTokens('node', ['node' => $node], $tokens); } /** diff --git a/token.tokens.inc b/token.tokens.inc index 0bf2fd5..b94aefc 100644 --- a/token.tokens.inc +++ b/token.tokens.inc @@ -17,6 +17,7 @@ use Drupal\Core\Url; use Drupal\field\FieldStorageConfigInterface; use Drupal\menu_link_content\MenuLinkContentInterface; use Drupal\node\Entity\Node; +use Drupal\node\NodeInterface; use Drupal\system\Entity\Menu; use Drupal\user\UserInterface; use Symfony\Cmf\Component\Routing\RouteObjectInterface; @@ -1182,7 +1183,7 @@ function menu_ui_tokens($type, $tokens, array $data = array(), array $options = else { $url = $node->toUrl(); if ($links = $menu_link_manager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters())) { - $link = reset($links); + $link = _token_menu_link_best_match($node, $links); $replacements[$original] = token_menu_link_translated_title($link, $langcode); } } @@ -1198,7 +1199,7 @@ function menu_ui_tokens($type, $tokens, array $data = array(), array $options = else { $url = $node->urlInfo(); if ($links = $menu_link_manager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters())) { - $link = reset($links); + $link = _token_menu_link_best_match($node, $links); $replacements += \Drupal::token()->generate('menu-link', $menu_tokens, array('menu-link' => $link), $options, $bubbleable_metadata); } } @@ -1269,6 +1270,36 @@ function menu_ui_tokens($type, $tokens, array $data = array(), array $options = } /** + * Returns a best matched link for a given node. + * + * If the url exists in multiple menus, default to the one + * set on the node itself. + * + * @param \Drupal\node\NodeInterface $node + * The node to lookup the default menu settings from + * @param array $links + * An array of instances keyed by plugin ID. + * + * @return \Drupal\Core\Menu\MenuLinkInterface + * A Link instance. + */ +function _token_menu_link_best_match(NodeInterface $node, array $links) { + // Get the menu ui defaults so we can determine what menu was + // selected for this node. This ensures that if the node was added + // to the menu via the node UI, we use that as a default. If it + // was not added via the node UI then grab the first in the + // retrieved array. + $defaults = menu_ui_get_menu_link_defaults($node); + if (isset($defaults['id']) && isset($links[$defaults['id']])) { + $link = $links[$defaults['id']]; + } + else { + $link = reset($links); + } + return $link; +} + +/** * Implements hook_token_info_alter() on behalf of field.module. * * We use hook_token_info_alter() rather than hook_token_info() as other