Problem/Motivation
The problem is, when the "Summary or trimmed" or "Trimmed" field formatters do their thing, they first apply the text filter and then text_summary() will either return the same value (if no trimming is necessary) which is already marked as "safe" or will return a trimmed value, which is just a plain string (and so not marked as safe).
Then in \Drupal\Core\Render\Renderer->ensureMarkupIsSafe(), if it's a plain string (and so not marked as safe) it'll additionally run Xss::filter() on the output, which will remove stuff, even if it's allowed by the text format!
Steps to reproduce
- Install Drupal from 11.x HEAD with the Standard profile
- Select the Full HTML format when creating the following Article nodes as it doesn't filter by "Limit allowed HTML". The use case are dangerous things like iframes or script tags or inline styles. Not advisable, but there is a use case for it for admin users.
- Create an "Article" node with
<div style="color: red">red text</div>followed by less than 600 characters of text - Create an "Article" node with
<div style="color: red">red text</div>followed by more than 600 characters of text - On the node view page for both nodes, the text at the top will be red -- this is expected, because the text filter allows it
- Go to the front page - you'll see that one node (the one with less than 600 characters) shows the text in red, but the other (the one with greater than 600 characters) does not
Proposed resolution
If filtered markup is passed to the `#pre_render` callback, that summarizes the text, return filtered markup instead of a plain string.
Remaining tasks
Review
User interface changes
NA
Introduced terminology
NA
API changes
NA
Data model changes
NA
Release notes snippet
NA
| Comment | File | Size | Author |
|---|---|---|---|
| #48 | drupal-core-2922569-48.patch | 1.15 KB | dsnopek |
Issue fork drupal-2922569
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
dsnopekComment #3
dsnopekComment #6
dsnopekHere's a patch that works in limited manual testing!
Comment #7
andkar commentedThanks, this works for me.
Drupal version 8.6.13
Comment #8
joe_carvajalReroll for 8.8.
Comment #9
joe_carvajalSorry, wrong patch, This is a correct reroll for 8.8 version.
Comment #15
smustgrave commentedThis almost sounds like a bug, which would need a test case.
This also should be retested in D10 to see if still an issue and we can go from there.
Comment #17
shmy commentedI've reproduced the issue with current 11.x HEAD and updated the steps in issue summary.
Comment #18
shmy commentedComment #20
shmy commentedI've extended the patch (interdiff_9_19) by a safety check to ensure only markup, that is already passed as filtered, is back-casted from string. I'm not sure if the taken approach is sufficient.
Comment #21
shmy commentedAs the
ensureMarkupIsSaferenderer method the treatsMarkupInterfaceas safe andTextTrimmedFormatter::preRenderSummaryis a public static method and therefore may be called within a different context by contrib/custom modules (e.g. a render element that doesn't preserve the#pre_rendercallbackpreRenderText) iv'e tried to find a more generic implementation but asMarkupInterfacedoesn't dictate the `::create` method i couldn't find a practical approach.As test coverage is needed anyway i hope to have some time in the next days and extend an existing ones or add a new one if necessary.
Comment #22
wim leersMinor remarks, looking good :)
Comment #23
shmy commentedAs the implemented solution has been approved during review, i belief the proposed solution and remaining task can be updated in the issue summary. Back to review.
Comment #24
smustgrave commentedGoing to find out if this falls under BC policy as this could change the display on existing sites which might not be desired.
Comment #26
smustgrave commentedBrought this up in slack #needs-review-queue-initative https://drupal.slack.com/archives/C04CHUX484T/p1708719216555289
I asked if this would be a D11 fix only because of the backwards compatibility impact and @catch replied "It wouldn't make it 11.x only but we might have to put it behind a settings.php switch or feature flag"
So maybe a field formatter setting could cover it? Know smart trim has something like that.
Comment #27
shmy commentedThanks for taking care of BC.
I think the required change depends on issue classification.
In my eyes this is a bug fix, not a feature request, because as a user (i.e. site builder) i don't expect that my hard-coded markup is filtered out when summarized.
Since the activity (and probably demand) for a fix seems not very high why not make it 11.x only?
Comment #28
dsnopekHere's a version of the latest patch for Drupal 10.3 without the tests, for folks who want to include this in their composer.json.
Comment #30
smustgrave commentedSo we definitely missed the D11 boat but maybe this can make D12?
With regards to feature flags, we did something similar with layout builder using a module as a flag.
Comment #34
smustgrave commentedComment #36
smustgrave commentedFixed up the MR for main. I broke out the text_with_summary to it's own test so it can be easily removed when we deprecate text_with_summary
Comment #37
shmy commentedThanks for updating the MR.
Regarding the feature flag, i'm assuming thats opt-in? If so i'm worried that the fix will be just a dead end. I can't remember when / if i ever looked up if there is something behind a feature flag and instead chose contrib / custom.
I still thing that is a bug fix, but may change the markup in an unexpected way and therefore opt-in is just the most practical solution.
The field formatter settings would make it at least a reachable option, so i would favor that appraoch.
Comment #38
smustgrave commentedThis actually needs a summary update but it’s not an opt in feature as it’s fixing a bug.
Comment #39
shmy commentedAs there is no API for feature flags yet (#3423352) the flag would need to be implemented as a text submodule, like done in layout builder in #3432874?
Comment #40
smustgrave commentedThat was just a temporary stop gap. The module is being marked obsolete and deleted
Comment #41
shmy commentedI see, misread that. Then its just a field formatter setting.
Comment #42
shmy commentedI've reviewed the previous commits on the MR, these do look okay.
I'm not sure if that's how its supposed to be, but the behavior of the
text_summary()function is not as i would expect. I.e. it doesn't subtract the HTML tag length when determining the output length. OnTextFormatterTest::L108andTextFormatterTest::L149i would expect that the output is 17 chars (the length of the iframe tag) longer.A more lengthy tag or heavily nested ones, in combination with a short trim length, may yield an empty output string or just expose the HTML markup without the actual content.
Comment #43
smustgrave commentedNot sure I agree with the field formatter setting but that now changes trajectory of this ticket
Comment #44
smustgrave commentedComment #45
shmy commentedSo do we continue or replace it with a module setting instead?
A correction on the
text_summary()function note above: All of the lines should be longer, not only the most recently added ones.Found Strip tags from formatted text before trimming, which already had an MR. Added as related.
Comment #46
smustgrave commentedNice find, I do think we are achieving the same thing as the issue mentioned. Lets continue over there. Am giving credit to this issue.
Comment #48
dsnopekHere's patch rerolled for D11 without tests