diff --git a/Api/Data/VisualInterface.php b/Api/Data/VisualInterface.php new file mode 100644 index 00000000..0441ad12 --- /dev/null +++ b/Api/Data/VisualInterface.php @@ -0,0 +1,31 @@ +request->getParam('product_id'); + $itemId = (string) $this->request->getParam('item_id'); $cardType = $this->request->getParam('card_type'); - $itemHtml = $cardType ? $this->cacheHelper->load((int)$productId, $cardType) : - $this->cacheHelper->load((int)$productId); + $itemHtml = $cardType ? $this->cacheHelper->load($itemId, $cardType) : + $this->cacheHelper->load($itemId); $response = $this->httpFactory->create(); $response->appendBody($itemHtml); diff --git a/Helper/Cache.php b/Helper/Cache.php index 2aeff9e6..ec98b2d5 100644 --- a/Helper/Cache.php +++ b/Helper/Cache.php @@ -47,29 +47,29 @@ public function __construct( } /** - * @param int $productId + * @param string $itemId * @param string $cardType * @return string * @throws LocalizedException * @throws NoSuchEntityException */ - public function load(int $productId, string $cardType = 'default'): string + public function load(string $itemId, string $cardType = 'default'): string { - $result = $this->cache->load($this->getCacheKey($productId, $cardType)); + $result = $this->cache->load($this->getCacheKey($itemId, $cardType)); return $result ? $result : ''; } /** * @param string $data - * @param int $productId + * @param string $itemId * @param string $cardType * @return void * @throws LocalizedException * @throws NoSuchEntityException */ - public function save(string $data, int $productId, string $cardType = 'default'): void + public function save(string $data, string $itemId, string $cardType = 'default'): void { - $this->cache->save($data, $this->getCacheKey($productId, $cardType)); + $this->cache->save($data, $this->getCacheKey($itemId, $cardType)); } /** @@ -128,13 +128,13 @@ public function isHyvaTheme(): bool } /** - * @param int $productId + * @param string $itemId * @param string $cardType * @return string * @throws LocalizedException * @throws NoSuchEntityException */ - private function getCacheKey(int $productId, string $cardType): string + private function getCacheKey(string $itemId, string $cardType): string { $storeId = $this->storeManager->getStore()->getId(); $customerGroupId = $this->customerSession->getCustomerGroupId(); @@ -143,7 +143,7 @@ private function getCacheKey(int $productId, string $cardType): string '%s_%s_%s_%s_%s', $storeId, $customerGroupId, - $productId, + $itemId, $cardType, self::REDIS_CACHE_KEY ); diff --git a/Model/Catalog/Layer/Url/Strategy/QueryParameterStrategy.php b/Model/Catalog/Layer/Url/Strategy/QueryParameterStrategy.php index f867334f..aa89e8c7 100644 --- a/Model/Catalog/Layer/Url/Strategy/QueryParameterStrategy.php +++ b/Model/Catalog/Layer/Url/Strategy/QueryParameterStrategy.php @@ -161,10 +161,7 @@ protected function getCurrentQueryUrl(MagentoHttpRequest $request, array $query) { $selectedFilters = $request->getQuery(); $reservedParams = [ - self::PARAM_LIMIT, - self::PARAM_MODE, self::PARAM_PAGE, - self::PARAM_ORDER, self::PARAM_CATEGORY, ]; diff --git a/Model/Catalog/Product/Collection.php b/Model/Catalog/Product/Collection.php index ae215fef..a4a1752a 100644 --- a/Model/Catalog/Product/Collection.php +++ b/Model/Catalog/Product/Collection.php @@ -9,11 +9,16 @@ namespace Tweakwise\Magento2Tweakwise\Model\Catalog\Product; +use Exception; +use Tweakwise\Magento2Tweakwise\Model\Config; +use Tweakwise\Magento2Tweakwise\Model\Enum\ItemType; +use Tweakwise\Magento2Tweakwise\Api\Data\VisualInterface; use Tweakwise\Magento2Tweakwise\Model\Catalog\Layer\NavigationContext; use Tweakwise\Magento2Tweakwise\Model\Client\Request\ProductSearchRequest; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\Indexer\Product\Flat\State; use Magento\Catalog\Model\Product\OptionFactory; +use Tweakwise\Magento2Tweakwise\Model\VisualFactory; use Magento\Catalog\Model\ResourceModel\Helper as CatalogResourceHelper; use Magento\Catalog\Model\ResourceModel\Url; use Magento\Customer\Api\GroupManagementInterface; @@ -41,7 +46,29 @@ class Collection extends AbstractCollection protected $navigationContext; /** - * {@inheritdoc} + * @param CollectionEntityFactory $entityFactory + * @param LoggerInterface $logger + * @param FetchStrategyInterface $fetchStrategy + * @param ManagerInterface $eventManager + * @param EavConfig $eavConfig + * @param ResourceConnection $resource + * @param EavEntityFactory $eavEntityFactory + * @param CatalogResourceHelper $resourceHelper + * @param UniversalFactory $universalFactory + * @param StoreManagerInterface $storeManager + * @param Manager $moduleManager + * @param State $catalogProductFlatState + * @param ScopeConfigInterface $scopeConfig + * @param OptionFactory $productOptionFactory + * @param Url $catalogUrl + * @param TimezoneInterface $localeDate + * @param Session $customerSession + * @param DateTime $dateTime + * @param GroupManagementInterface $groupManagement + * @param NavigationContext $navigationContext + * @param VisualFactory $visualFactory + * @param Config $config + * @param AdapterInterface|null $connection */ public function __construct( CollectionEntityFactory $entityFactory, @@ -64,6 +91,8 @@ public function __construct( DateTime $dateTime, GroupManagementInterface $groupManagement, NavigationContext $navigationContext, + private readonly VisualFactory $visualFactory, + private readonly Config $config, AdapterInterface $connection = null ) { parent::__construct( @@ -139,9 +168,40 @@ protected function _afterLoad() $this->applyCollectionSizeValues(); + if ($this->config->isPersonalMerchandisingActive()) { + $this->addVisuals(); + } + return $this; } + /** + * @return void + */ + protected function addVisuals(): void + { + try { + $response = $this->navigationContext->getResponse(); + } catch (Exception $e) { + return; + } + + foreach ($response->getItems() as $item) { + if ($item->getValue('type') !== ItemType::VISUAL->value) { + continue; + } + + /** @var VisualInterface $visual */ + $visual = $this->visualFactory->create(); + $visual->setId($item->getValue('itemno')); + $visual->setImageUrl($item->getImage()); + $visual->setUrl($item->getUrl()); + $itemPosition = array_search($item, $response->getItems()); + + array_splice($this->_items, $itemPosition, 0, [$visual]); + } + } + /** * {@inheritdoc} */ diff --git a/Model/Enum/ItemType.php b/Model/Enum/ItemType.php new file mode 100644 index 00000000..0b5c1098 --- /dev/null +++ b/Model/Enum/ItemType.php @@ -0,0 +1,10 @@ +getData(self::IMAGE_URL); + } + + /** + * @param string $imageUrl + * @return VisualInterface + */ + public function setImageUrl(string $imageUrl): VisualInterface + { + return $this->setData(self::IMAGE_URL, $imageUrl); + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->getData(self::URL); + } + + /** + * @param string $url + * @return VisualInterface + */ + public function setUrl(string $url): VisualInterface + { + return $this->setData(self::URL, $url); + } +} diff --git a/ViewModel/LinkedProductListItem.php b/ViewModel/LinkedProductListItem.php index cd76b70d..6072717d 100644 --- a/ViewModel/LinkedProductListItem.php +++ b/ViewModel/LinkedProductListItem.php @@ -5,12 +5,14 @@ namespace Tweakwise\Magento2Tweakwise\ViewModel; use Magento\Catalog\Model\Product; +use Magento\Customer\Model\Session; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\View\Element\AbstractBlock; use Magento\Framework\View\Element\Block\ArgumentInterface; use Magento\Framework\View\LayoutInterface; use Tweakwise\Magento2Tweakwise\Helper\Cache; +use Magento\Store\Model\StoreManagerInterface; class LinkedProductListItem implements ArgumentInterface { @@ -20,7 +22,9 @@ class LinkedProductListItem implements ArgumentInterface */ public function __construct( private readonly LayoutInterface $layout, - private readonly Cache $cacheHelper + private readonly Cache $cacheHelper, + private readonly StoreManagerInterface $storeManager, + private readonly Session $customerSession ) { } @@ -48,7 +52,7 @@ public function getItemHtml( ); } - $productId = (int) $product->getId(); + $productId = (string) $product->getId(); $cardType = str_replace(' ', '_', $params['card_type']); if (!$this->cacheHelper->load($productId, $cardType)) { $itemHtml = $this->getItemHtmlWithRenderer( @@ -59,10 +63,15 @@ public function getItemHtml( $this->cacheHelper->save($itemHtml, $productId, $cardType); } + $storeId = $this->storeManager->getStore()->getId(); + $customerGroupId = $this->customerSession->getCustomerGroupId(); + return sprintf( - '', + '', Cache::PRODUCT_CARD_PATH, $productId, + $storeId, + $customerGroupId, $cardType ); } diff --git a/ViewModel/ProductListItem.php b/ViewModel/ProductListItem.php index ab2d59c1..0faa6df4 100644 --- a/ViewModel/ProductListItem.php +++ b/ViewModel/ProductListItem.php @@ -5,12 +5,15 @@ namespace Tweakwise\Magento2Tweakwise\ViewModel; use Magento\Catalog\Model\Product; +use Magento\Customer\Model\Session; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\View\Element\AbstractBlock; use Magento\Framework\View\Element\Block\ArgumentInterface; use Magento\Framework\View\LayoutInterface; use Tweakwise\Magento2Tweakwise\Helper\Cache; +use Tweakwise\Magento2Tweakwise\Model\Visual; +use Magento\Store\Model\StoreManagerInterface; class ProductListItem implements ArgumentInterface { @@ -20,12 +23,14 @@ class ProductListItem implements ArgumentInterface */ public function __construct( private readonly LayoutInterface $layout, - private readonly Cache $cacheHelper + private readonly Cache $cacheHelper, + private readonly StoreManagerInterface $storeManager, + private readonly Session $customerSession ) { } /** - * @param Product $product + * @param Product|Visual $item * @param AbstractBlock $parentBlock * @param string $viewMode * @param string $templateType @@ -36,19 +41,24 @@ public function __construct( * @throws NoSuchEntityException */ public function getItemHtml( - Product $product, + Product|Visual $item, AbstractBlock $parentBlock, string $viewMode, string $templateType, string $imageDisplayArea, bool $showDescription ): string { + $isVisual = $item instanceof Visual; if ( !$this->cacheHelper->personalMerchandisingCanBeApplied() || $this->cacheHelper->isTweakwiseAjaxRequest() ) { + if ($isVisual) { + return $this->getVisualHtml($item); + } + return $this->getItemHtmlWithRenderer( - $product, + $item, $parentBlock, $viewMode, $templateType, @@ -57,20 +67,34 @@ public function getItemHtml( ); } - $productId = (int) $product->getId(); - if (!$this->cacheHelper->load($productId)) { - $itemHtml = $this->getItemHtmlWithRenderer( - $product, - $parentBlock, - $viewMode, - $templateType, - $imageDisplayArea, - $showDescription - ); - $this->cacheHelper->save($itemHtml, $productId); + $itemId = (string) $item->getId(); + if (!$this->cacheHelper->load($itemId)) { + if ($isVisual) { + $itemHtml = $this->getVisualHtml($item); + } else { + $itemHtml = $this->getItemHtmlWithRenderer( + $item, + $parentBlock, + $viewMode, + $templateType, + $imageDisplayArea, + $showDescription + ); + } + + $this->cacheHelper->save($itemHtml, $itemId); } - return sprintf('', Cache::PRODUCT_CARD_PATH, $productId); + $storeId = $this->storeManager->getStore()->getId(); + $customerGroupId = $this->customerSession->getCustomerGroupId(); + + return sprintf( + '', + Cache::PRODUCT_CARD_PATH, + $itemId, + $storeId, + $customerGroupId + ); } /** @@ -114,4 +138,22 @@ private function getItemHtmlWithRenderer( return $itemRendererBlock->toHtml(); } + + /** + * @param Visual $visual + * @return string + */ + private function getVisualHtml(Visual $visual): string + { + /** @var AbstractBlock $visualRendererBlock */ + $visualRendererBlock = $this->layout->getBlock('tweakwise.catalog.product.list.visual'); + + if (! $visualRendererBlock) { + return ''; + } + + $visualRendererBlock->setData('visual', $visual); + + return $visualRendererBlock->toHtml(); + } } diff --git a/composer.json b/composer.json index ea2c3102..ffe9d6bc 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "license": "OSL-3.0", "description": "Magento 2 module for Tweakwise integration", "require": { - "php": "^8.0", + "php": "^8.1", "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 263a9b45..61284868 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -12,7 +12,7 @@
- Tweakwise version v8.0.0 + Tweakwise version v8.1.0 Provided by Tweakwise (8 alphanumeric characters) diff --git a/etc/di.xml b/etc/di.xml index 507485c1..0a1374fa 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -12,6 +12,7 @@ + diff --git a/view/frontend/layout/catalog_category_view.xml b/view/frontend/layout/catalog_category_view.xml index ae8a2b45..4b093759 100644 --- a/view/frontend/layout/catalog_category_view.xml +++ b/view/frontend/layout/catalog_category_view.xml @@ -33,6 +33,10 @@ name="tweakwise.catalog.product.list.item" template="Tweakwise_Magento2Tweakwise::product/list/item.phtml" ifconfig="tweakwise/personal_merchandising/enabled"/> + diff --git a/view/frontend/templates/product/list/visual.phtml b/view/frontend/templates/product/list/visual.phtml new file mode 100644 index 00000000..59fc4c6f --- /dev/null +++ b/view/frontend/templates/product/list/visual.phtml @@ -0,0 +1,31 @@ +getData('visual'); +if (!$visual) { + return; +} +$hasUrl = !empty($visual->getUrl()); +?> + +
  • + + + +
    + +
    + +
    + +
  • +