How to Change the Configurable products name dynamically when i click configurable swatches, currently price change when click swatches .I need to change name too. please suggest better way! Thank You,
3 Answers
You must create a module that will override the "ConfigurableProduct" and "Swatches" modules of Magento.
I made you something based based on a solution from an author of this forum (As soon as I find his name, I will tag him) that will dynamically change the product name, Sku and description. You can make anything you want dynamic with this module. :
First, create your base file in : /app/code/VendorName/ModuleName
In each of the indications below, VendorName and Module/name are to be modified by what you want.
registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'VendorName_ModuleName',
__DIR__
);
Create directory /app/code/VendorName/ModuleName/etc
Put this file in it : module.xml
<?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="VendorName_ModuleName" setup_version="1.0.0">
<sequence>
<module name="Magento_ConfigurableProduct"/>
<module name="Magento_Swatches"/>
</sequence>
</module>
</config>
Now create directory /app/code/VendorName/ModuleName/etc/frontend/
Put this file in it : di.xml
<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\ConfigurableProduct\Block\Product\View\Type\Configurable">
<plugin disabled="false" name="VendorName_ModuleName_Plugin_Magento_ConfigurableProduct_Block_Product_View_Type_Configurable" sortOrder="10" type="VendorName\ModuleName\Plugin\Magento\ConfigurableProduct\Block\Product\View\Type\Configurable"/>
</type>
<type name="Magento\Swatches\Block\Product\Renderer\Configurable">
<plugin disabled="false" name="VendorName_ModuleName_Plugin_Magento_Swatches_Block_Product_Renderer_Configurable" sortOrder="10" type="VendorName\ModuleName\Plugin\Magento\Swatches\Block\Product\Renderer\Configurable"/>
</type>
</config>
Create directories /app/code/VendorName/ModuleName/Plugin/Magento/ConfigurableProduct/Block/Product/View/Type/ /app/code/VendorName/ModuleName/Plugin/Magento/Swatches/Block/Product/Renderer/
In /app/code/VendorName/ModuleName/Plugin/Magento/ConfigurableProduct/Block/Product/View/Type/
Put this file : Configurable.php
<?php
namespace VendorName\ModuleName\Plugin\Magento\ConfigurableProduct\Block\Product\View\Type;
class Configurable
{
public function afterGetJsonConfig(\Magento\ConfigurableProduct\Block\Product\View\Type\Configurable $subject, $result) {
$jsonResult = json_decode($result, true);
foreach ($subject->getAllowProducts() as $simpleProduct) {
$id = $simpleProduct->getId();
foreach($simpleProduct->getAttributes() as $attribute) {
if(($attribute->getIsVisible() && $attribute->getIsVisibleOnFront()) || in_array($attribute->getAttributeCode(), ['sku','description','name']) ) { // <= Here you can put any attribute you want to see dynamic
$code = $attribute->getAttributeCode();
$value = (string)$attribute->getFrontend()->getValue($simpleProduct);
$jsonResult['dynamic'][$code][$id] = [
'value' => $value
];
}
}
}
$result = json_encode($jsonResult);
return $result;
}
}
In /app/code/VendorName/ModuleName/Plugin/Magento/Swatches/Block/Product/Renderer/
<?php
namespace VendorName\ModuleName\Plugin\Magento\Swatches\Block\Product\Renderer;
class Configurable
{
public function afterGetJsonConfig(\Magento\Swatches\Block\Product\Renderer\Configurable $subject, $result) {
$jsonResult = json_decode($result, true);
foreach ($subject->getAllowProducts() as $simpleProduct) {
$id = $simpleProduct->getId();
foreach($simpleProduct->getAttributes() as $attribute) {
if(($attribute->getIsVisible() && $attribute->getIsVisibleOnFront()) || in_array($attribute->getAttributeCode(), ['sku','description','name']) ) { // <= Here you can put any attribute you want to see dynamic
$code = $attribute->getAttributeCode();
$value = (string)$attribute->getFrontend()->getValue($simpleProduct);
$jsonResult['dynamic'][$code][$id] = [
'value' => $value
];
}
}
}
$result = json_encode($jsonResult);
return $result;
}
}
Now, we enter in the LAST STEP :
Create Directories : /app/code/VendorName/ModuleName/view/frontend/web/js/model/
In this folder "model", add these files:
attswitch.js
define([
'jquery',
'mage/utils/wrapper'
], function ($, wrapper) {
'use strict';
return function(targetModule){
$('h1 span').attr("data-dynamic", "name");
var reloadPrice = targetModule.prototype._reloadPrice;
targetModule.prototype.dynamic = {};
$('[data-dynamic]').each(function(){
var code = $(this).data('dynamic');
var value = $(this).html();
targetModule.prototype.dynamic[code] = value;
});
var reloadPriceWrapper = wrapper.wrap(reloadPrice, function(original){
var dynamic = this.options.spConfig.dynamic;
console.log(dynamic);
for (var code in dynamic){
if (dynamic.hasOwnProperty(code)) {
var value = "";
var $placeholder = $('[data-dynamic='+code+']');
if(!$placeholder.length) {
continue;
}
if(this.simpleProduct){
value = this.options.spConfig.dynamic[code][this.simpleProduct].value;
} else {
value = this.dynamic[code];
}
$placeholder.html(value);
}
}
return original();
});
targetModule.prototype._reloadPrice = reloadPriceWrapper;
return targetModule;
};
});
swatch-attswitch.js
/*jshint browser:true jquery:true*/
/*global alert*/
define([
'jquery',
'mage/utils/wrapper'
], function ($, wrapper) {
'use strict';
return function(targetModule){
$('h1 span').attr("data-dynamic", "name");
var updatePrice = targetModule.prototype._UpdatePrice;
targetModule.prototype.dynamic = {};
$('[data-dynamic]').each(function(){
var code = $(this).data('dynamic');
var value = $(this).html();
targetModule.prototype.dynamic[code] = value;
});
var updatePriceWrapper = wrapper.wrap(updatePrice, function(original){
var dynamic = this.options.jsonConfig.dynamic;
console.log(dynamic);
for (var code in dynamic){
if (dynamic.hasOwnProperty(code)) {
var value = "";
var $placeholder = $('[data-dynamic='+code+']');
var allSelected = true;
if(!$placeholder.length) {
continue;
}
for(var i = 0; i<this.options.jsonConfig.attributes.length;i++){
if (!$('div.product-info-main .product-options-wrapper .swatch-attribute.' + this.options.jsonConfig.attributes[i].code).attr('option-selected')){
allSelected = false;
}
}
if(allSelected){
var products = this._CalcProducts();
value = this.options.jsonConfig.dynamic[code][products.slice().shift()].value;
} else {
value = this.dynamic[code];
}
$placeholder.html(value);
}
}
return original();
});
targetModule.prototype._UpdatePrice = updatePriceWrapper;
return targetModule;
};
});
And finally in /app/code/VendorName/ModuleName/view/frontend/
Add this file : requirejs-config.js
var config = {
config: {
mixins: {
'Magento_ConfigurableProduct/js/configurable': {
'VendorName_ModuleName/js/model/attswitch': true
},
'Magento_Swatches/js/swatch-renderer': {
'VendorName_ModuleName/js/model/swatch-attswitch': true
}
}
}
};
You have now a fully functionnal module that will change dynamically all information you want on product page.
Just pass habitual CLI commands and well done, it work.
Regards,
-
-
With pleasure! ! Feel free to pass your subject to solved if it is :) Jul 6, 2019 at 10:52
-
But an issue in related product case, if any products have related product at that case last related product name comes in the actual product name section ! first load. when swatches click its clear, but initial loading show wrong name .how to solve this Bug? Jul 6, 2019 at 11:08
-
I checked, I cannot reproduce your problem. Can you tell me more about it ? Have you a link ? Jul 6, 2019 at 11:13
-
Module Method Working For me in Magento 2.1 / 2.2 /2.3 :: The below Code is to change Name & Description both. For Magento 2.4 add mixin
1. app/code/[VendorName]/[ModuleName]/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'[VendorName_ModuleName]',
__DIR__
);
2. app/code/[VendorName]/[ModuleName]/etc/module.xml
<?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="[VendorName_ModuleName]" setup_version="1.0.0" />
</config>
3. app/code/[VendorName]/[ModuleName]/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\ConfigurableProduct\Block\Product\View\Type\Configurable">
<plugin name="[VendorName_ModuleName]-product-block" type="[VendorName]\[ModuleName]\Plugin\Product\View\Type\ConfigurablePlugin" sortOrder="1" />
</type>
<type name="Magento\ConfigurableProduct\Model\Product\Type\Configurable">
<plugin name="[VendorName_ModuleName]-product-model" type="[VendorName]\[ModuleName]\Plugin\Product\Type\ConfigurablePlugin" sortOrder="1" />
</type>
</config>
4. app/code/[VendorName]/[ModuleName]/Plugin/Product/Type/ConfigurablePlugin.php
<?php
namespace [VendorName]\[ModuleName]\Plugin\Product\Type;
class ConfigurablePlugin
{
public function afterGetUsedProductCollection(\Magento\ConfigurableProduct\Model\Product\Type\Configurable $subject, $result)
{
$result->addAttributeToSelect('name');
$result->addAttributeToSelect('description');
return $result;
}
}
5. app/code/[VendorName]/[ModuleName]/Plugin/Product/View/Type/ConfigurablePlugin.php
<?php
namespace [VendorName]\[ModuleName]\Plugin\Product\View\Type;
class ConfigurablePlugin
{
protected $jsonEncoder;
protected $jsonDecoder;
public function __construct(
\Magento\Framework\Json\DecoderInterface $jsonDecoder,
\Magento\Framework\Json\EncoderInterface $jsonEncoder
){
$this->jsonEncoder = $jsonEncoder;
$this->jsonDecoder = $jsonDecoder;
}
public function afterGetJsonConfig(\Magento\ConfigurableProduct\Block\Product\View\Type\Configurable $subject, $result)
{
$result = $this->jsonDecoder->decode($result);
$currentProduct = $subject->getProduct();
if ($currentProduct->getName()) {
$result['productName'] = $currentProduct->getName();
}
if ($currentProduct->getDescription()) {
$result['productDescription'] = $currentProduct->getDescription();
}
foreach ($subject->getAllowProducts() as $product) {
$result['names'][$product->getId()][] =
[
'name' => $product->getData('name'),
];
$result['descriptions'][$product->getId()][] =
[
'description' => $product->getData('description'),
];
}
return $this->jsonEncoder->encode($result);
}
}
6. app/code/[VendorName]/[ModuleName]/view/frontend/requirejs-config.js
var config = {
map: {
'*': {
'Magento_Swatches/js/swatch-renderer':'[VendorName]_[ModuleName]/js/swatch-renderer'
}
}
};
7. app/code/[VendorName]/[ModuleName]/view/frontend/web/js/swatch-renderer.js
Copy original JS file(vendor/magento/module-swatches/view/frontend/web/js/swatch-renderer.js & Replace _OnClick function with below code (Line No Approx: 712)
_OnClick: function ($this, $widget, eventName) {
var $parent = $this.parents('.' + $widget.options.classes.attributeClass),
$wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper),
$label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass),
attributeId = $parent.attr('attribute-id'),
$input = $parent.find('.' + $widget.options.classes.attributeInput);
if ($widget.inProductList) {
$input = $widget.productForm.find(
'.' + $widget.options.classes.attributeInput + '[name="super_attribute[' + attributeId + ']"]'
);
}
if ($this.hasClass('disabled')) {
return;
}
if ($this.hasClass('selected')) {
$parent.removeAttr('option-selected').find('.selected').removeClass('selected');
$input.val('');
$label.text('');
$this.attr('aria-checked', false);
} else {
$parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected');
$label.text($this.attr('option-label'));
$input.val($this.attr('option-id'));
$input.attr('data-attr-name', this._getAttributeCodeById(attributeId));
$this.addClass('selected');
$widget._toggleCheckedAttributes($this, $wrapper);
/* CUSTOM CODE START */
if (jQuery('[data-ui-id="page-title-wrapper"]').length && this.options.jsonConfig.names) {
if (this.getProduct()) {
var iname = this.options.jsonConfig.names[this.getProduct()][0].name
if (iname != '') {
jQuery('[data-ui-id="page-title-wrapper"]').html(iname);
}
}
else {
var productName = this.options.jsonConfig.productName
if (productName) {
jQuery('[data-ui-id="page-title-wrapper"]').html(productName);
}
}
}
if (jQuery('.description > div.value').length && this.options.jsonConfig.descriptions) {
if (this.getProduct()) {
var description = this.options.jsonConfig.descriptions[this.getProduct()][0].description
if (description) {
jQuery('.description > div.value').html(description);
}
} else {
var productDescription = this.options.jsonConfig.productDescription
if (productDescription) {
jQuery('.description > div.value').html(productDescription);
}
}
}
/* CUSTOM CODE END */
$widget._Rebuild();
if ($widget.element.parents($widget.options.selectorProduct)
.find(this.options.selectorProductPrice).is(':data(mage-priceBox)')
) {
$widget._UpdatePrice();
}
$widget._loadMedia(eventName);
$input.trigger('change');
}
},
For Magento 2.4
For mixins you have to Add or Update app/code/[VendorName]/[ModuleName]/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
"Magento_Swatches/js/swatch-renderer" : {
"[VendorName]_[ModuleName]/js/swatch-renderer": true
}
}
}
};
For mixins you have to Add or Update app/code/[VendorName]/[ModuleName]/view/frontend/web/js/swatch-renderer.js
define([
'jquery',
'underscore',
'jquery/ui',
'jquery/jquery.parsequery'
], function ($, _) {
'use strict';
return function (widget) {
$.widget('mage.SwatchRenderer', widget, {
/**
* Event for swatch options
*
* @param {Object} $this
* @param {Object} $widget
* @private
*/
_OnClick: function ($this, $widget) {
$widget._super($this, $widget);
$widget._UpdateDetailProduct();
},
/**
* Event for select
*
* @param {Object} $this
* @param {Object} $widget
* @private
*/
_OnChange: function ($this, $widget) {
$widget._super($this, $widget);
$widget._UpdateDetailProduct();
},
_UpdateDetailProduct: function () {
var $widget = this,
index = '',
options = _.object(_.keys($widget.optionsMap), {}),
childProductName = this.options.jsonConfig.names,
childProductDescription = this.options.jsonConfig.descriptions;
$widget.element.find('.' + $widget.options.classes.attributeClass + '[data-option-selected]').each(function () {
var attributeId = $(this).attr('data-attribute-id');
options[attributeId] = $(this).attr('data-option-selected');
});
/* CUSTOM CODE START */
if (jQuery('[data-ui-id="page-title-wrapper"]').length && this.options.jsonConfig.names) {
//console.log("In "names);
console.log(this.getProduct());
if (this.getProduct()) {
var iname = this.options.jsonConfig.names[this.getProduct()][0].name
if (iname != '') {
jQuery('[data-ui-id="page-title-wrapper"]').html(iname);
}
}
else {
var productName = this.options.jsonConfig.productName
if (productName) {
jQuery('[data-ui-id="page-title-wrapper"]').html(productName);
}
}
}
if (jQuery('.description > div.value').length && this.options.jsonConfig.descriptions) {
if (this.getProduct()) {
var description = this.options.jsonConfig.descriptions[this.getProduct()][0].description
if (description) {
jQuery('.description > div.value').html(description);
}
} else {
var productDescription = this.options.jsonConfig.productDescription
if (productDescription) {
jQuery('.description > div.value').html(productDescription);
}
}
}
/* CUSTOM CODE END */
},
});
return $.mage.SwatchRenderer;
}
});
-
-
@paj Yes, even you can do this also using the above code. change in 5. app/code/[VendorName]/[ModuleName]/Plugin/Product/View/Type/ConfigurablePlugin.php & 7. app/code/[VendorName]/[ModuleName]/view/frontend/web/js/swatch-renderer.js, else remain same. Nov 8, 2019 at 12:15
-
ok, but overriding swatch-renderer.js can cause problems with other image modules. So perhaps first answer is a better method.– pajNov 8, 2019 at 15:59
-
@Rahul I have one small query i.e for parent level product doesn't have a description than can we display the simple product description at the description tab? Dec 26, 2019 at 8:52
-
Hi, I tried it on magento 2.3.3 and not work.. I would need this small extension for other attributes too. Can I get help for this?– JosoDec 29, 2019 at 15:49
Out of the box, when choosing options, the images and the price will change. But not product name.
More information about which elements on the page change when options are selected can be found here: Magento\ConfigurableProduct\Block\Product\View\Type\Configurable::getJsonConfig()
.
In order to display the Product name of the selected product, you can create a Plugin (Interceptor) for Magento\ConfigurableProduct\Block\Product\View\Type\Configurable::getJsonConfig()
where you need to add missing Product name for each simple product.
Switching Product name when selecting an option can be implemented in vendor/magento/module-swatches/view/base/web/js/swatch-renderer.js
and vendor/magento/module-configurable-product/view/frontend/web/js/configurable.js
depending on the type of attribute.
I made VCT Product Info Switcher
module on Magento Marketplace that solves this problem.