Closed (fixed)
Project:
REST absolute URLs
Version:
2.0.0
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
17 Jun 2025 at 17:31 UTC
Updated:
9 Oct 2026 at 06:30 UTC
Jump to comment: Most recent
Comments
Comment #4
batigolixComment #5
batigolixComment #6
arjenk commentedNeeds a re-merge, so setting the status back to needs work.
The solution looks good, one suggestion:
preg_match('/<[^>]+>|(?:src|href)=["\']?\//i', $value)Core does in Html::transformRootRelativeUrlsToAbsolute() rewrite more attributes than src/href: data, srcset, .. Could we include them as well? Or simplify to an if for any tag:
if (!str_contains($value, '<'))And it would be nice to have this covered in a unittest.
Comment #7
longwaveIs there a way of narrowing the normalizer so it only applies to field types that should contain formatted markup in the first place?
Comment #8
arjenk commentedGood question, the solution now looks for a setting on the field 'text source', like core does in https://git.drupalcode.org/project/drupal/-/blob/11.4.5/core/modules/tex.... I think that makes the regex if() redundant, so removed.
Tested this with titles like 'Tom & Jerry <3' and 'a < b > c', which were previously broken. Also int and bools are not converted to strings anymore. One side effect, NULL strings now come back as NULL, was "".
Had to merge 8.x-1.x, tested on Drupal 11.4.5 / PHP 8.4, all unittests green. The old unit tests ran, but the helper reimplemented the conversion instead of calling normalize(), so they never tested the class; fixed that too.
Comment #10
andres alvarez commentedTested the current MR branch (3530605-) end-to-end on a fresh Drupal 11 site (DDEV, standard profile, JSON:API enabled) to validate the fix beyond the unit tests.
Created an article node with:
- Title: Tom & Jerry <3 "quotes"
- Body (full_html):
Some text with internal link and
Fetched it via /jsonapi/node/article/{uuid} and confirmed:
- title: returned exactly as stored, no double-encoding. The original bug (ampersands/angle brackets in plain string fields getting mangled) is fixed.
- body.value: relative URLs correctly rewritten to absolute (/internal → https://.../internal, /sites/default/files/pic.jpg → https://.../sites/default/files/pic.jpg).
One limitation found and confirmed not fixable within this normalizer's current design: body.processed (the pre-rendered HTML that many REST/JSON:API consumers read instead of value) is not rewritten. Root cause: core's \Drupal\text\TextProcessed (the real class backing the processed computed property) implements neither StringInterface (so getSupportedTypes() never dispatches this normalizer to it) nor getCastedValue() (so forcing it through would fatal in the parent PrimitiveDataNormalizer::normalize()).
Fixing that properly would require explicitly registering TextProcessed::class in getSupportedTypes(), bypassing parent::normalize() for that branch, and manually reattaching the cacheable metadata (cache tags/contexts/max-age) that TextProcessed exposes via CacheableDependencyInterface — a materially different and riskier change than what this issue set out to fix. I've left the reasoning documented in a docblock on isFormattedText() so it isn't silently reintroduced, and updated the README to make the scope explicit.
Given processed was never handled before this MR either, I'd suggest tracking it as a separate follow-up issue rather than blocking this one on it. Happy to open that if there's interest.
Comment #11
arjenk commentedThanks for the quick reply and the end-to-end test. I have good news: the processed property is already covered by #3360137: Only affecting "value" not "processed" property (MR !6 adds a TextProcessedNormalizer for this), so no new issue is needed. I should have mentioned that i guess.
Your README additions are a good improvement. One request: replace the advice to read value instead of processed with a reference to #3360137; that MR must then update the README.
Comment #12
andres alvarez commentedUpdated the README to point at #3360137 instead of the "read 'value' instead" workaround, since that issue already adds proper 'processed' support.
Comment #13
batigolixMany thanks for testing and reviewing. I revert the most recent documentation changes as they are related to the other issue #3360137: Only affecting "value" not "processed" property
Comment #14
batigolix