Problem/Motivation
The link text of the link field does allow to use tokens, but the url does not.
A use case example is using the link for a sharing function where the link is
http://twitter.com/share?url=[current-page:url:absolute]&text=[current-page:title]
and the link text "Twitter".
It does not appear logical why I can use tokens for the link text and not for the title. Therefore I marked this as a bug.
Steps to reproduce
- Enable token module
- Enable link module
- Create content type
- Add link field to content type form display. Allow unlimited values so we can test lots of things.
- Go to /node/add/ to create a new piece of content and to test tokens in the url input of a link field.
- Enter title
- Enter link title in your newly created link field
-
Enter url with a token in it.
http://twitter.com/share?url=[current-page:url:absolute]&text=[current-page:title]/node/[node:id]
- Save the content and see how this doesn't replace the token
Proposed resolution
Optionally allow tokens to be used in the url field of link fields
Remaining tasks
This currently only works on form submissions, tested with a migration and it seems more work is needed to make this work in a migration, my assumption is that it probably won't work in other non-form related entity creations either. example JSON API
links are rendered correctly on the front end, but they are not tied to the context in the database, and are instead tied to the node itself.
The contrib module: https://www.drupal.org/project/field_group_link does not render link properly which leads to other questions about how these types of links should be rendered.
Additionally, this does not account for entity references via token.
User interface changes
Maybe allow tokens on the link field creation form.
API changes
Add new method for generating links with tokens.
Add new scheme:// type for tokens token://
Data model changes
Adds token context array to url options array in database so that contextual tokens can validate on form submission.
a:1:{s:7:"context";a:1:{s:4:"node";s:3:"193";}}
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #74 | allow_tokens_for_url-2903336-74.patch | 7.07 KB | a.hover |
| #71 | 2903336-71.patch | 8.73 KB | voleger |
| #68 | allow_tokens_for_url-2903336-68.patch | 8.21 KB | junaidpv |
| #65 | allow_tokens_for_url-2903336-65.patch | 8.73 KB | alt.dev |
| #59 | 2903336-nr-bot.txt | 2.54 KB | needs-review-queue-bot |
Issue fork drupal-2903336
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
demonde commentedComment #3
dawehnerWhy I totally get why you need this particular feature, its less easy as you think it is.
When you expose the data in REST, what do you return?
This is just a short example of questions one might need to answer. Given that, at least for me personally, it feels like a contrib module you could work on, and well, maybe figure out all the various problems, that might come up.
Even if you disagree with these problems, I think this is at least a clear feature request :)
Comment #4
demonde commentedThe Drupal 7 Link module would allow Token by a checkbox in the backend.
If the problems like caching and REST requests are grave, why is there a token allowed for the link text but not for the link itself?
Comment #7
lucas cavalcante commentedWhen we tried to use token inside a link field it broken, concatenating the right URI with the token in front of it.
We made a patch to solve this issue in the link module.
Comment #8
hypertext200I think you can easily extend the
LinkFormatterclass and add token replace function to theviewElementsmethod to make it work, so while you are working on that you can add an additional setting. Not sure how this is going to impact on caching since cache tags aren't aware of dynamic tokens.Comment #9
eahonet commentedCame across this as I was researching the same request. I was able to leverage this module to solve: https://www.drupal.org/project/token_filter
Comment #10
Amit Dwivedi commented@heshanlk @eahonet,
I want to replace whole URL with some custom token. (As Url is different for all environments)
I tried with creating a custom LinkFormatter for that purpose and Token is working fine when I put it after http:// or https://.
But that doesn't seems a good solution as I need to trim it in LinkFormatter.
When token is filled in link field (without prefixing http:// or https://) it throws invalid path error.
So how can I skip that validation in case of token is there in link field.
Thank you.
Comment #11
freed_paris commentedHi,
This patch is not working actually, I'm not sure but I think 8.6.1 updated things about validations of URLs
Unable to validate the field with a token, it says : "Manually entered paths should start with /, ? or #."
Any solution ?
Thanks
Freed
Comment #12
brooke_heaton commentedThis patch does not work fully due to two problems:
1. validateUriElement in LinkWidget.php is going to throw a validation error because a token will start with '[' and not with the other allowed elements. I think this can be fixed by allowing [ but it might be best to validate the actual token here before saving.
2. LinkNotExistingInternalConstraintValidator will throw an invalid exception on getUrl since a token will not validate as a url - the token should be identified and rendered here as well.
Ultimately we likely need a new 'token' url scheme that differs from 'base', 'internal' and 'external' and it should get its own formatter and validation.
Comment #13
brooke_heaton commentedThis is a pretty meaty patch against 8.7 and adds a new method to get urls from tokens as well as a token property to define the url as a token. It also includes validation and replacement via the token service. Non-url tokens will not validate.
Comment #14
brooke_heaton commentedComment #16
alisonApplies cleanly on 8.7.0 and 8.7.1! I can't test the actual functionality right now, but, just wanted to chime in that it applies cleanly for me.
Comment #17
demonde commentedI applied the patch in #13 against 8.7 cleanly but I have no token replacement for the link using
http://twitter.com/share?url=[current-page:url:absolute]&text=[current-page:title]while token replacement for the title works. Not sure if I did sth wrong.
Comment #18
brooke_heaton commented@demonde - I think the issue is that my patch currently replaces entire tokens but not tokens within strings. I will refactor the patch to replace tokens within strings.
Comment #19
ccasals commented@brooke_heaton The 'isToken()' method appears to be missing from Drupal\Core\Url. It looks like everything else is wired up though. This is a nice approach that will let other modules extend this logic. (for example: https://www.drupal.org/project/rabbit_hole/issues/3060274)
edit: after manual testing this further I found a couple of other places that are missing some logic.
elseif (empty($uri_parts['scheme']))on line 280 fails the check since there's no token scheme returned from parse_url()This causes the later on 'if $scheme is token' check you have to fail as well (it's never set).
Comment #20
brooke_heaton commented@ccasals. I'll take a look at that and test it with the rabbit_hole issue. I'm still needing to get back to this and to ensure that multiple tokens within strings can be replaced. I've just been swamped.
Comment #21
ccasals commentedYeah I hear you! Thanks for your work on this (I added a few other notes to #19 as well). We may need to manually set the scheme using internal logic(presumably the missing 'isToken' method). Were you planning on using Token's scan method for that check? https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Utility%2...
Cheers
Comment #22
yogeshmpawarComment #23
yogeshmpawarResolved all coding standard issues & added an interdiff as well.
Comment #24
demonde commentedI applied the patch in #23 which works with the URL
[current-page:url:absolute]but it does not work withhttp://twitter.com/share?url=[current-page:url:absolute]&text=[current-page:title]Also sth like
https://[current-page:title]does not work.Comment #25
bramdriesenI tested the patch in #23 and this does seem to work in my case when I put
<a href="https://[my:token]">bla bla</a>But it doesn't work for without the https:// in front of it like so:
<a href="[my:token]">bla bla</a>Comment #26
bramdriesenThis might actually be related to #2944173: CKEditor mangles tokens in URLs, due to bug in Xss::attributes() I think :-)
Comment #28
VishalKumarSahu commented#9 How were you able to achieve it using token_filter module?
Comment #29
ctrladelI've updated the token finding logic to use
\Drupal\Core\Utility\Token::scan()instead of regex, this should address the issues where full tokens worked but tokens in strings were not.There was also a couple issues with the
fromToken()method, the first being that it didn't set a scheme for the parsed uri that was passed toUrl::fromUri(). This is whyhttps://[some:token]worked but just[some:token]token did not. I set it to always to useinternal:, based on the description this seems correct but perhaps we need some extra logic infromToken()to determine the true scheme. The other issue I noticed was that options passed with token paths were not making it to the render array so I added$optionsas an argument to thefromToken()method and pass it through for the call it does toUrl::fromUri()Comment #30
ctrladelComment #31
ctrladelLets try this again without random files included in the patch.
This is functionally identical to #29 and also addresses 2 coding standard issues.
Comment #32
kenton.r commentedI have tested the patch #31 and I get the following error while trying to save a link with a token:
"The path 'token:/user/[user:uid]/requests/new' is invalid."
if I dump the $uri variable on line 154 of LinkWidget.php, it looks like it is geting called twice and the second time it is the following:
"token:token:/user/[user:uid]/requests/new"
When instead of exploding the string I changed it to what is being done with the "route:" scheme with ltrim like:
elseif ($scheme === 'token') {
$displayable_string = ltrim($displayable_string, 'token:');
}
I am able to get it to save and display correctly, but the tokens are never processed.
Were the tokens being processed in "checkTokens"? This "checkTokens" is now being totally bypassed. It should be removed if not needed.
Comment #33
kenton.r commentedWith looking into this more I found that since there are no entity contexts many of the tokens are not available for use in the links url.
Token::replace API
So the tokens that are available are the [site:], [current-page:], [current-user:], and [current-date:]. With any of those token it works. but not with [user:] because it is not aware of the user entity.
The attached patch adds only a workaround for the double token being added to the Uri string. I think this is coming from somewhere in the formvalidtion.
There are also checks for being empty in the URL.php and a removal of the unused "checkTokens" in the linkWidget.php.
Add support for entities
Would there be the possibility of adding support for the current node, user, view, group, comment, term, vocabulary, URL, menu, and file to be collected and made available to this replacement of tokens?
It would be great to be able to use more of the tokens related to entities.
Comment #35
mepperly commented?[current-page:URL] work in the link UI to get the Current Page as link.
Does anyone know the token for the original node URL when the content is in a view? When I use ?[current-page:URL], it goes to the view page itself (naturally).
Thanks,
Meg
Sorry--this should be in a forum, but I don't see how to delete!
Comment #36
mandclu commented+1 for getting this functionality added to core url fields
Comment #37
jamiep commentedCreated a new patch from #33 that allows external URLs to be constructed. Also removes 2 lines that were commented out
Comment #38
bramdriesenThere is still code in comment which doesn't pass the quality check.
Comment #39
mandclu commentedI re-rolled the patch from #37 to remove the line that was commented out.
Comment #40
mandclu commentedHmmm the last patch wouldn't apply, trying a manual update to the paths.
Comment #41
bramdriesenSetting it to needs review for #40
Comment #44
trackleft2Interdiff between patch @comment 40 and MR1076 https://www.drupal.org/files/issues/2021-08-18/interdiff_40_MR1076.txt
Comment #45
vikashsoni commentedAppied patch but not working when trying to add url like [current-page:URL] not working if missing some tell me
Comment #47
effortdee commentedHow do i get this to work? I want the exact same, thanks.
Comment #48
fernly commentedApplying the patch in #40 works for me. In the URL field of a Link field, fill in any available token. There is no "browse tokens" link, so you should look up the tokens somewhere else and paste them into the URL field.
I don't think it's possible to use a token only in the URL field because of URL validation. In my case it was just a GET parameter at the end of a fixed URL.
Comment #49
mradcliffeI added the Needs issue summary update tag so that the issue summary can be formatted with the issue summary template.
Comment #50
trackleft2Comment #51
trackleft2Comment #52
trackleft2Comment #53
trackleft2Comment #54
mradcliffeThank you for the issue summary update! That really helps a subsystem or core maintainer when reviewing the issue. I removed the issue summary update tag and added subsystem maintainer review tag since there are some changes that need discussion (maybe Needs product manager review instead?).
Comment #56
trackleft2I might be wrong about this, but I think if we change the
core/modules/link/src/LinkItemInterface.phpinterface, all implementing classes downstream will have to add the same new methodisToken()or be invalid?Comment #57
abhijith s commentedApplied MR !1076 in 9.5.x and its not working. I've tried the url like this
http://twitter.com/share?url=[current-page:url:absolute]&text=[current-page:title]/node/[node:id]After patch:

Needs work
Comment #59
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #61
abhishek.kumar commentedCan this be reviewed by core maintainers and suggest their view on this ?
Comment #62
bramdriesenVersion should always target the latest version and be back ported when needed.
Comment #64
alt.dev commentedWe faced an issue with this patch.
If the page title has an apostrophe symbol, the \Drupal::service('token')->replace() method will run the Html::escape() method which will convert the apostrophe to the
'HTML symbol. After that, the \Drupal::request()->query->get() function won't be able to extract the whole param and will trim everything after the # symbol since it will be considered as an anchor, and not the query param.I made changes so the patch will use the "replacePlain()" method instead.
Comment #65
alt.dev commentedAdding the patch with the current state of the branch. Works with 10.4.3.
Comment #68
junaidpvRe-rolled #65 for 10.4.5
Comment #71
volegerrebased `9.2.0` against latest `11.x` branch and pushed to `2903336-allow_tokens_for_url` fork branch. I suggest closing MR !1076 and hiding the `9.2.0` fork branch to avoid confusion.
Attaching the patch from the new MR
Comment #74
a.hover commentedRe-based #71 patch against D11 latest (11.4.6).