From 170e14dae5759395afb1a7c4f8092e1d4f9ada5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 27 Oct 2026 11:28:11 +0100 Subject: [PATCH] fix: product pages no longer serve one visitor's back link to everyone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "back to search results" link took ?ref= as it came and was cached with the page, which ignores ref: the first visitor of a product page set the link for every later one, and a javascript: URL in ref put script into the page for all of them (verified locally). The page now always renders the link hidden and without a target; the backlink Stimulus controller fills in the visitor's own ?ref= and shows it, only for URLs of the same origin. The label stays "zurück zum Suchergebnis": refs only come from the search, and the old check (strpos() !== -1) always picked that label anyway. Co-Authored-By: Claude Opus 5.5 --- .../Classes/Controller/ProductController.php | 6 ----- .../js/controllers/backlink_controller.js | 25 +++++++++++++++++++ .../Partials/Product/HeaderDetail.html | 10 +++----- 3 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 packages/ep_theme/Resources/Private/Assets/js/controllers/backlink_controller.js diff --git a/packages/ep_products/Classes/Controller/ProductController.php b/packages/ep_products/Classes/Controller/ProductController.php index 72bb831..4aaa102 100644 --- a/packages/ep_products/Classes/Controller/ProductController.php +++ b/packages/ep_products/Classes/Controller/ProductController.php @@ -91,10 +91,6 @@ class ProductController extends ActionController $isProductWithGroupInquiryForm = ($concept !== null) && \in_array($concept->getUid(), $groupInquiryFormConceptUids); $nonBookableInfo = $product->getNonBookableInfo(); - // Assemble backlink - $backlinkUrl = $this->request->getQueryParams()['ref'] ?? null; - $backLinkLabel = strpos((string)$backlinkUrl, 'suche') !== -1 ? 'zurück zum Suchergebnis' : 'zurück'; - $this->view->assignMultiple([ 'hotel' => $hotel, 'product' => $product, @@ -106,8 +102,6 @@ class ProductController extends ActionController 'currentPageUid' => $this->request->getAttribute('frontend.page.information')->getId(), 'dateFrom' => $dateFrom, 'dateTo' => $dateTo, - 'referringUrl' => $backlinkUrl, - 'backlinkLabel' => $backLinkLabel, 'nonBookableInfo' => $nonBookableInfo, 'pickupsOverview' => $this->pickupOverviewService->getOverview($product, $hotel), ]); diff --git a/packages/ep_theme/Resources/Private/Assets/js/controllers/backlink_controller.js b/packages/ep_theme/Resources/Private/Assets/js/controllers/backlink_controller.js new file mode 100644 index 0000000..3e1d99d --- /dev/null +++ b/packages/ep_theme/Resources/Private/Assets/js/controllers/backlink_controller.js @@ -0,0 +1,25 @@ +import { Controller } from '@hotwired/stimulus' + +// The page is cached alike for every visitor, so the link back to the visitor's own search is +// taken from ?ref= here, and only when it points to this site: anything else, javascript: URLs +// included, has a different origin +export default class extends Controller { + + connect() { + const ref = new URLSearchParams(window.location.search).get('ref') + if (null === ref) { + return + } + let url + try { + url = new URL(ref, window.location.href) + } catch { + return + } + if (url.origin !== window.location.origin) { + return + } + this.element.href = url.href + this.element.classList.remove('hidden') + } +} diff --git a/packages/ep_theme/Resources/Private/Partials/Product/HeaderDetail.html b/packages/ep_theme/Resources/Private/Partials/Product/HeaderDetail.html index fcb7913..9053d2b 100644 --- a/packages/ep_theme/Resources/Private/Partials/Product/HeaderDetail.html +++ b/packages/ep_theme/Resources/Private/Partials/Product/HeaderDetail.html @@ -55,12 +55,10 @@ - - - {ep:icon(icon: 'chevron-left', class: 'w-4 h-4 text-white')} - {backlinkLabel} - - +