We're using our website as a decoupled Drupal, and the front-end needs various Metatag information including the canonical URL.
As the default token for the canonical url in the Metatag module is [node:url], the front-end receives the absolute path to the Node while - for obvious reasons - they prefer to have the relative path to the Node.
However, when I change the [node:url] token to [node:url:relative], this fatal error is thrown on creating the Node:
Drupal\Core\Entity\EntityMalformedException: The "node" entity cannot have a URI as it does not have an ID in Drupal\Core\Entity\EntityBase->toUrl() (line 192 of core/lib/Drupal/Core/Entity/EntityBase.php).
This seems to be triggered by this block of code:
if (($url_tokens = \Drupal::token()->findWithPrefix($tokens, 'url'))) {
$replacements += \Drupal::token()->generate('url', $url_tokens, ['url' => $node->toUrl()], $options, $bubbleable_metadata);
}which calls $node->toUrl() where the error is triggered due to $node not yet having an ID.
| Comment | File | Size | Author |
|---|---|---|---|
| #20 | new_nodes_no_uri_3216016-20.patch | 2.74 KB | josephr5000 |
| #19 | new_nodes_no_uri_3216016-19.patch.txt | 2.74 KB | josephr5000 |
| #10 | new_nodes_no_uri_3216016-10.patch | 842 bytes | gcb |
Issue fork token-3216016
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
berdirI suppose we can put a try/catch around that, but why would you call this on a node that wasn't saved yet? I don't see node_tokens() catching that error, so I would assume that should give you the same error.
Comment #3
vodde83 commentedIt only seems to be triggered with a 'chained' token on
[node:url]( e.g.[node:url:relative],[node:url:absolute], .. ) due to the IF statement.If I don't chain any further, all goes well. I'm guessing Core doesn't deal with chained token on [node:url].
And why? Because I want the relative URL to appear on the canonical URL meta-tag :)
If I initially create the node with
[node:url], and afterwards update the canonical URL with[node:url:relative]and save again, there's no error.But that is quite cumbersome for the customer to do.
I could apply some magic myself during initial Node creation and updating, but I would assume that chained
[node:url]-tokens should work out-of-the-box.Comment #4
berdirI'm not asking why you want that token, I'm asking why you're doing token replacements before the node is saved. An unsaved node has no URL, relative or otherwise.
Comment #5
berdirAnd I just double-checked that node:url causes the exact same exception.
Comment #6
berdirComment #7
staceroni commentedI am seeing the same message for [node:edit-url] when trying to use something in configuring the default Layout (layout builder) for a node.
In this context, it is a layout configuration, the node doesn't have an ID. I get a stack trace:
This is a different scenario as described above, however I hope that it can be resolved by not providing these tokens for a node that doesn't yet have an ID.
Comment #8
staceroni commentedTo the reporter --
Have you considered one of these :
https://www.drupal.org/project/drupal/issues/3069001
https://www.drupal.org/project/ctools/issues/3029323
Comment #9
stanleyfernandesconsider this issue also to fix the error reported :
https://www.drupal.org/project/yoast_seo/issues/3110455
Comment #10
gcb@Berdir the core module layout_builder regularly renders content with sample entities in its UX. These sample entities do not have IDs. As a result, if you use a URI token anywhere on a default layout, the layout builder screen is crashed by this issue.
The function
\Drupal\Core\Entity\EntityBase::toUrl()begins with a check for a Null entity ID, and throws an exception if there's no ID. Passing an entity to this function without checking for an ID first is asking for whitescreens -- new, unsaved entities are valid for rendering according to Drupal standards. See the discussion in https://www.drupal.org/project/drupal/issues/3069001 about having contrib modules sensibly handling "preview" content.Comment #11
gcbComment #12
tim.plunkettCould also use
empty($node->in_preview). That pre-dates LB (think original node preview) but is also set when LB generates the sample entity.Comment #15
berdirI don't think in preview is the right thing to check here. you can also preview an existing, already saved node with an ID.
We have an existing case that checks for isNew(), for the generic entity:url token, no strong preference betweenn isNew() and id(). I suppose id() could in edge cases be more reliable.
Remaining tasks:
* As mentioned earlier, node_tokens() in core has the same issue, aka the :url and :edit-url tokens, and a core issue should be opened to improve this.
* Either add checks for other toUrl() calls in token replacements in this module or create a follow-up.
* As usual, tests will make it more likely that this gets committed. Look for exsting tests for those tokens, copy paste with a new node, ensure it doesn't throw an error (assert for not replacing the token).
Comment #16
joelpittetWe used MR 52 to explicitly fix this error in preview (usually I don't enable preview on nodes...)
Comment #17
joelpittetRerolled it into the new class for the hooks.
Comment #18
joelpittet@berdir, will that suffice for the test coverage?
I tried to avoid parsing the URL but came up short and the core tests for Preview didn't help fill in the gaps enough.
It is red/green on the issue though.
Comment #19
josephr5000 commentedFreezing current mr52 state as a patch to give a convenient reference for our composer.json
Comment #20
josephr5000 commentedOops, wrong file extension. Here's a correction.
Comment #22
berdirI would have just created a new node in code and a kernel test, this seems a bit fragile if core ever changes how previews work, but I guess we'll deal with it then.
Merged.