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!
Hi, this is now working great on our Magento 2.3.3 site. However it gives new problem in tracking of google merchant. We provide utm for url of simple products to merchant by adding to url “utm_source=google&utm_medium=cpc&utm_campaign=example’
So example:
Normal url: https://oursite.com/tacx-shiva-bidon-wit-500-ml.html
To google: https://oursite.com/tacx-shiva-bidon-wit-500-ml.html?utm_source=google&utm_medium=cpc&utm_campaign=feedsimple
But with the extension it will create url: https://oursite.com/tacx-shiva-bidon.html#93=397&293=4099
So now problem with tracking of campaigns.
So we would like to keep the ‘utm’ extension we give. Would this be possible in any way?
Definitely. But it’ll need some adjustments in the code. Just keep in mind that you’ll need to modify the output url as follows: https://yoursite.com/product-url.html?utm_source=google&other_utm_params=something_else#93=397&293=4099.
I.e. the parameters after the hashtag (#) need to be added to the URL last, since everything after the # is client side, i.e. not accessible by the server.
Hi, works great. Thanks. However, it gives us an issue with adwords tracking. We add to the url utm_source=google&utm_medium=cpc&utm_campaign=aa
Now when redirect simple product it will redirect to something like #93=403&156=1604
and the utm code will be lost.
Is there any way to make sure we keep the utm code when redirecting with the extension?
Hi Emile,
You already left the same comment earlier. And I replied. 🙂
Ah, my bad. Sorry. Got a reminder from my adwords agency and kind of forgot
Hello Daan,
How same thing can be do in the search result page ?
We need to redirect same simple product to configurable product with pre selected option from search result page.
Let us know how can do it.
Thanks.
This extension has been a life saver and I can’t thank you enough for sharing it!
Unfortunately, I’m updating to M2.4.1 and the redirects are not triggered anymore.
Tested on a fresh install with Luma theme, the old link pattern is still working, it means the pre-selected options are being automatically selected when you add the options at the end of the urls, like those ones (#157=272&93=52)
But the only issue is the reductions are not working from simple products urls to their parent product.
Are you planning to update your code for Magento 2.4.1?
Thank you
Hi Dan,
Thanks for notifying me. I’ll put it on my todo list.
It’s working again but I cannot really explain how. I changed most of Magento default settings to make the new store ready to be used (canonical, flat catalog, .html etc…). Now it is working without any issue. It looks fully compatible with Magento 2.4.1.
Thanks again
Hello, very nice extension! I install it magento 2.4.1. the only thing is not working right is that open the configurable product page with preselected options but with Review tab open and not Description as it is default.
Hi guys,
For anyone still got the issue image not changed and no errors in console. Here is the fix I figured out:
Add these files to your module:
app/code/Vendor/Module/view/frontend/requirejs-config.js
********************************************************
var config = {
config: {
mixins: {
‘Magento_ConfigurableProduct/js/configurable’: {
‘Fgc_Simple2Configurable/js/configurable-mixin’: true
},
},
},
};
********************************************************
app/code/Vendor/Module/view/frontend/web/js/configurable-mixin.js
********************************************************
define([‘jquery’], function ($) {
‘use strict’;
return function (targetWidget) {
$.widget(‘mage.configurable’, targetWidget, {
_onGalleryLoaded: function (element) {
this._super(element);
this._changeProductImage();
},
_changeProductImage: function () {
this._super();
}
});
return $.mage.configurable;
};
});
********************************************************
Clear the cache, redeploy static files and check it out!
Thnx Hieu!
I’ll add this solution to the post! 🙂