3 namespace Drupal\token\Tests;
5 use Drupal\node\Entity\Node;
7 use Drupal\node\Entity\NodeType;
8 use Drupal\language\Entity\ConfigurableLanguage;
9 use Drupal\Core\Language\LanguageInterface;
10 use Drupal\system\Entity\Menu;
11 use Drupal\menu_link_content\Entity\MenuLinkContent;
18 class TokenMenuTest extends TokenTestBase {
25 public static $modules = [
31 'content_translation',
34 function testMenuTokens() {
35 // Make sure we have a body field on the node type.
36 $this->drupalCreateContentType(['type' => 'page']);
38 $menu = Menu::create([
40 'label' => 'Main menu',
41 'description' => 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.',
45 // Place the menu block.
46 $this->drupalPlaceBlock('system_menu_block:main-menu');
49 /** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $root_link */
50 $root_link = MenuLinkContent::create([
51 'link' => ['uri' => 'internal:/admin'],
52 'title' => 'Administration',
53 'menu_name' => 'main-menu',
57 // Add another link with the root link as the parent.
58 /** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $parent_link */
59 $parent_link = MenuLinkContent::create([
60 'link' => ['uri' => 'internal:/admin/config'],
61 'title' => 'Configuration',
62 'menu_name' => 'main-menu',
63 'parent' => $root_link->getPluginId(),
67 // Test menu link tokens.
69 'id' => $parent_link->getPluginId(),
70 'title' => 'Configuration',
71 'menu' => 'Main menu',
72 'menu:name' => 'Main menu',
73 'menu:machine-name' => $menu->id(),
74 'menu:description' => 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.',
75 'menu:menu-link-count' => '2',
76 'menu:edit-url' => Url::fromRoute('entity.menu.edit_form', ['menu' => 'main-menu'], ['absolute' => TRUE])->toString(),
77 'url' => Url::fromRoute('system.admin_config', [], ['absolute' => TRUE])->toString(),
78 'url:absolute' => Url::fromRoute('system.admin_config', [], ['absolute' => TRUE])->toString(),
79 'url:relative' => Url::fromRoute('system.admin_config', [], ['absolute' => FALSE])->toString(),
80 'url:path' => '/admin/config',
81 'url:alias' => '/admin/config',
82 'edit-url' => Url::fromRoute('entity.menu_link_content.canonical', ['menu_link_content' => $parent_link->id()], ['absolute' => TRUE])->toString(),
83 'parent' => 'Administration',
84 'parent:id' => $root_link->getPluginId(),
85 'parent:title' => 'Administration',
86 'parent:menu' => 'Main menu',
87 'parent:parent' => NULL,
88 'parents' => 'Administration',
90 'parents:keys' => $root_link->getPluginId(),
91 'root' => 'Administration',
92 'root:id' => $root_link->getPluginId(),
93 'root:parent' => NULL,
96 $this->assertTokens('menu-link', ['menu-link' => $parent_link], $tokens);
99 $node = $this->drupalCreateNode();
101 // Allow main menu for this node type.
102 //$this->config('menu.entity.node.' . $node->getType())->set('available_menus', ['main-menu'])->save();
104 // Add a node menu link.
105 /** @var \Drupal\menu_link_content\Plugin\Menu\MenuLinkContent $node_link */
106 $node_link = MenuLinkContent::create([
107 'link' => ['uri' => 'entity:node/' . $node->id()],
108 'title' => 'Node link',
109 'parent' => $parent_link->getPluginId(),
110 'menu_name' => 'main-menu',
114 // Test [node:menu] tokens.
116 'menu-link' => 'Node link',
117 'menu-link:id' => $node_link->getPluginId(),
118 'menu-link:title' => 'Node link',
119 'menu-link:menu' => 'Main menu',
120 'menu-link:url' => $node->toUrl('canonical', ['absolute' => TRUE])->toString(),
121 'menu-link:url:path' => '/node/' . $node->id(),
122 'menu-link:edit-url' => $node_link->url('edit-form', ['absolute' => TRUE]),
123 'menu-link:parent' => 'Configuration',
124 'menu-link:parent:id' => $parent_link->getPluginId(),
125 'menu-link:parents' => 'Administration, Configuration',
126 'menu-link:parents:count' => 2,
127 'menu-link:parents:keys' => $root_link->getPluginId() . ', ' . $parent_link->getPluginId(),
128 'menu-link:root' => 'Administration',
129 'menu-link:root:id' => $root_link->getPluginId(),
131 $this->assertTokens('node', ['node' => $node], $tokens);
133 // Reload the node which will not have $node->menu defined and re-test.
134 $loaded_node = Node::load($node->id());
135 $this->assertTokens('node', ['node' => $loaded_node], $tokens);
137 // Regression test for http://drupal.org/node/1317926 to ensure the
138 // original node object is not changed when calling menu_node_prepare().
139 $this->assertTrue(!isset($loaded_node->menu), t('The $node->menu property was not modified during token replacement.'), 'Regression');
141 // Now add a node with a menu-link from the UI and ensure it works.
142 $this->drupalLogin($this->drupalCreateUser([
143 'create page content',
144 'edit any page content',
147 'administer content types',
148 'access administration pages',
150 // Setup node type menu options.
152 'menu_options[main-menu]' => 1,
153 'menu_options[main]' => 1,
154 'menu_parent' => 'main-menu:',
156 $this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
158 // Use a menu-link token in the body.
159 $this->drupalGet('node/add/page');
160 $this->drupalPostForm(NULL, [
161 // This should get replaced on save.
162 // @see token_module_test_node_presave()
163 'title[0][value]' => 'Node menu title test',
164 'body[0][value]' => 'This is a [node:menu-link:title] token to the menu link title',
165 'menu[enabled]' => 1,
166 'menu[title]' => 'Test preview',
168 $node = $this->drupalGetNodeByTitle('Node menu title test');
169 $this->assertEqual('This is a Test preview token to the menu link title', $node->body->value);
171 // Disable the menu link, save the node and verify that the menu link is
172 // no longer displayed.
173 $link = menu_ui_get_menu_link_defaults($node);
174 $this->drupalPostForm('admin/structure/menu/manage/main-menu', ['links[menu_plugin_id:' . $link['id'] . '][enabled]' => FALSE], t('Save'));
175 $this->assertText('Menu Main menu has been updated.');
176 $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save'));
177 $this->assertNoLink('Test preview');
179 // Now test a parent link and token.
180 $this->drupalGet('node/add/page');
181 // Make sure that the previous node save didn't result in two menu-links
182 // being created by the computed menu-link ER field.
183 // @see token_entity_base_field_info()
184 // @see token_node_menu_link_submit()
185 $selects = $this->cssSelect('select[name="menu[menu_parent]"]');
186 $select = reset($selects);
187 $options = $this->getAllOptions($select);
188 // Filter to items with title containing 'Test preview'.
189 $options = array_filter($options, function (\SimpleXMLElement $item) {
190 return strpos((string) $item[0], 'Test preview') !== FALSE;
192 $this->assertEqual(1, count($options));
193 $this->drupalPostForm(NULL, [
194 'title[0][value]' => 'Node menu title parent path test',
195 'body[0][value]' => 'This is a [node:menu-link:parent:url:path] token to the menu link parent',
196 'menu[enabled]' => 1,
197 'menu[title]' => 'Child link',
198 'menu[menu_parent]' => 'main-menu:' . $parent_link->getPluginId(),
200 $node = $this->drupalGetNodeByTitle('Node menu title parent path test');
201 $this->assertEqual('This is a /admin/config token to the menu link parent', $node->body->value);
203 // Now edit the node and update the parent and title.
204 $this->drupalPostForm('node/' . $node->id() . '/edit', [
205 'menu[menu_parent]' => 'main-menu:' . $node_link->getPluginId(),
206 'title[0][value]' => 'Node menu title edit parent path test',
207 'body[0][value]' => 'This is a [node:menu-link:parent:url:path] token to the menu link parent',
209 $node = $this->drupalGetNodeByTitle('Node menu title edit parent path test', TRUE);
210 $this->assertEqual(sprintf('This is a /node/%d token to the menu link parent', $loaded_node->id()), $node->body->value);
212 // Make sure that the previous node edit didn't result in two menu-links
213 // being created by the computed menu-link ER field.
214 // @see token_entity_base_field_info()
215 // @see token_node_menu_link_submit()
216 $this->drupalGet('node/add/page');
217 $selects = $this->cssSelect('select[name="menu[menu_parent]"]');
218 $select = reset($selects);
219 $options = $this->getAllOptions($select);
220 // Filter to items with title containing 'Test preview'.
221 $options = array_filter($options, function (\SimpleXMLElement $item) {
222 return strpos((string) $item[0], 'Child link') !== FALSE;
224 $this->assertEqual(1, count($options));
226 // Now add a new node with no menu.
227 $this->drupalGet('node/add/page');
228 $this->drupalPostForm(NULL, [
229 'title[0][value]' => 'Node menu adding menu later test',
230 'body[0][value]' => 'Going to add a menu link on edit',
231 'menu[enabled]' => 0,
233 $node = $this->drupalGetNodeByTitle('Node menu adding menu later test');
234 // Now edit it and add a menu item.
235 $this->drupalGet('node/' . $node->id() . '/edit');
236 $this->drupalPostForm(NULL, [
237 'title[0][value]' => 'Node menu adding menu later test',
238 'body[0][value]' => 'This is a [node:menu-link:parent:url:path] token to the menu link parent',
239 'menu[enabled]' => 1,
240 'menu[title]' => 'Child link',
241 'menu[menu_parent]' => 'main-menu:' . $parent_link->getPluginId(),
243 $node = $this->drupalGetNodeByTitle('Node menu adding menu later test', TRUE);
244 $this->assertEqual('This is a /admin/config token to the menu link parent', $node->body->value);
245 // And make sure the menu link exists with the right URI.
246 $link = menu_ui_get_menu_link_defaults($node);
247 $this->assertTrue(!empty($link['entity_id']));
248 $query = \Drupal::entityQuery('menu_link_content')
249 ->condition('link.uri', 'entity:node/' . $node->id())
252 $result = $query->execute();
253 $this->assertTrue($result);
255 // Create a node with a menu link and create 2 menu links linking to this
256 // node after. Verify that the menu link provided by the node has priority.
257 $node_title = $this->randomMachineName();
259 'title[0][value]' => $node_title,
260 'menu[enabled]' => 1,
261 'menu[title]' => 'menu link provided by node',
263 $this->drupalPostForm('node/add/page', $edit, t('Save'));
264 $this->assertText('page ' . $node_title . ' has been created');
265 $node = $this->drupalGetNodeByTitle($node_title);
267 $menu_ui_link1 = MenuLinkContent::create([
268 'link' => ['uri' => 'entity:node/' . $node->id()],
269 'title' => 'menu link 1 provided by menu ui',
270 'menu_name' => 'main-menu',
272 $menu_ui_link1->save();
274 $menu_ui_link2 = MenuLinkContent::create([
275 'link' => ['uri' => 'entity:node/' . $node->id()],
276 'title' => 'menu link 2 provided by menu ui',
277 'menu_name' => 'main-menu',
279 $menu_ui_link2->save();
282 'menu-link' => 'menu link provided by node',
283 'menu-link:title' => 'menu link provided by node',
285 $this->assertTokens('node', ['node' => $node], $tokens);
289 * Tests that the module doesn't affect integrity of the menu, when
290 * translating them and that menu links tokens are correct.
292 function testMultilingualMenu() {
293 // Place the menu block.
294 $this->drupalPlaceBlock('system_menu_block:main');
296 // Add a second language.
297 $language = ConfigurableLanguage::create([
303 // Create the article content type.
304 $node_type = NodeType::create([
310 'access administration pages',
311 'administer content translation',
312 'administer content types',
313 'administer languages',
314 'create content translations',
315 'create article content',
316 'edit any article content',
317 'translate any entity',
320 $this->drupalLogin($this->drupalCreateUser($permissions));
322 // Enable translation for articles and menu links.
323 $this->drupalGet('admin/config/regional/content-language');
325 'entity_types[node]' => TRUE,
326 'entity_types[menu_link_content]' => TRUE,
327 'settings[node][article][translatable]' => TRUE,
328 'settings[node][article][fields][title]' => TRUE,
329 'settings[menu_link_content][menu_link_content][translatable]' => TRUE,
331 $this->drupalPostForm(NULL, $edit, t('Save configuration'));
332 $this->assertText('Settings successfully updated.');
334 // Create an english node with an english menu.
335 $this->drupalGet('/node/add/article');
337 'title[0][value]' => 'English test node with menu',
338 'menu[enabled]' => TRUE,
339 'menu[title]' => 'English menu title',
341 $this->drupalPostForm('/node/add/article', $edit, t('Save'));
342 $this->assertText('English test node with menu has been created.');
344 // Add a german translation.
345 $this->drupalGet('node/1/translations');
346 $this->clickLink('Add');
348 'title[0][value]' => 'German test node with menu',
349 'menu[enabled]' => TRUE,
350 'menu[title]' => 'German menu title',
352 $this->drupalPostForm(NULL, $edit, t('Save (this translation)'));
353 $this->assertText('German test node with menu has been updated.');
355 // Verify that the menu links are correct.
356 $this->drupalGet('node/1');
357 $this->assertLink('English menu title');
358 $this->drupalGet('de/node/1');
359 $this->assertLink('German menu title');
361 // Verify that tokens are correct.
362 $node = Node::load(1);
363 $this->assertTokens('node', ['node' => $node], ['menu-link' => 'English menu title']);
364 $this->assertTokens('node', ['node' => $node], [
365 'menu-link' => 'German menu title',
366 'menu-link:title' => 'German menu title',
367 ], ['langcode' => 'de']);
369 // Get the menu link and create a child menu link to assert parent and root
371 $url = $node->toUrl();
372 /** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
373 $menu_link_manager = \Drupal::service('plugin.manager.menu.link');
374 $links = $menu_link_manager->loadLinksByRoute($url->getRouteName(), $url->getRouteParameters());
375 $link = reset($links);
378 'provider' => 'menu_test',
379 'menu_name' => 'menu_test',
381 $child_1 = $base_options + [
382 'title' => 'child_1 title EN',
383 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child_1'],
384 'parent' => $link->getPluginId(),
387 $child_1 = MenuLinkContent::create($child_1);
390 // Add the german translation.
391 $child_1->addTranslation('de', ['title' => 'child_1 title DE'] + $child_1->toArray());
394 $this->assertTokens('menu-link', ['menu-link' => $child_1], [
395 'title' => 'child_1 title EN',
396 'parents' => 'English menu title',
397 'root' => 'English menu title',
399 $this->assertTokens('menu-link', ['menu-link' => $child_1], [
400 'title' => 'child_1 title DE',
401 'parents' => 'German menu title',
402 'root' => 'German menu title',
403 ], ['langcode' => 'de']);
407 * Tests menu link parents token.
409 public function testMenuLinkParentsToken() {
410 // Create a menu with a simple link hierarchy :
416 'label' => 'Test menu',
419 'provider' => 'menu_test',
420 'menu_name' => 'menu_test',
422 $parent = $base_options + [
423 'title' => 'parent title',
424 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent'],
426 $parent = MenuLinkContent::create($parent);
428 $child_1 = $base_options + [
429 'title' => 'child_1 title',
430 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child_1'],
431 'parent' => $parent->getPluginId(),
433 $child_1 = MenuLinkContent::create($child_1);
435 $child_1_1 = $base_options + [
436 'title' => 'child_1_1 title',
437 'link' => ['uri' => 'internal:/menu-test/hierarchy/parent/child_1/child_1_1'],
438 'parent' => $child_1->getPluginId(),
440 $child_1_1 = MenuLinkContent::create($child_1_1);
443 $this->assertTokens('menu-link', ['menu-link' => $child_1_1], ['parents' => 'parent title, child_1 title']);
445 // Change the parent of child_1_1 to 'parent' at the entity level.
446 $child_1_1->parent->value = $parent->getPluginId();
449 $this->assertTokens('menu-link', ['menu-link' => $child_1_1], ['parents' => 'parent title']);
451 // Change the parent of child_1_1 to 'main', at the entity level.
452 $child_1_1->parent->value = '';
455 // The token shouldn't have been generated; the menu link has no parent.
456 $this->assertNoTokens('menu-link', ['menu-link' => $child_1_1], ['parents']);