Magento – Magento2 Event Observer Redirect Simple Product to Configurable Product

event-observermagento2redirect

I'm trying to write a module to redirect simple products to their configurable products once each simple product is clicked on. I've done a bit research and wrote an Observer to catch event: controller_action_predispatch_catalog_product_view
Now I'm stuck in getting the clicked product (such as ID), from which I want to get its configurable product URL, then execute the redirect. Here is my Observer/redirect.php:
`

namespace Vendor_name\Module_name\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Event\Observer;

class redirect implements ObserverInterface {

    protected $_catalogProductTypeConfigurable;
    protected $_productloader;

    public function __construct(
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $_productloader,
        \Magento\Catalog\Block\Product\Context $context,
        \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable,
        \Magento\Catalog\Model\Session $catalogSession,
        \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\UrlInterface $url
    ){
        $this->_productloader = $_productloader;
        $this->_catalogProductTypeConfigurable = $catalogProductTypeConfigurable;
        $this->_catalogSession = $catalogSession;
        $this->_responseFactory = $responseFactory;
        $this->_url = $url;
    }
    public function execute(\Magento\Framework\Event\Observer $observer ) {
        $_product = $observer->getEvent()->getProduct();//this dosen't seem to return anything at all
        $product_id = $_product->getProductId();
        $parentByChild = $this->_catalogProductTypeConfigurable->getParentIdsByChild($product_id);
        //preset product options
        if(isset($parentByChild[0])){
            $id = $parentByChild[0];
            $productCollection = $this->_productloader->create()->load($id);
            $productAttributeOptions = $productCollection->getTypeInstance(true)->getConfigurableAttributesAsArray($productCollection);
            $attributeOptions = array();
            foreach ($productAttributeOptions as $productAttribute) {
                $attributeOptions[$productAttribute['attribute_id']] = $_product->getData($productAttribute['attribute_code']);
            }
        }
        $this->catalogSession->setSuperAttributes($attributeOptions);
        //redirect to configurable product
        $configProductUrl = $parentByChild->getProductUrl();
        $this->_responseFactory->create()->setRedirect($configProductUrl)->sendResponse();
        exit();
    }
}

`

Best Answer

Here is my solution. It will redirect to the simple product's first parent. It will also select the configuration options for the simple product on the configuration page.

<?php
namespace {DEVELOPER}\{MODULENAME}\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class Predispatch implements ObserverInterface
{

    protected $_redirect;
    protected $_productTypeConfigurable;
    protected $_productRepository;
    protected $_storeManager;

    public function __construct(
        \Magento\Framework\App\Response\Http $redirect,
        \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $productTypeConfigurable,
        \Magento\Catalog\Model\ProductRepository $productRepository,
        \Magento\Store\Model\StoreManagerInterface $storeManager
    )
    {
        $this->_redirect = $redirect;
        $this->_productTypeConfigurable = $productTypeConfigurable;
        $this->_productRepository = $productRepository;
        $this->_storeManager = $storeManager;
    }

    public function execute(Observer $observer)
    {
        /** @var \Magento\Framework\App\RequestInterface $request */
        $request = $observer->getEvent()
            ->getRequest();
        $simpleProductId = $request->getParam('id');
        if (!$simpleProductId) {
            return;
        }
        $simpleProduct = $this->_productRepository->getById($simpleProductId, false, $this->_storeManager->getStore()->getId());
        if (!$simpleProduct || $simpleProduct->getTypeId() != \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) {
            return;
        }

        $configProductId = $this->_productTypeConfigurable->getParentIdsByChild($simpleProductId);
        if (isset($configProductId[0])) {
            $configProduct = $this->_productRepository->getById($configProductId[0], false, $this->_storeManager->getStore()->getId());
            $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;
            }
            $options = http_build_query($options);
            $hash = $options ? '#' . $options : '';
            $configProductUrl = $configProduct->getUrlModel()
                ->getUrl($configProduct) . $hash;
            $this->_redirect->setRedirect($configProductUrl, 301);
        }
    }
}

Things I am still going to add:

  • system setting to enable or disable the redirect
  • Logic to detect simple product's visibility setting. Only redirect if the simple product is set up not to be visible.
Related Topic