Skip to content

Select configurable product option, Magento 2

I have a module that redirects the url of a simple product to the configurable product. For this I have this:
events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <event name="controller_action_predispatch_catalog_product_view">
            <observer name="vendor_redirectsimpletoconfigurable_products_observer_predispatch"
                      instance="VendorRedirectSimpleToConfigurableObserverPredispatch"/>
    </event>
</config>

Predispatch.php

<?php

declare(strict_types=1);

namespace VendorRedirectSimpleToConfigurableObserver;

use VendorRedirectSimpleToConfigurableHelperConfig;
use MagentoCatalogApiDataProductInterface;
use MagentoCatalogModelProductRepository;
use MagentoConfigurableProductModelProductTypeConfigurable;
use MagentoFrameworkAppConfigScopeConfigInterface;
use MagentoFrameworkAppRequestInterface;
use MagentoFrameworkAppResponseHttp;
use MagentoFrameworkEventObserver;
use MagentoFrameworkEventObserverInterface;
use MagentoFrameworkExceptionNoSuchEntityException;
use MagentoStoreModelStoreManagerInterface;
use MagentoCatalogModelProductType;
use MagentoFrameworkAppRequestHttp as HttpRequest;


class Predispatch implements ObserverInterface {

    /**
     * Predispatch constructor
     *
     * @param Http $redirect
     * @param Configurable $productTypeConfigurable
     * @param ProductRepository $productRepository
     * @param StoreManagerInterface $storeManager
     * @param ScopeConfigInterface $scopeConfig
     * @param Config $config
     */
    public function __construct (
        protected readonly Http                  $redirect,
        protected readonly Configurable          $productTypeConfigurable,
        protected readonly ProductRepository     $productRepository,
        protected readonly StoreManagerInterface $storeManager,
        protected readonly ScopeConfigInterface  $scopeConfig,
        protected readonly Config                $config
    ) {}

    /**
     * @param Observer $observer
     * @return void
     * @throws NoSuchEntityException
     */
    public function execute(Observer $observer): void
    {
        if (!$this->config->isModuleEnabled()) {
            return;
        }

        $request = $observer->getEvent()->getRequest();
        if (!str_contains($request->getPathInfo(), 'product')) {
            return;
        }

        $simpleProductId = $request->getParam('id');
        if (!$simpleProductId) {
            return;
        }

        try {
            $simpleProduct = $this->productRepository->getById($simpleProductId, false, $this->storeManager->getStore()->getId());
            if ($simpleProduct->getTypeId() !== Type::TYPE_SIMPLE) {
                return;
            }

            $parentId = $this->getParentId($simpleProductId);
            if ($simpleProductId !== $parentId) {
                $this->redirectToConfigurableProduct($request, $simpleProduct, $parentId);
            }
        } catch (NoSuchEntityException $noSuchEntityException) {
            return;
        }
    }

    /**
     * @param int $childId
     * @return int
     * @throws NoSuchEntityException
     */
    private function getParentId(int $childId): int
    {
        $parentProductIds = $this->productTypeConfigurable->getParentIdsByChild($childId);
        foreach ($parentProductIds as $parentId) {
            $parentProduct = $this->productRepository->getById($parentId);
            if (in_array($this->storeManager->getStore()->getWebsiteId(), $parentProduct->getWebsiteIds())) {
                return $parentId;
            }
        }
        return $childId;
    }

    private function redirectToConfigurableProduct(HttpRequest $request, ProductInterface $simpleProduct, int $parentId): void
    {
        $configProduct = $this->productRepository->getById($parentId);
        $configType = $configProduct->getTypeInstance();
        $attributes = $configType->getConfigurableAttributesAsArray($configProduct);

        $options = [];
        foreach ($attributes as $attribute) {
            $id = $attribute['attribute_id'];
            $value = $simpleProduct->getData($attribute['attribute_code']);
            $options[$id] = $value;
        }

        $request->setParam('super_attribute', $options);

        $request->setModuleName('catalog')
            ->setControllerName('product')
            ->setActionName('view')
            ->setPathInfo('/catalog/product/view/id/' . $parentId)
            ->setParam('id', $parentId);
    }
}

I have based myself on this module https://github.com/techyouknow/magento2-redirect-simple-products

But I need it not to do redirection. For SEO reasons, the url that should be seen is the simple url, but the configurable product must be shown with the options that the simple url has marked.

The only thing I can’t get to work is to check the options, any suggestions?

I know that with #137=88&145=13 you can pass the attributes to be selected, but this way

$request->setModuleName('catalog')
            ->setControllerName('product')
            ->setActionName('view')
            ->setPathInfo('/catalog/product/view/id/' . $parentId)
            ->setParam('id', $parentId);

does not accept parameters