From 903292d84c9e8e5e5dad3ed17eb9e23ff092041a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 27 Oct 2026 11:41:18 +0100 Subject: [PATCH] feat: products can have their own text in the subsite popup The popup that announces the switch to another site (e.g. from a teaser on ep-reisen.de to semesterende-skireisen.de) showed the text of the product's concept for every product. A product now has an optional popup text (new "Popup" tab) that replaces the concept's; empty, the concept's text stays. Title, image and button remain the concept's, and whether a popup appears at all is still up to the concept. Teasers pass the product to the popup request. Pages cached before the deploy request it without one and get the concept's text, as before. The new column tx_epproducts_domain_model_product.popup_text is the only pending schema change; the deploy's extension:setup adds it. Co-Authored-By: Claude Opus 5.5 --- .../Controller/AjaxTeaserPopupController.php | 9 ++++++++- .../Classes/Domain/Model/Product.php | 17 +++++++++++++++++ .../TCA/tx_epproducts_domain_model_product.php | 13 +++++++++++++ packages/ep_products/ext_tables.sql | 3 ++- .../Private/Partials/Product/Teaser.html | 2 +- .../Templates/AjaxTeaserPopup/Concept.html | 2 +- 6 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/ep_products/Classes/Controller/AjaxTeaserPopupController.php b/packages/ep_products/Classes/Controller/AjaxTeaserPopupController.php index c972d80..9d5b4ee 100644 --- a/packages/ep_products/Classes/Controller/AjaxTeaserPopupController.php +++ b/packages/ep_products/Classes/Controller/AjaxTeaserPopupController.php @@ -4,14 +4,21 @@ namespace EP\EpProducts\Controller; use Psr\Http\Message\ResponseInterface; use EP\EpProducts\Domain\Model\Concept; +use EP\EpProducts\Domain\Model\Product; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class AjaxTeaserPopupController extends ActionController { - public function conceptAction(Concept $concept, string $targetUrl): ResponseInterface + public function conceptAction(Concept $concept, string $targetUrl, ?Product $product = null): ResponseInterface { + // A product can have its own text; title, image and button stay those of the concept + $popupText = (string)$product?->getPopupText(); + if ('' === trim(strip_tags($popupText))) { + $popupText = $concept->getPopupText(); + } $this->view->assignMultiple([ 'concept' => $concept, + 'popupText' => $popupText, 'targetUrl' => $targetUrl, ]); return $this->htmlResponse(); diff --git a/packages/ep_products/Classes/Domain/Model/Product.php b/packages/ep_products/Classes/Domain/Model/Product.php index a4c1ea5..bde2968 100644 --- a/packages/ep_products/Classes/Domain/Model/Product.php +++ b/packages/ep_products/Classes/Domain/Model/Product.php @@ -279,6 +279,11 @@ class Product extends AbstractEntity implements TeaserInterface */ protected $nonBookableInfo; + /** + * @var string + */ + protected $popupText = ''; + public function __construct() { $this->initStorageObjects(); @@ -1146,6 +1151,18 @@ class Product extends AbstractEntity implements TeaserInterface $this->tourThumbnail = $tourThumbnail; } + public function getPopupText() + { + return $this->popupText; + } + + public function setPopupText($popupText): static + { + $this->popupText = $popupText; + + return $this; + } + public function getTourLink() { return $this->tourLink; diff --git a/packages/ep_products/Configuration/TCA/tx_epproducts_domain_model_product.php b/packages/ep_products/Configuration/TCA/tx_epproducts_domain_model_product.php index bc8d56c..b0cb13b 100644 --- a/packages/ep_products/Configuration/TCA/tx_epproducts_domain_model_product.php +++ b/packages/ep_products/Configuration/TCA/tx_epproducts_domain_model_product.php @@ -41,6 +41,7 @@ return [ tour_thumbnail, --div--;Bewertung, --palette--;;rating, testimonials, --div--;Buchbarkeit, non_bookable_dates, + --div--;Popup, popup_text, --div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language, sys_language_uid, l10n_parent', ], ], @@ -876,6 +877,18 @@ return [ 'maxitems' => 1, ], ], + 'popup_text' => [ + 'exclude' => 0, + 'label' => 'Popup Text', + 'description' => 'Ersetzt für dieses Produkt den Popup-Text des Konzepts. Leer: Text des Konzepts. Ob ein Popup erscheint, legt weiterhin das Konzept fest.', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 5, + 'eval' => 'trim', + 'enableRichtext' => true, + ], + ], 'non_bookable_info' => [ 'exclude' => 0, 'label' => 'Infobox nicht buchbar', diff --git a/packages/ep_products/ext_tables.sql b/packages/ep_products/ext_tables.sql index 2a54011..2a1d996 100644 --- a/packages/ep_products/ext_tables.sql +++ b/packages/ep_products/ext_tables.sql @@ -65,7 +65,8 @@ CREATE TABLE tx_epproducts_domain_model_product badge int(11) unsigned NOT NULL default '0', non_bookable_info int(11) unsigned NOT NULL default '0', non_bookable_dates varchar(255) DEFAULT '' NOT NULL, - min_price int(11) unsigned NOT NULL default '0', + popup_text text NOT NULL, + min_price int(11) unsigned NOT NULL default '0', tstamp int(11) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL, cruser_id int(11) unsigned DEFAULT '0' NOT NULL, diff --git a/packages/ep_theme/Resources/Private/Partials/Product/Teaser.html b/packages/ep_theme/Resources/Private/Partials/Product/Teaser.html index e54e2dd..f0d1db4 100644 --- a/packages/ep_theme/Resources/Private/Partials/Product/Teaser.html +++ b/packages/ep_theme/Resources/Private/Partials/Product/Teaser.html @@ -71,7 +71,7 @@