Problem/Motivation
If the HtmlTag render element is passed a value that is plain text (does not implement MarkupInterface) but resembles HTML (contains a < character followed by a letter) then the markup is corrupted.
Steps to reproduce
Example code - the title for an article about HTML.
$build = [
'#type' => 'html_tag',
'#tag' => 'h2', '#value' => 'How to use the <script> tag'
];
\Drupal::service('renderer')->renderPlain($build);
Actual output: <h2>How to use the tag</h2>
Expected output: <h2>How to use the <script> tag</h2>
For a real-life example, I hit this using TitleFormatter
from the module
Manage Display →
.
Proposed resolution
The problem is this code in ::preRenderHtmlTag
:
$element['#markup'] = Markup::create(Xss::filterAdmin($element['#value']));
The code assumes that if the input is not safe-markup then it is unsafe markup. This is contrary to the assumption elsewhere in the Drupal render system that text would be automatically escaped. The class comment confirms this expectation, describing this parameter as a string, not as markup:
#value: (string, optional) A string containing the textual contents of the tag.
This suggests that the correct code is like this:
$element['#markup'] = new HtmlEscapedText($element['#value']);
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet