Question

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,

Was it helpful?

Solution

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,

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top