diff --git a/Helper/Config.php b/Helper/Config.php index b0c8826..c3d465c 100644 --- a/Helper/Config.php +++ b/Helper/Config.php @@ -4,6 +4,7 @@ */ declare(strict_types=1); + namespace Aligent\PrerenderIo\Helper; use Magento\Framework\App\Config\ScopeConfigInterface; @@ -13,6 +14,7 @@ class Config { private const XML_PATH_RECACHE_ENABLED = 'system/prerender_io/enabled'; private const XML_PATH_PRERENDER_TOKEN = 'system/prerender_io/token'; + private const XML_PATH_PRERENDER_USE_PRODUCT_CANONICAL_URL = 'system/prerender_io/use_product_canonical_url'; /** @var ScopeConfigInterface */ private ScopeConfigInterface $scopeConfig; @@ -36,7 +38,7 @@ public function isRecacheEnabled(?int $storeId = null): bool { return $this->scopeConfig->isSetFlag( self::XML_PATH_RECACHE_ENABLED, - ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORES, $storeId ); } @@ -51,7 +53,22 @@ public function getToken(?int $storeId = null): ?string { return $this->scopeConfig->getValue( self::XML_PATH_PRERENDER_TOKEN, - ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORES, + $storeId + ); + } + + /** + * Return if product canonical url configuration is enabled or not + * + * @param int|null $storeId + * @return string|null + */ + public function isUseProductCanonicalUrlEnabled(?int $storeId = null): bool + { + return $this->scopeConfig->isSetFlag( + self::XML_PATH_PRERENDER_USE_PRODUCT_CANONICAL_URL, + ScopeInterface::SCOPE_STORES, $storeId ); } diff --git a/Model/Url/GetUrlsForProducts.php b/Model/Url/GetUrlsForProducts.php index bfec571..31a3969 100644 --- a/Model/Url/GetUrlsForProducts.php +++ b/Model/Url/GetUrlsForProducts.php @@ -4,38 +4,32 @@ */ declare(strict_types=1); + namespace Aligent\PrerenderIo\Model\Url; -use Magento\Catalog\Model\Product; -use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Aligent\PrerenderIo\Helper\Config; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Model\App\Emulation; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; +use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite; +use Magento\UrlRewrite\Model\UrlFinderInterface; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; class GetUrlsForProducts { - /** @var CollectionFactory */ - private CollectionFactory $productCollectionFactory; - /** @var StoreManagerInterface */ - private StoreManagerInterface $storeManager; - /** @var Emulation */ - private Emulation $emulation; - /** - * - * @param CollectionFactory $productCollectionFactory * @param StoreManagerInterface $storeManager * @param Emulation $emulation + * @param UrlFinderInterface $urlFinder + * @param Config $prerenderConfigHelper */ public function __construct( - CollectionFactory $productCollectionFactory, - StoreManagerInterface $storeManager, - Emulation $emulation + private readonly StoreManagerInterface $storeManager, + private readonly Emulation $emulation, + private readonly UrlFinderInterface $urlFinder, + private readonly Config $prerenderConfigHelper ) { - $this->productCollectionFactory = $productCollectionFactory; - $this->storeManager = $storeManager; - $this->emulation = $emulation; } /** @@ -47,16 +41,6 @@ public function __construct( */ public function execute(array $productIds, int $storeId): array { - $productCollection = $this->productCollectionFactory->create(); - // do not ignore out of stock products - $productCollection->setFlag('has_stock_status_filter', true); - // if array of product ids is empty, just load all products - if (!empty($productIds)) { - $productCollection->addIdFilter($productIds); - } - $productCollection->setStoreId($storeId); - $productCollection->addUrlRewrite(); - try { /** @var Store $store */ $store = $this->storeManager->getStore($storeId); @@ -64,17 +48,33 @@ public function execute(array $productIds, int $storeId): array return []; } + $useProductCanonical = $this->prerenderConfigHelper->isUseProductCanonicalUrlEnabled($storeId); + + $findByData = [ + UrlRewrite::ENTITY_TYPE => Rewrite::ENTITY_TYPE_PRODUCT, + UrlRewrite::STORE_ID => $storeId, + UrlRewrite::ENTITY_ID => $productIds + ]; + + $urlRewrites = $this->urlFinder->findAllByData($findByData); + $this->emulation->startEnvironmentEmulation($storeId); $urls = []; - /** @var Product $product */ - foreach ($productCollection as $product) { - $urlPath = $product->getData('request_path'); - if (empty($urlPath)) { + + foreach ($urlRewrites as $urlRewrite) { + if (empty($urlRewrite->getRequestPath())) { + continue; + } + + // Ignore the product URL with category path. + if ($useProductCanonical && $urlRewrite->getMetadata()) { continue; } try { - // remove trailing slashes from urls - $urls[] = rtrim($store->getUrl($urlPath), '/'); + // Generate direct URL to avoid Magento stopping at the 4th level onwards + $url = $store->getUrl('', ['_direct' => $urlRewrite->getRequestPath()]); + // Remove trailing slashes from urls + $urls[] = rtrim($url, '/'); } catch (NoSuchEntityException $e) { continue; } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index e787bef..5f3435e 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -20,6 +20,11 @@ 1 + + + Ignore the non-canonical URLs which includes category paths for products. + Magento\Config\Model\Config\Source\Yesno + diff --git a/etc/config.xml b/etc/config.xml new file mode 100644 index 0000000..d346dc2 --- /dev/null +++ b/etc/config.xml @@ -0,0 +1,11 @@ + + + + + + 0 + + + + \ No newline at end of file