Redirect Simple Products to their Configurable Parent with Attributes Pre-selected in Magento 2
About two years ago I wrote a tutorial on how to redirect simple products to their configurable parents with pre-selected attributes in Magento 1.9.x. Shortly after that Magento 2 was released and I’ve received some requests on how to do the same in the new version.
In this post I will explain to you how to build a module that will redirect simple products to their configurable parent product with automatically pre-selected configurable attributes.
[Update June 18th, 2020] Due to many comments that the code in this tutorial doesn’t work anymore, I’ve tested it with Magento 2.3.5-p1 and can verify that it still works.
If it doesn’t work, then another module must be messing with your configuration.
Don’t feel like doing the work? Download the extension from Github. Feel free to fork its repository and add your own features!
Building a Basic Magento 2 Module
First we need to create the basic files and folders necessary for the module to be recognized by Magento 2.
- Create the file
/app/code/DaanvdB/RedirectSimpleProducts/registration.php
and add the following snippet of code to it:This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'DaanvdB_RedirectSimpleProducts', __DIR__ ); - Create the file
/app/code/DaanvdB/RedirectSimpleProducts/etc/module.xml
and add the following code to it:This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <module name="DaanvdB_RedirectSimpleProducts" setup_version="1.0.0" /> </config>
Run php bin/magento setup:upgrade
from your terminal so Magento 2 will update and add your new module to its configuration.
Redirecting Simple Products to their Configurable Parent using an Observer
In order to redirect simple products to their configurable parent, we need to create an observer that hooks into an event which is triggered before the catalog_product_view
is requested. The best event for this observer is controller_action_predispatch_catalog_product_view
.
First we create our custom Observer-class in /app/code/DaanvdB/RedirectSimpleProducts/Observer/Predispatch.php
and add the following code (inspired by StackOverflow):
<?php | |
namespace DaanvdB\RedirectSimpleProducts\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) | |
{ | |
$pathInfo = $observer->getEvent()->getRequest()->getPathInfo(); | |
/** If it's not a product view we don't need to do anything. */ | |
if (strpos($pathInfo, 'product') === false) { | |
return; | |
} | |
$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); | |
} | |
} | |
} |
The Observer we just created takes care of the entire process:
- At first it checks if we’re on a catalog_product_view-page,
- Then it checks if the current requests is a simple product,
- If so, it finds it’s corresponding configurable parent and loads all available configurable attributes,
- Then it takes the values for each configurable attribute from the simple product’s properties and builds an
options
array with them, - With this array it builds a query using Magento 2’s integrated URL parsing functionality.
- The created query is appended to the configurable products’ URL-key and a Redirect is set.
Adding the Observer-class to an event
To trigger our custom Observer when the earlier mentioned event is triggered, we need to create a file called events.xml
.
Create the file /app/code/DaanvdB/RedirectSimpleProducts/etc/events.xml
:
<?xml version="1.0"?> | |
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> | |
<event name="controller_action_predispatch_catalog_product_view"> | |
<observer name="daanvdb_redirectsimple_products_observer_predispatch" instance="DaanvdB\RedirectSimpleProducts\Observer\Predispatch"/> | |
</event> | |
</config> |
The events.xml
takes care of triggering our custom observer whenever the controller_action_predispatch_catalog_product_view
is called.
That’s it! It is this simple to create a module that redirects simple products to their configurable parent product with pre-selected configurable attributes. Make sure you empty your cache (php bin/magento cache:flush
) after you’ve copied the files to your site. Enjoy!
Hello,
Does this work for Magento 2.3.4 ? I have tried it over and over again, nothing changed !
Hi Mohammed,
I’m not sure. I haven’t tested or used it in a while. I should put the code on Github and allow people to make forks. To stay up-to-date.It works on M2.3.5-p1. You can find the Github Repository here.
Hi Mohammed,
Wanted to let you know that I just tested it with M2.3.5-p1 and it still works.
Hey Daan,
I just wanted to start off by thanking you for this tutorial, its definitely a lifesaver.
However, I am getting a similar issue as some of the other folks. Clicking on a child listing is linking correctly to the parent listing but it is not selecting the variation on load.
What I can do to get it to also select the variation that the customer clicks on.
I am running on CentOS 8 + Magento 2.3.5-P1
I am not receiving the error in my console: “Uncaught TypeError: Cannot read property ‘updateData’ of undefined”
The error that I am getting is: “JQMIGRATE: jQuery.attrFn is deprecated”
Thanks so much!
Jay
Hi Daan,
Nice tutorial!!, is the same method possible for configurable product listing to configurable product details page?
I don’t think so. From the logic in this article, there is a certain selection made. We can detect, from the simple product clicked in the product listing, which attributes to select. How would we do that if the configurable product is clicked?
if we add one of the attribute in the product url, when you click the url you can pass that attribute.
Hey Daan, I did some research and I think I may have found the issue causing the variations to not be selected when redirected on 2.3.5p. I think its the new CSP introduced to protect users from cross-site scripting. Here is the docs for it: https://devdocs.magento.com/guides/v2.3/extension-dev-guide/security/content-security-policies.html
Would you please kindly take a quick look for me? I would really appreciate it.
Best Regards,
Jay
Hi Jay,
I’ve tested it with M2.3.5-1 and with Magento_Csp disabled. It works fine. I don’t see why a Content Security Policy would interfere with its functioning, though.
Hi Daan
Trying your script as you advised, however i get an error: (running magento 2.3.5-p1)
ReflectionException: Class Magento\Framework\App\Http\Interceptor does not exist in /home/path/public_html/path/magento2/vendor/magento/framework/Code/Reader/ClassReader.php:26 Stack trace: #0 /home/path/public_html/path/magento2/vendor/magento/framework/Code/Reader/ClassReader.php(26): ReflectionClass->__construct(‘Magento\\Framewo…’) #1 /home/path/public_html/path/magento2/vendor/magento/framework/ObjectManager/Definition/Runtime.php(54): Magento\Framework\Code\Reader\ClassReader->getConstructor(‘Magento\\Framewo…’) #2 /home/path/public_html/path/magento2/vendor/magento/framework/ObjectManager/Factory/Dynamic/Developer.php(48): Magento\Framework\ObjectManager\Definition\Runtime->getParameters(‘Magento\\Framewo…’) #3 /home/path/public_html/path/magento2/vendor/magento/framework/ObjectManager/ObjectManager.php(56): Magento\Framework\ObjectManager\Factory\Dynamic\Developer->create(‘Magento\\Framewo…’, Array) #4 /home/path/public_html/path/magento2/vendor/magento/framework/App/Bootstrap.php(235): Magento\Framework\ObjectManager\ObjectManager->create(‘Magento\\Framewo…’, Array) #5 /home/path/public_html/path/magento2/index.php(38): Magento\Framework\App\Bootstrap->createApplication(‘Magento\\Framewo…’) #6 {main}
Thanks in advance for any help.
I’ve also tried all the steps above in developer mode and production, i get error “This page isn’t working”
You did run setup:upgrade, etc. after creating the module? Because the class does exist in 2.3.5-p1. I just checked.
Did you run
bin/magento setup:upgrade
?I tried this tutorial but how it works?