From 483fb328ad3cff244480180e45d23d366361666f Mon Sep 17 00:00:00 2001 From: i-just Date: Tue, 3 Feb 2026 14:07:29 +0100 Subject: [PATCH 1/3] prevent an infinite loop where getting translation key triggers normalization over and over --- src/fields/Link.php | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/fields/Link.php b/src/fields/Link.php index 79add605d73..8df24adab41 100644 --- a/src/fields/Link.php +++ b/src/fields/Link.php @@ -511,23 +511,34 @@ public function normalizeValue(mixed $value, ?ElementInterface $element): mixed $value instanceof LinkData && $element?->propagating && ($element->propagateAll || ($element->isNewForSite && !isset($element->duplicateOf))) && - isset($element->propagatingFrom) && - $this->getTranslationKey($element) !== $this->getTranslationKey($element->propagatingFrom) + isset($element->propagatingFrom) ) { - $linkedElement = $value->getElement(); - if ($linkedElement && $linkedElement::isLocalized()) { - $localizedQuery = $linkedElement->getLocalized(); - if ( - $localizedQuery instanceof ElementQueryInterface && - $localizedQuery->siteId($element->siteId)->exists() - ) { - $type = $value->getType(); - $value = [ - 'type' => $type, - 'value' => sprintf('{%s:%s@%s:url}', $linkedElement::refHandle(), $linkedElement->id, $element->siteId), - ]; + // in order to avoid infinite loop when using custom translation format with a translation key containing `include()` + // we need to prevent `View::renderObjectTemplate()` from trying to normalize this value again and again + // to do that, we can e.g. set `propagating` to false before getting the translation key + // see https://github.com/craftcms/cms/issues/18363 for more details + $originalPropagating = $element->propagating; + if ($this->translationMethod === self::TRANSLATION_METHOD_CUSTOM) { + $element->propagating = false; + } + if ($this->getTranslationKey($element) !== $this->getTranslationKey($element->propagatingFrom)) { + $linkedElement = $value->getElement(); + if ($linkedElement && $linkedElement::isLocalized()) { + $localizedQuery = $linkedElement->getLocalized(); + if ( + $localizedQuery instanceof ElementQueryInterface && + $localizedQuery->siteId($element->siteId)->exists() + ) { + $type = $value->getType(); + $value = [ + 'type' => $type, + 'value' => sprintf('{%s:%s@%s:url}', $linkedElement::refHandle(), $linkedElement->id, $element->siteId), + ]; + } } } + // and we need to set `propagating` back to what it was at the beginning + $element->propagating = $originalPropagating; } if ($value instanceof LinkData) { From 006950b678c6bb3fba9aedeba30315e637379660 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 3 Feb 2026 08:31:28 -0800 Subject: [PATCH 2/3] Cleanup --- src/fields/Link.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fields/Link.php b/src/fields/Link.php index 8df24adab41..7407870b72c 100644 --- a/src/fields/Link.php +++ b/src/fields/Link.php @@ -517,10 +517,10 @@ public function normalizeValue(mixed $value, ?ElementInterface $element): mixed // we need to prevent `View::renderObjectTemplate()` from trying to normalize this value again and again // to do that, we can e.g. set `propagating` to false before getting the translation key // see https://github.com/craftcms/cms/issues/18363 for more details - $originalPropagating = $element->propagating; if ($this->translationMethod === self::TRANSLATION_METHOD_CUSTOM) { $element->propagating = false; } + if ($this->getTranslationKey($element) !== $this->getTranslationKey($element->propagatingFrom)) { $linkedElement = $value->getElement(); if ($linkedElement && $linkedElement::isLocalized()) { @@ -537,8 +537,9 @@ public function normalizeValue(mixed $value, ?ElementInterface $element): mixed } } } - // and we need to set `propagating` back to what it was at the beginning - $element->propagating = $originalPropagating; + + // set $propagating back to true + $element->propagating = true; } if ($value instanceof LinkData) { From 2b3df037019c53495a11346f5644309cb873e4ec Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Tue, 3 Feb 2026 08:32:50 -0800 Subject: [PATCH 3/3] Release note [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a49f99fd9b3..cec4b0f1641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Fixed a bug where newly-selected elements weren’t being rendered correctly for relational fields set to the “Card grid” view mode. ([#18362](https://github.com/craftcms/cms/issues/18362)) - Fixed a bug where card previews weren’t getting updated when a selected field was removed from the field layout. - Fixed potential JavaScript errors that could occur if a disclosure menu’s trigger or target elements were missing. ([#18358](https://github.com/craftcms/cms/issues/18358)) +- Fixed an infinite recursion bug. ([#18363](https://github.com/craftcms/cms/issues/18363)) ## 5.9.5 - 2026-01-31