Problem/Motivation
We noticed that ampersands were being double-escaped when smart_trim was involved with processing a field for display via EntityViewDisplay. This happened when the render array that was created had #format set to NULL.
The format is expected to be provided by $item in the viewElements() function of the SmartTrimFormatter.
See https://git.drupalcode.org/project/smart_trim/blob/8.x-1.2/src/Plugin/Fi...
Proposed resolution
At the moment I've written a workaround using hook_entity_display_build_alter to set the #format to 'basic_html' when #formatter is set to "smart_trim". But it feels like the format should be set in the configuration for the field or field formatter somewhere...
If someone could show me the correct way to set #format for the smart_trim field formatter that would be great, thanks!
Here's some code which seems to work for us at the moment:
/**
* Fix double-escaped output.
*
* Set default #format to basic_html for fields processed by smart_trim.
* (Only when the #format key exists and is set to NULL).
*
* Implements hook_entity_display_build_alter().
*
* @param array $build
* @param array $context
* @return void
*/
function mymodule_entity_display_build_alter(&$build, $context) {
// Loop through fields being built for display.
foreach (Element::children($build) as $field_name) {
// Use local variable to work with field element.
$element =& $build[$field_name];
// Only consider fields being formatted by smart_trim.
if (isset($element['#formatter']) && $element['#formatter'] == 'smart_trim') {
// Loop over render arrays built by smart_trim.
foreach (Element::children($element) as $item_key) {
if (!isset($element[$item_key]['#type'])) {
continue;
}
// Set default value to 'basic_html'.
if (
$element[$item_key]['#type'] == 'processed_text' &&
array_key_exists('#format', $element[$item_key]) &&
is_null($element[$item_key]['#format'])
) {
$element[$item_key]['#format'] = 'basic_html';
}
}
}
}
}
| Comment | File | Size | Author |
|---|---|---|---|
| #24 | 3108420-fix-2.1.0-24.patch | 743 bytes | a.dmitriiev |
| #12 | add_format_setting-3108420-12.patch | 2.51 KB | dennis_meuwissen |
| #11 | add_format_setting-3108420-11.patch | 2.52 KB | a.dmitriiev |
| #4 | add_format_setting-3108420-4.patch | 2.15 KB | mcgowanm |
| #2 | add_format_setting-3108420-2.patch | 2.73 KB | p-neyens |
Issue fork smart_trim-3108420
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
p-neyens commentedAt the moment there is no setting for the format.
In the provided patch i added a setting for the format. The patch is based on the field formatter "Advanced Text" of the advanced_text_formatter module.
I hope it is enough.
Comment #3
p-neyens commentedComment #4
mcgowanm commentedI tweaked the patch a bit so by default it defers to trying to use the item's format and only asserts a format when one is explicitly set.
Comment #5
markie commentedHi there,
Can you please checkout the issue fork and add your patch to it? We are trying to test the fork / merge system.
Comment #8
kevin.- commentedComment #9
a.dmitriiev commentedThe patch #4 works for me, thanks. As by default the format is plain_text, make sure that you changed it to some that has HTML processing so that the problem with encoded ampersands is solved, because plain_text still shows them encoded for me (maybe it is some cache related problem).
Also patch worked for 1.3 version.
Thanks.
Comment #10
ultimikeI think adding a "Format" select box to the formatter configuration will be a bit confusing for most users (including me). I don't understand why we can't just set the format to "plain_text" when it is not set - why do we need to add the Format select? If the Format select is absolutely necessary, then there should definitely be some help text explaining why it is there. Maybe even hide it in a closed-by-default "Advanced" fieldset?
Also, let's move this to the 2.0.x branch.
Finally, this needs a (unit, preferably) test.
-mike
Comment #11
a.dmitriiev commentedRe-roll the patch for 2.1.x branch
Comment #12
dennis_meuwissen commentedThe patch from #11 contains a mistake in line 65, this is probably supposed to be
$format ?: $item->formatinstead of$format ?? $item->format. Otherwise leaving the format selector set to Default will use an empty string as the text format, which does not exist and causes a "Missing text format ." in the Drupal logs. And the output of the formatter will be blank. Attached is a patch with that issue fixed.Comment #13
ultimikeThanks to everyone for their assistance with this one so far.
Before we move forward with a fix, we really need to write a test for this issue. In order to do that, we need a set of clear instructions to reproduce the issue. Here's what I did (on the 2.1.x branch).
When viewing the Smart Trimmed field, the output is: "Fire & ice". I assume this is the issue.
Looking at both the MR and recent patch, I'm not sure why a new "Filter" config is necessary (or wanted). Both the patch and the MR allow the site builder to select the text format to be used for the smart trimmed content. Why should this be an option? Why shouldn't the smart trimmed content use the same filter as field? What am I missing here?
If the issue is just the fact that when a plain text field is smart trimmed, it outputs & instead of &, then that is the issue that needs to be fixed.
Thoughts?
-mike
Comment #14
lostcarpark commentedSo what I think is happening:
&but the format rules aren't generally modifying this.&, but as Smart Trim already encoded it, the resultant double occurs.The Format selector in the patch feels like a hack to me. and it feels a bit of a blunt instrument to add a default format to the FieldWidget in case the format isn't specified.
I'm left wondering should it be Smart Trim's job to encode the
&at all? If the field format is going to take care of encoding, should we not just leave encoding for the format to encode if require?If encoding
&is required when the field is formatted, then I would suggest adding a check of the format, and if not specified, convert the&back to&rather than add a new property to Smart Trim.Comment #15
markie commentedI do remember there was an issue a long time ago about the ampersand being borked after trimming, so I do want to make sure our output is encoded. I definitely don't want to add a new property or setting as we are trying to stream line the config... pondering...
either way this needs tests and the MR needs updating to the latest branch (though I think I can do it)
Comment #18
ultimikeComment #19
ultimikeSoooo - I learned a lot about issue forks on this task - hence all the branches and what not. Thanks to @xjm at Drupal Dev Days for showing me how to create a new issue fork branch and MR - this is a skill I'll be utilizing in the future.
Regardless, I believe I found a much simpler solution for this issue, and have added tests to demonstrate.
D10 tests are passing. D9 tests will pass once #3365797: Read more link always displayed in some settings is merged into 2.1.x
-mike
Comment #20
lostcarpark commentedI agree with the approach here. The test looks good.
The pipeline failed, but it seems to be a reflection error on TruncateHTMLTest, so I suspect the problem may be the branch you are merging against, and nothing to do with this change. Hopefully some tinkering with the repo can fix that.
Comment #21
ultimikeLooks good to me!
-mike
Comment #23
markie commentedThanks for the help. Merged MR and added to changelog for next release.
Comment #24
a.dmitriiev commentedUploading the patch for version 2.1.0 (without test), because there is no new stable version that includes the patch yet.
Comment #25
lostcarpark commentedJust for future reference, you can get the patch file by appending
.patchto the MR URL.For example, the patch link here is: https://git.drupalcode.org/project/smart_trim/-/merge_requests/62.patch
There is no need to upload patch files when using merge requests.
Comment #26
a.dmitriiev commentedThe change to tests doesn't apply to 2.1.0, that is why the patch was uploaded with only change to formatter class. I am not trying to hunt for credits here.
Comment #28
norman.lolThere's one famous downside to using MR patches. Imagine someone else pushes new code to the MR. The patch will change. Now imagine someone pushes malicious code to the MR. And you pull it in without knowing.
Static patches are still the preferred method until GitLab lets us pull in patches by commit reference.
Comment #29
lostcarpark commented@leymannx, while I agree static patches are best, it's not necessary to upload the patch file just so it can be statically linked. I save all patches a directory in my project repository so Composer is only applying local patches. That prevents any danger from the patch (whether a file or auto-generated from MR) being modified, or just getting deleted from the issue thread, and ensures the patches being applied are what you think they are.
I do take the point that patch files are still useful for applying the change to a different version branch.
Comment #30
yannickooFYI it's also possible to open a specific commit in GitLab and then just append
.patchwhich might be safer when downloading patches from remote.