Tokenized URLs in iframe fields are replaced and saved as plain values when editing content

Created on 11 February 2025, 19 days ago

Problem/Motivation

When using tokenized URLs in an iframe field to dynamically pass parameters to an external service to an external service, such as synchronizing languages between the iframe and Drupal, the URLs are unexpectedly saved with the token-replaced values during content editing, even though tokenized string should be preserved.
This behavior conflicts with the expected functionality of "Token Support" for iframe fields.

Examples include using a token like `[current-page:content-language:langcode]` in the URL field to ensure the iframe reflects the current Drupal page's language (`https://example.com?lang=[current-page:content-language:langcode]`). Instead of retaining the tokenized string format after editing, the URL is saved as `https://example.com?lang=en` (with the token replaced), breaking the intended dynamic behavior.

Steps to reproduce

1. Configure an iframe field in a content type and set the "Token Support" option to "Tokens for title and URL field".

2. Create a new content entity and fill the iframe URL field with a tokenized string such as `https://example.com?lang=[current-page:content-language:langcode]`.

3. Save the content and reopen the edit form:
- Issue: You will see that the token has been replaced in the URL field (e.g., `https://example.com?lang=en` is now stored as the value).

4. To verify what goes wrong:
- Set "Token Support" to "No tokens allowed."
- Enter the tokenized URL (`https://example.com?lang=[current-page:content-language:langcode]`) and save your changes. The tokenized string will be stored as entered and displayed correctly when the edit form is reopened (without replacement).
- Switch "Token Support" back to "Tokens for title and URL field," and observe that the token is dynamically replaced at runtime to reflect the current language, as expected (e.g., it shows `https://example.com?lang=en` on the rendered output and changes when switching languages).

5. Attempt to edit the URL value again. You will observe that the token is replaced and saved as its resolved value once more, breaking the tokenized functionality.

Proposed resolution

Upon investigating the `IframeWidgetBase::validateUrl` function, the issue appears to be in the following section of the code:

public function validateUrl($element, FormStateInterface $form_state, $form) {  
  // Replace any tokens.  
  $settings = $this->getFieldSettings();  
  if (isset($settings['tokensupport']) && $settings['tokensupport'] == 2) {  
    $element['#value'] = $this->token->replace($element['#value'], ['user' => $this->currentUser]);  
  }  
  
  // Use Drupal core's LinkWidget to validate the URL.  
  LinkWidget::validateUriElement($element, $form_state, $form);  
}

When the `validateUrl` method replaces tokens using `$this->token->replace`, it passes the modified `$element` to `LinkWidget::validateUriElement`. This method seems to manipulate somehow the `$form_state->values`, storing the token-replaced URL (`https://example.com?lang=en`) instead of leaving the original tokenized string intact (`https://example.com?lang=[current-page:content-language:langcode]`).

I don't know how to better handle this situation.
One way could be to simply skip the token replacement in the validation if tokens are allowed.

🐛 Bug report
Status

Active

Version

3.0

Component

Miscellaneous

Created by

🇩🇪Germany LudwigJP

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024