5

How I can change my configurable product name and description dynamically when one option is selected, right now is change only the image, I need to do the same with the name and description.

HTML structure:

<div class="product media">
    <div class="product attribute description">
        <div class="value">
            <p>text description.</p>
        </div>
    </div>
</div>

enter image description here

4

4 Answers 4

12

You can try below custom module and modify according to your requirement.

app/code/Anshu/SCdata/registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Anshu_SCdata',
    __DIR__
);

app/code/Anshu/SCdata/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="Anshu_SCdata" setup_version="1.0.0">
            <sequence>
                <module name="Magento_Swatches"/>
            </sequence>
        </module>
    </config>

app/code/Anshu/SCdata/etc/frontend/di.xml

<?xml version="1.0" encoding="UTF-8"?>
    <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="anshu_configurable_product_configurable"
                    type="Anshu\SCdata\Block\ConfigurableProduct\Product\View\Type\Configurable"
                    sortOrder="1"/>
        </type>
    </config>

app/code/Anshu/SCdata/Block/ConfigurableProduct/Product/View/Type/Configurable.php

<?php

namespace Anshu\SCdata\Block\ConfigurableProduct\Product\View\Type;

use Magento\Framework\Json\EncoderInterface;
use Magento\Framework\Json\DecoderInterface;

class Configurable
{
    protected $jsonEncoder;
    protected $jsonDecoder;
    protected $_productRepository;

    public function __construct(
            \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
            EncoderInterface $jsonEncoder,
            DecoderInterface $jsonDecoder
    ) {
        $this->jsonDecoder = $jsonDecoder;
        $this->jsonEncoder = $jsonEncoder;
        $this->_productRepository = $productRepository;
    }
    
    public function getProductById($id)
    {
        return $this->_productRepository->getById($id);
    }

    public function aroundGetJsonConfig(
        \Magento\ConfigurableProduct\Block\Product\View\Type\Configurable $subject,
        \Closure $proceed
    )
    {
        $sname = [];
        $sdescription = [];
        
        $config = $proceed();
        $config = $this->jsonDecoder->decode($config);

        foreach ($subject->getAllowProducts() as $prod) {
            $id = $prod->getId();
            $product = $this->getProductById($id);
            $sname[$id] = $product->getName();
            $sdescription[$id] = $product->getDescription();
        }
        $config['sname'] = $sname;
        $config['sdescription'] = $sdescription;

        return $this->jsonEncoder->encode($config);
    }
}

app/code/Anshu/SCdata/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {
            'Magento_Swatches/js/swatch-renderer' : 'Anshu_SCdata/js/swatch-renderer',
            'magento-swatch.renderer' : 'Magento_Swatches/js/swatch-renderer',
        }
    }
};

app/code/Anshu/SCdata/view/frontend/web/js/swatch-renderer.js

define([
  'jquery',
  'jquery/ui',
  'magento-swatch.renderer'
], function($){
 
  $.widget('anshu.SwatchRenderer', $.mage.SwatchRenderer, { 
        
        /**
         * Event for swatch options
         *
         * @param {Object} $this
         * @param {Object} $widget
         * @private
         */
        _OnClick: function ($this, $widget) {
            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);
            }

            $widget._Rebuild();
            
            // Custom Code starts
            var iname = $widget.options.jsonConfig.sname[this.getProduct()];
            var idescription = $widget.options.jsonConfig.sdescription[this.getProduct()];
            
            if(idescription != ''){
                $('[data-role="content"]').find('.description .value').html(idescription);
            }
            if(iname != ''){
                $('[data-ui-id="page-title-wrapper"]').html(iname);
            }
            // Custom code ends

            if ($widget.element.parents($widget.options.selectorProduct)
                    .find(this.options.selectorProductPrice).is(':data(mage-priceBox)')
            ) {
                $widget._UpdatePrice();
            }

            $widget._loadMedia();
            $input.trigger('change');
        }
  
    });
 
  return $.anshu.SwatchRenderer;
});

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.sname,
                    childProductDescription = this.options.jsonConfig.sdescription;

                $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.sname) {
                    
                    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.sdescription) {
                    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;
    }
});

** Output::** enter image description here

19
  • Hi thanks for your complete answer, I have only one issue the description is not work, I really don't know what is happened. can you check please?
    – Robert
    Jan 27, 2018 at 14:26
  • I forgot to tell you, in my custom theme I move the description here: <move element="product.info.description" destination="product.info.media" before="product.info.media.image"/> maybe this can be the issue?
    – Robert
    Jan 27, 2018 at 14:33
  • Change the code $('[data-role="content"]').find('.description .value').html(idescription); according to your placement of the element. Rest of the code will be the same. Jan 29, 2018 at 4:56
  • I already do this but still not working
    – Robert
    Jan 29, 2018 at 7:28
  • you have any idea what is wrong with this module? why is not work description?
    – Robert
    Jan 30, 2018 at 11:10
4

Try following module:

  1. app/code/[VendorName]/[ModuleName]/registration.php
  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">
        <sequence>
            <module name="Magento_Swatches"/>
        </sequence>
    </module>
</config>
  1. 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>
  1. 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('description');
        return $result;
    }
}
  1. 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->getDescription()) {
            $result['productDescription'] = $currentProduct->getDescription();
        }

        foreach ($subject->getAllowProducts() as $product) {
            $result['descriptions'][$product->getId()][] =
                [
                    'description' => $product->getData('description'),
                ];
        }

        return $this->jsonEncoder->encode($result);
    }
}
  1. app/code/[VendorName]/[ModuleName]/view/frontend/requirejs-config.js
var config = {
    map: {
        '*': {
            'Magento_Swatches/js/swatch-renderer':'[VendorName]_[ModuleName]/js/swatch-renderer'
        }
    }
};
  1. app/code/[VendorName]/[ModuleName]/view/frontend/web/js/swatch-renderer.js
_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('.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');
},

Note: Copy original JS file(vendor/magento/module-swatches/view/frontend/web/js/swatch-renderer.js) and paste on the above path and update above function(_OnClick) OR you can customize JS code as per your requirement. Here, you can also use minix to override JS function.

2
  • Hi thank you, but I think your code is not complete, I have errors
    – Robert
    Jan 27, 2018 at 13:42
  • how to change the custom attribute for this
    – Divya
    May 28, 2019 at 9:43
0

Out of the box, when choosing options, the images and the price will change. But not product name and description.

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 and description 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 and description for each simple product.

Switching product name and description 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 (Visual Swatch, Text Swatch, Dropdown).


I made VCT Product Info Switcher module on Magento Marketplace that solves this problem.

-1

You can use an observer and event product before save and set your dynamically created description based in certain conditions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.