I set my content to have a pathauto pattern of /[node:menu-link:parent:url:path]/[node:title]

When I create content and choose a menu parent for the node and save it, I get just the node title as the url pattern. However if I go back to edit the node and save it again then I get the expected pattern. I suppose that the data about the node:menu-link must not be available in time to be used upon the original node creation.

Comments

Jody Lynn created an issue. See original summary.

peter törnstrand’s picture

I'm experiencing the same problem but I'm also using the [node:menu-link]-token on the last bit as well.

My pattern looks like this: [node:menu-link:parents:join-path]/[node:menu-link:title]

On first save I just get the default node/X "alias". On the second save the correct alias appears.

peter törnstrand’s picture

Title: Pattern with node:menu-link:parent:url:path doesn't work on first save » Patterns with node:menu-link tokens doesn't work on first save

Change the title to reflect that this seems not to be working regardless of what token from [node:menu-link] you use.

peter törnstrand’s picture

Update. Running Update URL-Alias via the content overview page does not create the missing alias. Only when saving the node form (the second time) the alias is created.

berdir’s picture

Yes, that's a known issue. See https://github.com/md-systems/pathauto/issues/76 for some background, discussion and a possible workaround.

I don't see a clean solution for this atm.

peter törnstrand’s picture

Ok thanks @Berdir. The "hack module" at https://github.com/idflood/pathauto_menu_link_parents_hack solves the problem for me. It seems it would require a core fix to do this properly.

kevinquillen’s picture

This is major IMO (to find a solution), as automating path aliasing based off menu structure is probably a common use case for automatic aliasing for most people when it comes to content.

From GitHub:

Maybe it's not so bad to react on a menu_link(_content) save for [node:menu-link:parents:join-path]. What should happen if a menu item is re-positioned the menu system. Should the alias be updated?

Yes. If you are aliasing content from menu paths, and change the menu structure, the alias and any below it should be checked for updates. The automation of all of this worked for me in D7 with the same tokens.

maartendelputte’s picture

I've tried to fix it myself with this code, seems to work ok:

        function hook_entity_insert($entity) {
		// If on menu content update save
		if($entity->getEntityTypeId()==='menu_link_content') {
			_hook_update_alias($entity);
		}
	}

	function hook_entity_update($entity) {
		// If on menu content update save
		if($entity->getEntityTypeId()==='menu_link_content') {
			_hook_update_alias($entity);
		}
	}

	function _hook_update_alias($entity) {
		// Clear the cache used in token_menu_link_load_all_parents().
		drupal_static_reset('token_menu_link_load_all_parents');

		// Check if the link points to something
		if(isset($entity->toArray()['link'][0]['uri'])&&!empty($entity->toArray()['link'][0]['uri'])){
			// Get value
			$nodeId = $entity->toArray()['link'][0]['uri'];
			// Explode the string on the entity:node/ (make sure it links to a node)
			$nodeParts = explode('entity:node/', $nodeId);
			if(!empty($nodeParts)) {
				// Last key has the node id
				$nodeId = end($nodeParts);
				if(!empty($nodeId)) {
					// Get value if autopath is checked upon the node
					$pathAutoCheck = \Drupal::keyValue('pathauto_state.node')->get($nodeId);
					if($pathAutoCheck==true) {
						// Get node storage
						$nodeStorage = \Drupal::entityManager()->getStorage('node');
						// Load the node
						$node = $nodeStorage->load($nodeId);
						if(!empty($node)) {
							// Update node url
							\Drupal::service('pathauto.generator')->updateEntityAlias($node, 'update', array('force' => TRUE));
						}
					}
				}
			}
		}
	}


	function hook_form_alter(&$form,$form_state,$form_id) {
		// If menu get's saved
		if($form_id=='menu_edit_form') {
			// Add extra submit handler
			$form['actions']['submit']['#submit'][] = '_hook_menu_submit';
		}
	}

	function _hook_menu_submit(&$form,$form_state) {
		// Get form values
		$formValues = $form_state->getValues();
		// Check if there are links
		if(!empty($formValues)&&isset($formValues['links'])&&!empty($formValues['links'])) {
			// Check each link out
			$menuIds = array();
			foreach ($formValues['links'] as $key => $link) {
				$parts = explode('menu_plugin_id:menu_link_content:', $key);
				$menuIds[end($parts)] = end($parts);
			}

			// Get all menu links info we found
			$query = db_select('menu_link_content', 'm');
			$query->fields('m');
			$query->condition('uuid',$menuIds,'in');
			$menuItems = $query->execute()->fetchAll();

			if(!empty($menuItems)) {
				foreach ($menuItems as $key => $menuItem) {
					// Load node linked to this menu item
					$menuItemContent = entity_load('menu_link_content',$menuItem->id);
					if(!empty($menuItemContent)) {
						// Update node alias
						_hook_update_alias($menuItemContent);
					}
				}
			}
		}
	}
rgpublic’s picture

I'm still trying to figure out the reason I get this error message:

The path "/anwendungen/boden" collides with the route with identifier entity.node.canonical, whose path is /node/{node}

This happens if I clear all URL aliases and bulk generate as well as if I just save a node.

I'm also using the "infamous" pattern [node:menu-link:parents:join-path]/[node:menu-link:title]

Installing the hack module doesn't help either.

BTW: I wonder... Isn't that pattern pretty standard? It's the most intutive pattern I can think of for a hierarchically structured website... I find it confusing that this hasn't been caught yet. Without this, the whole URL alias / pathauto feature becomes almost useless. It's a major D8 show-stopper IMHO...

kevinquillen’s picture

I agree, this is the token I use for general page content (Basic Page) because 98% of it is structured in the menu tree, and I like my URLs to reflect that fact. It also makes it dead simple for a content editor to create content, put it in the menu, and get a great URL automatically without having to go to a handful of places within the admin.

The 'workarounds' posted so far mirror the same sort of ones from D6 and D7 before this token was implemented in D7. I don't want to save a node twice, that can have all sorts of implications down the road.

I haven't had time lately to really dig into this, but with all the new tools in D8 there has to be a clean solution.

larowlan’s picture

Title: Patterns with node:menu-link tokens doesn't work on first save » Patterns with node:menu-link tokens don't work on first node save
Project: Pathauto » Token
StatusFileSize
new3.47 KB
new11.29 KB

So here's a new approach as follows:

- create a computed ER field on node entity type that references a menu-link entity
- add an entity builder that runs on the node submit form that builds a menu-link entity and stores this in the computed field with a temporary URI (node isn't yet saved).
- after the node is saved update the URI to the correct one.
- store the saved entity ID for menu_ui module to pick up later.
- means all the tokens for node:menu-link are available (except for the path one - but no-one wants that here, because we're using pathauto to create a path, so we wouldn't reference our own path in a token) - although that will work too after #2353611: Make it possible to link to an entity by UUID is in
- only down-side I can see here is that the menu link entity is saved three times as follows:
- when the node is being built (after validation) - with the UUID based URI
- after the node is saved and the NID is known
- when _menu_ui_node_save runs

Includes tests.

larowlan’s picture

Status: Active » Needs review

The last submitted patch, 11: 2670120-menu-link-tokens.fail_.patch, failed testing.

The last submitted patch, 11: 2670120-menu-link-tokens.fail_.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 11: 2670120-menu-link-tokens.patch, failed testing.

larowlan’s picture

Oh, also forgot to mention the other piece of the puzzle.

change menu_ui_tokens (in token module, despite the name) use the values in $node->menu_link computed field if they're present instead of using loading from the menu-tree storage

The last submitted patch, 11: 2670120-menu-link-tokens.patch, failed testing.

larowlan’s picture

Status: Needs work » Needs review
StatusFileSize
new688 bytes
new11.34 KB
berdir’s picture

  1. +++ b/tests/modules/token_module_test/token_module_test.module
    @@ -17,3 +18,14 @@ function token_module_test_page_attachments() {
    + */
    +function token_module_test_node_presave(NodeInterface $node) {
    +  // Transform tokens in the body.
    +  if ($node->hasField('body')) {
    

    Can we add a comment here and reference to the test that is relying on this?

  2. +++ b/token.module
    @@ -635,3 +639,99 @@ function token_element_children(&$elements, $sort = FALSE) {
    + */
    +function token_entity_base_field_info(EntityTypeInterface $entity_type) {
    +  if ($entity_type->id() === 'node' && \Drupal::moduleHandler()->moduleExists('menu_ui')) {
    +    $fields['menu_link'] = BaseFieldDefinition::create('entity_reference')
    +      ->setLabel(t('Menu link'))
    

    Same here, a description why we do this and a comment/todo to related core issues would be great as well. Maybe at some point core will add a similar field and I'm not sure what's going to happen then exactly.

    This is also going to be one of those fields that confuse users in search api/REST/default content because it will exist but always be empty on export.

  3. +++ b/token.module
    @@ -635,3 +639,99 @@ function token_element_children(&$elements, $sort = FALSE) {
    +  $node = $form_object->getEntity();
    +  if (!$node->isNew() || !\Drupal::currentUser()->hasPermission('administer menu')) {
    +    // We're only interested in when the node is unsaved and the editor has
    +    // permission to create new menu links.
    +    return;
    +  }
    

    Sure about isNew? What happens if you change the menu link on an existing node? I assume that has the same problem, as the current code only looks at the currently stored data.

larowlan’s picture

StatusFileSize
new6.16 KB
new13.09 KB

#19.1 done
#19.2 done, and changed the field description to it's clear that its only transient
#19.3 done, and added new tests - client actually reported that bug too - pretty impressed that you can pick stuff up like that straight from a review :)

Status: Needs review » Needs work

The last submitted patch, 20: 2670120-menu-link-tokens.20.patch, failed testing.

The last submitted patch, 20: 2670120-menu-link-tokens.20.patch, failed testing.

harsha012’s picture

StatusFileSize
new23.26 KB

added patch

harsha012’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 23: menu-link-token-2670120-23.patch, failed testing.

The last submitted patch, 23: menu-link-token-2670120-23.patch, failed testing.

larowlan’s picture

Issue tags: +Needs reroll
hussainweb’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new13.1 KB

Rerolling #20. I am not sure what the patch in #23 was trying to do and there was no interdiff either.

larowlan’s picture

Status: Needs review » Needs work

Just a note that this doesn't work, on edit the URI is changed to node/{uuid}

larowlan’s picture

working on fix

larowlan’s picture

Status: Needs work » Needs review
StatusFileSize
new3.13 KB
new260.97 KB

test demonstrating the issue, with a fix

Status: Needs review » Needs work

The last submitted patch, 31: 2670120-menu-link-tokens.31.patch, failed testing.

The last submitted patch, 31: 2670120-menu-link-tokens.31.patch, failed testing.

larowlan’s picture

Status: Needs work » Needs review
StatusFileSize
new14.75 KB

too many remotes

Bambell’s picture

I manually tested #34 and the patch fixes #2, although I am not experiencing exactly the same issue. I created a "[node:menu-link:parents:join-path]/[node:menu-link:title]" pattern and created a node with a "Menu link title" and "Parent item". This would not generate an alias at all (unlike what's mentioned in #2). Going back to the node and hitting the "Save and keep published" button triggered the alias' generation. With patch #34, the alias is properly created when the node is created, so this issue seems fixed. I tested this few times.

  • Berdir committed 77f9872 on 8.x-1.x authored by larowlan
    Issue #2670120 by larowlan, hussainweb, Bambell: Patterns with node:menu...
berdir’s picture

Status: Needs review » Fixed

Thanks everyone, committed.

larowlan’s picture

:dance:

samtny’s picture

Just a note that this patch did not work until I cleared cache drush cr.

-S

acbramley’s picture

Status: Fixed » Needs work

Unfortunately updating to 8.x-1.x after this was committed is giving me a bug with the menu parent selection on the node form.

I can no longer see an unpublished node's menu item in the parent item select box. Once published it shows fine.

I've tested going back and forth between versions of token and can confirm the update is what is breaking it.

The bug with the path aliases is nicely fixed however :)

berdir’s picture

Status: Needs work » Fixed

Can you create a new issue with reference to this instead?

From a quick glance, I can't see anything that would cause that, we don't mess with the available options in the menu AFAIK, but who knows..

acbramley’s picture

Sure, I can't see what else changed between the two versions but I'll fire up a simplytestme to see if I can replicate it.

EDIT: Seems to be an issue with automated tests rather than the actual UI.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

criscom’s picture

acbramley’s picture

bkosborne’s picture

Heads up for anyone using the "Menu Admin per Menu" module, the fix that was committed here will likely not work for you because it checks that the user submitting the node form has the "administer menu" permission. If you're using the "Menu Admin per Menu" module, you likely don't give that permission to your editors, and instead give them the per-menu admin permissions.

Our workaround for now is to replace the entity builder with our own that does a different permission check.

bkosborne’s picture

chris burge’s picture

Re Menu Admin per Menu, take a look at #3017441: Unnecessary 'administer menu' Permission Check in token_form_node_form_alter(). The 'administer menu' check is unnecessary.

ayalon’s picture

This change introduced several new problems. I decribed them here, if you are looking for a solution:
#3036077: Bug with menu item uuid when first save a node