1

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();
    }
}

`

1
  • This may not be any help, but why do you need to show the simple products in the first place? There may be an easier solution if you could just only show the Configurables instead of showing the Simples. Then you wouldn't need to worry about any redirect.
    – user50408
    Mar 2, 2017 at 21:12

3 Answers 3

3

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.
4
  • Nice work there, it indeed worked for me however the product image didn't load properly, in my case it still uses configurable product's images.
    – Ethan Wan
    Jul 9, 2018 at 3:53
  • The reason why the images are not updating is because a known bug here: github.com/magento/magento2/pull/14873/commits/…
    – Ethan Wan
    Jul 16, 2018 at 4:49
  • For multiple attribute option, it will not work. It will redirect the URL but attribute options not selected as pre-selected for multiple.
    – Indian
    May 7, 2019 at 7:07
  • It's working but impacted the performance as it's taking some time to redirect from listing to PDP page, any solution on this?
    – Jack
    Feb 4, 2020 at 11:43
1

Looks like no one has interests in this yet, it is actually a very common request from clients especially in the fashion sector - shop owners often want to display simple products in category, then once clicked on goes to configurable product. In this way you get to see the exact product you interest the most yet still have the option to browse the variations (The Iconic being a good example). I haven't worked out how to pre-populate product options but the redirect part is now working for me, so here I'm answering my own Q:

First of all you need to know basics about creating custom module, Event, Observer and URL redirect. My Observer/ScRdirect.php file:

<?php

    namespace Eharvest\ScRedirect\Observer;
    use Magento\Framework\Event\ObserverInterface;
    use Magento\Framework\Event\Observer;

    class ScRedirect 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,
            \Magento\Catalog\Model\ProductRepository $productRepository
        ){
            $this->_request = $context->getRequest();
            $this->_productloader = $_productloader;
            $this->_catalogProductTypeConfigurable = $catalogProductTypeConfigurable;
            $this->_catalogSession = $catalogSession;
            $this->_responseFactory = $responseFactory;
            $this->_url = $url;
            $this->_productRepository = $productRepository;
        }

        public function execute(\Magento\Framework\Event\Observer $observer ) {
            $simpleProductId = $this->_request->getParam('id');
            $simpleProduct = $this->_productRepository->getById($simpleProductId);
            $configProductId = $this->_catalogProductTypeConfigurable->getParentIdsByChild($simpleProductId);
            if(isset($configProductId [0])){
                $parentId = $configProductId[0];
                $configProduct = $this->_productRepository->getById($parentId);
                $configProductUrl = $configProduct->getUrlModel()->getUrl($configProduct);
$this->_responseFactory->create()->setRedirect($configProductUrl)->sendResponse();
                die();
            }
        }
    }

My Model/Observer.php file:

<?php
namespace Eharvest\Module\Model;
class Observer
{
    protected $_scredirectData;
    protected $_registry = null;

    public function __construct (
        \Eharvest\ScRedirect\Helper\Data $scredirectData,
        \Magento\Framework\Registry $registry
    ) {
        $this->_scredirectData = $scredirectData;
        $this->_registry = $registry;
    }

}

Hope this would help anyone with similar request:)

2
  • After posting this thread, I've had quite a few fellow developers asked me about taking this simple module a step further - such as unique URLs, auto populate options, titles and ect. I also realised above solution will result simple product not getting indexed which is really bad for SEO. Any ideas, recommendations of getting this module properly done would be greatly appreciated.
    – Ethan Wan
    Oct 5, 2017 at 23:35
  • Could you provide the file paths of the files you modified or added for this solution? Thanks. Aug 11, 2018 at 16:13
0

In order to redirect simple products to configurable parent product, you can create a Plugin (Interceptor) for Magento\Catalog\Model\Product::getProductUrl(), where to change URL for simple products:

if ($product->getTypeId() === 'simple') {
    /*Get the configurable parent product URL and assign it to a simple product.*/
}

To preselect a simple product in a configurable product, the address of a simple product should look like this for example:

/mona-pullover-hoodlie.html#143=167&93=53

where

/mona-pullover-hoodlie.html - configurable product URL,

143, 93 - attributes IDs,

167, 53 - option IDs.


I made a VCT Simple Product URL module on Magento Marketplace that solves this problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.