4

enter image description here

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,

  • Add attribute of the name, add a name in that attribute and in the product page change the product name with Ajax on click event. – Krunal Pandya Jul 6 '19 at 7:01
5

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,

|improve this answer|||||
  • Hi, @Jimmy Labuche Thank you for this detailed solution – Shafeel Sha Jul 6 '19 at 10:48
  • With pleasure! ! Feel free to pass your subject to solved if it is :) – Jimmy Labuche Jul 6 '19 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? – Shafeel Sha Jul 6 '19 at 11:08
  • I checked, I cannot reproduce your problem. Can you tell me more about it ? Have you a link ? – Jimmy Labuche Jul 6 '19 at 11:13
  • please check updated question :) Thank you – Shafeel Sha Jul 6 '19 at 11:20
4

Module Method Working For me in Magento 2.1 / 2.2 /2.3 :: The below Code is to change Name & Description both.


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');
            }
        },

** Output::** enter image description here

|improve this answer|||||
  • Can you change the SKU also? – paj Nov 8 '19 at 12:03
  • @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. – Rahul Shukla Nov 8 '19 at 12:15
  • ok, but overriding swatch-renderer.js can cause problems with other image modules. So perhaps first answer is a better method. – paj Nov 8 '19 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? – Nagaraju K Dec 26 '19 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? – Joso Dec 29 '19 at 15:49

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.