0

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

`

  • 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. – dmatthew Mar 2 '17 at 21:12
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.
  • 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 '18 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 '18 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 at 7:07
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:)

  • 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 '17 at 23:35
  • Could you provide the file paths of the files you modified or added for this solution? Thanks. – Will Cousin Aug 11 '18 at 16:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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