How to Remove + Sign from Customizable Option Titles in Magento 2 Programmatically?

1
6818
Product Options Customization in Magento 2 | Mageworx Magento Blog
Reading Time: 5 minutes

Product options customization is vital to meet business needs.

In this article, we will focus on how to change the titles of the selected options and consider two examples.

In the first example,

We will focus on how to change titles of the selected option values of the “selectable” type with the help of the Mageworx Advanced Product Options extension and “js”.

In the second example,

We will focus on how to change the titles of “non-selectable” options with the help of “php”.

New Module Creation

New module creation was described in detail in this blog post.

Thus, let’s not focus on it today and move straight to the code. Here’s the code we’ll need:

1.composer.json

{
    "name": "mageworx/module-optionremoveplus",
    "description": "N/A",
    "require": {
        "magento/framework"     :     ">=100.1.0 <101",
        "magento/module-catalog":     ">=101.0.0 <104"
    },
    "type": "magento2-module",
    "version": "1.0.0",
    "license": [
        "OSL-3.0",
        "AFL-3.0"
    ],
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "VendorName\\OptionRemovePlus\\": ""
        }
    }
}

2.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_OptionRemovePlus" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Catalog"/>
            <module name="MageWorx_OptionBase"/>
        </sequence>
    </module>
</config>

3. registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'VendorName_OptionRemovePlus',
    __DIR__
);

Example #1. Changing Titles of Other Option Types

Here, we will cover such input types as drop-down, radio button, checkbox, and multiple select.

Let’s delete the + sign from the titles of selected option values. We will achieve this with the help of our Advanced Product Options extension. 

Out of the box, Advanced Product Options has the functionality to handle titles of the selected option values on the front-end of product pages. It gets achieved with the help of “js” in

app/code/MageWorx/OptionBase/view/base/web/js/catalog/product/base.js.

Before we begin, create a test product that has all the types of selectable options. It is done to see how these option values look on the front-end by default.

Product Options Customization in Magento 2 | Mageworx Magento Blog

How about changing these titles?

To do that, we will need to rewrite a couple of functions from app/code/MageWorx/OptionBase/view/base/web/js/catalog/product/base.js.

Let’s use the known JavaScript mixins mechanism to achieve that. 

Create the following file and define our mixin there:

app/code/VendorName/OptionRemovePlus/view/base/requirejs-config.js

var config = {
    config: {
        mixins: {
            'MageWorx_OptionBase/js/catalog/product/base': {
                'VendorName_OptionRemovePlus/js/catalog/product/base-mixin' : true
            }
        }
    }
};

Now, create the following file with the redefined functions that we need:

app/code/VendorName/OptionRemovePlus/view/base/web/js/catalog/product/base-mixin.js

define([
   'jquery',
   'Magento_Catalog/js/price-utils',
   'uiRegistry',
   'underscore',
   'mage/template',
   'jquery/ui'
], function ($, utils, registry, _, mageTemplate) {
   'use strict';

   return function (widget) {
       $.widget('mageworx.optionBase', widget, {

           /**
            * Make changes to select options
            * @param options
            * @param opConfig
            */
           _updateSelectOptions: function(options, opConfig)
           {
               var self = this;
               options.each(function (index, element) {
                   var $element = $(element);

                   if ($element.hasClass('datetime-picker') ||
                       $element.hasClass('text-input') ||
                       $element.hasClass('input-text') ||
                       $element.attr('type') == 'file'
                   ) {
                       return true;
                   }

                   var optionId = utils.findOptionId($element),
                       optionConfig = opConfig[optionId];

                   $element.find('option').each(function (idx, option) {
                       var $option = $(option),
                           optionValue = $option.val();

                       if (!optionValue && optionValue !== 0) {
                           return;
                       }

                       var title = optionConfig[optionValue] && optionConfig[optionValue].name,
                           valuePrice = utils.formatPrice(optionConfig[optionValue].prices.finalPrice.amount),
                           stockMessage = '',
                           specialPriceDisplayNode = '';

                       if (optionConfig[optionValue]) {
                           if (!_.isEmpty(optionConfig[optionValue].special_price_display_node)) {
                               specialPriceDisplayNode = optionConfig[optionValue].special_price_display_node;
                           }
                           if (!_.isEmpty(optionConfig[optionValue].stockMessage)) {
                               stockMessage = optionConfig[optionValue].stockMessage;
                           }
                           if (!_.isEmpty(optionConfig[optionValue].title)) {
                               title = optionConfig[optionValue].title;
                           }
                           if (!_.isEmpty(optionConfig[optionValue].valuePrice)) {
                               valuePrice = optionConfig[optionValue].valuePrice;
                           }
                       }
                       if (specialPriceDisplayNode) {
                           $option.text(title + ' ' + specialPriceDisplayNode + ' ' + stockMessage);
                       } else if (stockMessage) {
                           if (parseFloat(optionConfig[optionValue].prices.finalPrice.amount) > 0) {
                               $option.text(title + ' +' + valuePrice + ' ' + stockMessage);
                           } else {
                               $option.text(title + stockMessage);
                           }
                       }

                       $option.text(title + ' ' + valuePrice + ' ' + stockMessage);
                   });
               });
           },

           /**
            * Make changes to select options
            * @param options
            * @param opConfig
            */
           _updateInputOptions: function(options, opConfig)
           {
               var self = this;
               options.each(function (index, element) {
                   var $element = $(element);

                   if ($element.hasClass('datetime-picker') ||
                       $element.hasClass('text-input') ||
                       $element.hasClass('input-text') ||
                       $element.attr('type') == 'file'
                   ) {
                       return true;
                   }

                   var optionId = utils.findOptionId($element),
                       optionValue = $element.val();

                   if (!optionValue && optionValue !== 0) {
                       return;
                   }

                   var optionConfig = opConfig[optionId],
                       title = optionConfig[optionValue] && optionConfig[optionValue].name,
                       valuePrice = utils.formatPrice(optionConfig[optionValue].prices.finalPrice.amount),
                       stockMessage = '',
                       specialPriceDisplayNode = '';

                   if (optionConfig[optionValue]) {
                       if (!_.isEmpty(optionConfig[optionValue].special_price_display_node)) {
                           specialPriceDisplayNode = optionConfig[optionValue].special_price_display_node;
                       }
                       if (!_.isEmpty(optionConfig[optionValue].stockMessage)) {
                           stockMessage = optionConfig[optionValue].stockMessage;
                       }
                       if (!_.isEmpty(optionConfig[optionValue].title)) {
                           title = optionConfig[optionValue].title;
                       }
                       if (!_.isEmpty(optionConfig[optionValue].valuePrice)) {
                           valuePrice = optionConfig[optionValue].valuePrice;
                       }
                   }
                   if (specialPriceDisplayNode) {
                       $element.next('label').text(title + ' ' + specialPriceDisplayNode + ' ' + stockMessage);
                   } else if (stockMessage) {
                       if (parseFloat(optionConfig[optionValue].prices.finalPrice.amount) > 0) {
                           $element.next('label').text(title + ' +' + valuePrice + ' ' + stockMessage);
                       } else {
                           $element.next('label').text(title + stockMessage);
                       }
                   }

                   $element.next('label').text(title + ' ' + valuePrice + ' ' + stockMessage);
               });
           },

       });
       return $.mageworx.optionBase;
   };

});

Here’s the result:

Product Options Customization in Magento 2 | Mageworx Magento Blog

Example #2. Changing Titles of Selected Option Values 

Here, we will cover such input types as field, area, file, date, time, and date & time.

Let’s delete the + sign from the titles of selected option values. We will achieve this with the help of PHP, rewrite the classes that implement this method of the needed option type.

Before we begin, create a test product that has all the types of selectable options. It is done to see how these option values look on the front-end by default.

Product Options Customization in Magento 2 | Mageworx Magento Blog

Now, create the following file:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Product\View\Options\Type\Text"
                type="VendorName\OptionRemovePlus\Block\Product\View\Options\Type\Text" />
    <preference for="Magento\Catalog\Block\Product\View\Options\Type\Date"
                type="VendorName\OptionRemovePlus\Block\Product\View\Options\Type\Date" />
    <preference for="Magento\Catalog\Block\Product\View\Options\Type\File"
                type="VendorName\OptionRemovePlus\Block\Product\View\Options\Type\File" />
</config>

It’s time to create our classes and to rewrite the method:

app/code/VendorName/OptionRemovePlus/Block/Product/View/Options/Type/Date.php

<?php
namespace VendorName\OptionRemovePlus\Block\Product\View\Options\Type;

use Magento\Catalog\Pricing\Price\CustomOptionPriceInterface;

/**
 * Product options text type block
 *
 * @api
 * @since 100.0.2
 */
class Date extends \Magento\Catalog\Block\Product\View\Options\Type\Date
{
    /**
     * Return formatted price
     *
     * @param array $value
     * @param bool $flag
     * @return string
     */
    protected function _formatPrice($value, $flag = true)
    {
        if ($value['pricing_value'] == 0) {
            return '';
        }

        $sign = ' ';
        if ($value['pricing_value'] < 0) {
            $sign = '-';
            $value['pricing_value'] = 0 - $value['pricing_value'];
        }

        $priceStr = $sign;

        $customOptionPrice = $this->getProduct()->getPriceInfo()->getPrice('custom_option_price');
        $context = [CustomOptionPriceInterface::CONFIGURATION_OPTION_FLAG => true];
        $optionAmount = $customOptionPrice->getCustomAmount($value['pricing_value'], null, $context);
        $priceStr .= $this->getLayout()->getBlock('product.price.render.default')->renderAmount(
            $optionAmount,
            $customOptionPrice,
            $this->getProduct()
        );

        if ($flag) {
            $priceStr = '<span class="price-notice">' . $priceStr . '</span>';
        }

        return $priceStr;
    }
}

app/code/VendorName/OptionRemovePlus/Block/Product/View/Options/Type/File.php

<?php

namespace VendorName\OptionRemovePlus\Block\Product\View\Options\Type;

use Magento\Catalog\Pricing\Price\CustomOptionPriceInterface;

/**
 * Product options text type block
 *
 * @api
 * @since 100.0.2
 */
class File extends \Magento\Catalog\Block\Product\View\Options\Type\File
{
    /**
     * Return formatted price
     *
     * @param array $value
     * @param bool $flag
     * @return string
     */
    protected function _formatPrice($value, $flag = true)
    {
        if ($value['pricing_value'] == 0) {
            return '';
        }

        $sign = ' ';
        if ($value['pricing_value'] < 0) {
            $sign = '-';
            $value['pricing_value'] = 0 - $value['pricing_value'];
        }

        $priceStr = $sign;

        $customOptionPrice = $this->getProduct()->getPriceInfo()->getPrice('custom_option_price');
        $context = [CustomOptionPriceInterface::CONFIGURATION_OPTION_FLAG => true];
        $optionAmount = $customOptionPrice->getCustomAmount($value['pricing_value'], null, $context);
        $priceStr .= $this->getLayout()->getBlock('product.price.render.default')->renderAmount(
            $optionAmount,
            $customOptionPrice,
            $this->getProduct()
        );

        if ($flag) {
            $priceStr = '<span class="price-notice">' . $priceStr . '</span>';
        }

        return $priceStr;
    }
}

app/code/VendorName/OptionRemovePlus/Block/Product/View/Options/Type/Text.php

<?php

namespace VendorName\OptionRemovePlus\Block\Product\View\Options\Type;

use Magento\Catalog\Pricing\Price\CustomOptionPriceInterface;

/**
 * Product options text type block
 *
 * @api
 * @since 100.0.2
 */
class Text extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions
{

    /**
     * Return formatted price
     *
     * @param array $value
     * @param bool $flag
     * @return string
     */
    protected function _formatPrice($value, $flag = true)
    {
        if ($value['pricing_value'] == 0) {
            return '';
        }

        $sign = ' ';
        if ($value['pricing_value'] < 0) {
            $sign = '-';
            $value['pricing_value'] = 0 - $value['pricing_value'];
        }

        $priceStr = $sign;

        $customOptionPrice = $this->getProduct()->getPriceInfo()->getPrice('custom_option_price');
        $context = [CustomOptionPriceInterface::CONFIGURATION_OPTION_FLAG => true];
        $optionAmount = $customOptionPrice->getCustomAmount($value['pricing_value'], null, $context);
        $priceStr .= $this->getLayout()->getBlock('product.price.render.default')->renderAmount(
            $optionAmount,
            $customOptionPrice,
            $this->getProduct()
        );

        if ($flag) {
            $priceStr = '<span class="price-notice">' . $priceStr . '</span>';
        }

        return $priceStr;
    }
}

Here’s the result:

Product Options Customization in Magento 2 | Mageworx Magento Blog

What’s the bottom line?

This article provides all the information required to change the titles of product options and option values completely.

Should you have any questions or difficulties, feel free to leave a comment below. We will be happy to assist!

Book a Live Demo with Mageworx

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here