How To

Magento 2: How to Add Custom Input Type in Custom Option

Are you a Magento 2 store owner looking to offer more customization options to your customers? The ability to add custom input types in custom options can significantly enhance the shopping experience and cater to diverse needs. In this guide, we’ll explore how you can effortlessly integrate custom input types into your Magento 2 store’s custom options, empowering both you and your customers with more flexibility and choice.

Custom options in Magento 2 allow you to offer personalized variations of your products. These options can include dropdown menus, text fields, checkboxes, and more. While Magento 2 provides several default input types, such as text, file, and dropdown, sometimes you may need to go beyond these options to fulfill specific requirements.

Steps to Add Custom Input Types in Custom Options in Magento 2:

Step 1: Create “product_options.xml” file, inside the etc folder.

app\code\Vendor\Extension\etc\

Then add the code as follows

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/product_options.xsd">
    <option name="text" label="Text" renderer="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Type\Text">
        <inputType name="field" label="Field"/>
        <inputType name="area" label="Area"/>
    </option>
    <option name="file" label="File" renderer="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Type\File">
        <inputType name="file" label="File"/>
    </option>
    <option name="select" label="Select" renderer="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Type\Select">
        <inputType name="drop_down" label="Drop-down"/>
        <inputType name="radio" label="Radio Buttons"/>
        <inputType name="checkbox" label="Checkbox"/>
        <inputType name="multiple" label="Multiple Select"/>
        <inputType name="new_option_type" label="New Option Type"/>
    </option>
    <option name="date" label="Date" renderer="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Type\Date">
        <inputType name="date" label="Date"/>
        <inputType name="date_time" label="Date &amp; Time"/>
        <inputType name="time" label="Time"/>
    </option>
</config>

Step 2: Then create “di.xml” file inside etc folder.

app\code\Vendor\Extension\etc\

And add the code as given below

<?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\Select" type="Vendor\Extension\Block\Product\View\Options\Type\Select" />
    <preference for="Magento\Catalog\Model\Product\Option" type="Vendor\Extension\Model\Product\Option" />
</config>

Step 3: Then create “Select.php” file inside Type folder.

app\code\Vendor\Extension\Block\Product\View\Options\Type\

And include the below-mentioned code

<?php

namespace Vendor\Extension\Block\Product\View\Options\Type;

use Magento\Catalog\Block\Product\View\Options\Type\Select\CheckableFactory;
use Magento\Catalog\Block\Product\View\Options\Type\Select\MultipleFactory;
use Magento\Catalog\Helper\Data as CatalogHelper;
use Magento\Catalog\Model\Product\Option;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Pricing\Helper\Data;
use Magento\Framework\View\Element\Template\Context;
use Vendor\Extension\Model\Product\Option as ProductModel;

class Select extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions
{
    private $checkableFactory;
    private $multipleFactory;

    public function __construct(
        Context $context,
        Data $pricingHelper,
        CatalogHelper $catalogData,
        array $data = [],
        CheckableFactory $checkableFactory = null,
        MultipleFactory $multipleFactory = null
    ) {
        parent::__construct($context, $pricingHelper, $catalogData, $data);
        $this->checkableFactory = $checkableFactory ?: ObjectManager::getInstance()->get(CheckableFactory::class);
        $this->multipleFactory = $multipleFactory ?: ObjectManager::getInstance()->get(MultipleFactory::class);
    }

    public function getValuesHtml(): string
    {
        $option = $this->getOption();
        $optionType = $option->getType();
        if ($optionType === Option::OPTION_TYPE_DROP_DOWN ||
            $optionType === Option::OPTION_TYPE_MULTIPLE ||
            $optionType === ProductModel::OPTION_TYPE_NEW_OPTION_TYPE
        ) {
            $optionBlock = $this->multipleFactory->create();
        }
        if ($optionType === Option::OPTION_TYPE_RADIO ||
            $optionType === Option::OPTION_TYPE_CHECKBOX
        ) {
            $optionBlock = $this->checkableFactory->create();
        }
        return $optionBlock
            ->setOption($option)
            ->setProduct($this->getProduct())
            ->setSkipJsReloadPrice(1)
            ->_toHtml();
    }
}

Step 4: Then create “Option.php” file inside Product folder.

app\code\Vendor\Extension\Model\Product\

And add the below code-snippet

<?php

namespace Vendor\Extension\Model\Product;

use Magento\Catalog\Model\Product;

class Option extends \Magento\Catalog\Model\Product\Option
{
    const OPTION_TYPE_NEW_OPTION_TYPE = 'new_option_type';

    private $optionTypesToGroups;

    public function getGroupByType($type = null)
    {
        if ($type === null) {
            $type = $this->getType();
        }
        $optionTypesToGroups = [
            self::OPTION_TYPE_FIELD => self::OPTION_GROUP_TEXT,
            self::OPTION_TYPE_AREA => self::OPTION_GROUP_TEXT,
            self::OPTION_TYPE_FILE => self::OPTION_GROUP_FILE,
            self::OPTION_TYPE_DROP_DOWN => self::OPTION_GROUP_SELECT,
            self::OPTION_TYPE_RADIO => self::OPTION_GROUP_SELECT,
            self::OPTION_TYPE_CHECKBOX => self::OPTION_GROUP_SELECT,
            self::OPTION_TYPE_MULTIPLE => self::OPTION_GROUP_SELECT,
            self::OPTION_TYPE_NEW_OPTION_TYPE => self::OPTION_GROUP_SELECT,
            self::OPTION_TYPE_DATE => self::OPTION_GROUP_DATE,
            self::OPTION_TYPE_DATE_TIME => self::OPTION_GROUP_DATE,
            self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
        ];
        return isset($optionTypesToGroups[$type]) ? $optionTypesToGroups[$type] : '';
    }
}

Step 5: Then create “di.xml” file inside adminhtml folder.

app\code\Vendor\Extension\adminhtml

And add the following code

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <virtualType name="Magento\CatalogStaging\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
  <arguments>
   <argument name="modifiers" xsi:type="array">
    <item name="new-modifier-all" xsi:type="array">
     <item name="class" xsi:type="string">Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\All</item>
     <item name="sortOrder" xsi:type="number">71</item>
    </item>
   </argument>
  </arguments>
 </virtualType>
 <virtualType name="Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
  <arguments>
   <argument name="modifiers" xsi:type="array">
    <item name="new-modifier-all" xsi:type="array">
     <item name="class" xsi:type="string">Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\All</item>
     <item name="sortOrder" xsi:type="number">71</item>
    </item>
   </argument>
  </arguments>
 </virtualType>
 <virtualType name="Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\Pool" type="Magento\Ui\DataProvider\Modifier\Pool">
  <arguments>
   <argument name="modifiers" xsi:type="array">
   </argument>
  </arguments>
 </virtualType>
 <type name="Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\All">
  <arguments>
   <argument name="pool" xsi:type="object">Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\Pool</argument>
  </arguments>
 </type>
 <virtualType name="Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\Pool">
  <arguments>
   <argument name="modifiers" xsi:type="array">
    <item name="new-custom-option" xsi:type="array">
     <item name="class" xsi:type="string">Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\CustomOptions</item>
     <item name="sortOrder" xsi:type="number">72</item>
    </item>
   </argument>
  </arguments>
 </virtualType>
</config>

Step 6: Then create “All.php” file inside Modifier folder.

app\code\Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\

Now add the below-mentioned piece of code

<?php

namespace Vendor\Extension\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Ui\DataProvider\Modifier\ModifierInterface;
use Magento\Ui\DataProvider\Modifier\PoolInterface;

class All extends AbstractModifier implements ModifierInterface
{
    protected $pool;
    protected $meta = [];

    public function __construct(
        PoolInterface $pool
    ) {
        $this->pool = $pool;
    }

    public function modifyData(array $data)
    {
        foreach ($this->pool->getModifiersInstances() as $modifier) {
            $data = $modifier->modifyData($data);
        }

        return $data;
    }

    public function modifyMeta(array $meta)
    {
        $this->meta = $meta;

        foreach ($this->pool->getModifiersInstances() as $modifier) {
            $this->meta = $modifier->modifyMeta($this->meta);
        }

        return $this->meta;
    }
}

Step 7: Then create “CustomOptions.php” file inside Modifier folder.

app\code\Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\

And add the code as follows

<?php

namespace Vendor\Extension\Ui\DataProvider\Product\Form\Modifier;

use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions as CustomOptionsModifier;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\StoreManagerInterface;

class CustomOptions extends AbstractModifier
{
    protected $meta = [];
    protected $urlBuilder;
    protected $locator;
    protected $storeManager;

    public function __construct(
        UrlInterface $urlBuilder,
        LocatorInterface $locator,
        StoreManagerInterface $storeManager
    ) {
        $this->urlBuilder = $urlBuilder;
        $this->locator = $locator;
        $this->storeManager = $storeManager;
    }

    public function modifyData(array $data)
    {
        return $data;
    }

    public function modifyMeta(array $meta)
    {
        $this->meta = $meta;

        $this->addCustomOptionsFields();

        return $this->meta;
    }

    protected function addCustomOptionsFields()
    {
        $groupCustomOptionsName = CustomOptionsModifier::GROUP_CUSTOM_OPTIONS_NAME;
        $optionContainerName = CustomOptionsModifier::CONTAINER_OPTION;
        $commonOptionContainerName = CustomOptionsModifier::CONTAINER_COMMON_NAME;
        $fieldTypeName = CustomOptionsModifier::FIELD_TYPE_NAME;

        $this->meta[$groupCustomOptionsName]['children']['options']['children']['record']['children']
        [$optionContainerName]['children']
        [$commonOptionContainerName]['children']
        [$fieldTypeName]['arguments']['data']['config']['groupsConfig']['select'] = $this->getSelect();
    }

    private function getSelect()
    {
        return [
            'values' => [
                'drop_down',
                'radio',
                'checkbox',
                'multiple',
                'new_option_type',
            ],
            'indexes' => [
                CustomOptionsModifier::GRID_TYPE_SELECT_NAME,
            ],
        ];
    }
}

Output:

Conclusion:

Custom input types in custom options empower Magento 2 store owners to offer unparalleled flexibility and personalization to their customers. By understanding your requirements, developing custom input type modules, and seamlessly integrating them with Magento 2’s custom options feature, you can elevate the shopping experience and drive sales growth.

Whether you’re selling customizable apparel, personalized gifts, or bespoke products, incorporating custom input types can set your store apart and delight your customers with tailored offerings. Embrace the power of customization and unlock new opportunities for your Magento 2 store today!

Happy Coding!

Click to rate this post!
[Total: 0 Average: 0]
Dhiren Vasoya

Dhiren Vasoya is a Director and Co-founder at MageComp, Passionate ?️ Certified Magento Developer?‍?. He has more than 9 years of experience in Magento Development and completed 850+ projects to solve the most important E-commerce challenges. He is fond❤️ of coding and if he is not busy developing then you can find him at the cricket ground, hitting boundaries.?

Recent Posts

How to Add Tooltip in Checkout Shipping Field in Magento 2?

Hello Magento Friends, In today’s blog, I will explain How to Add Tooltip in Checkout…

2 days ago

How to Integrate and Use MongoDB with Laravel?

MongoDB is a popular NoSQL database that offers flexibility and scalability when handling modern web…

3 days ago

NodeJS | Callback Function

In NodeJS, callbacks empower developers to execute asynchronous operations like reading files, handling requests, and…

4 days ago

How to Show SKU in Order Summary in Magento 2?

Hello Magento Friends, In today’s blog, we will learn How to Show SKU in Order…

6 days ago

Best Colors to Use for CTA Buttons

The "Buy Now" and "Add to Cart" buttons serve as the primary call-to-action (CTA) elements…

1 week ago

Magento 2: How to Save Custom Field Value to quote_address for Multi-Shipping Orders

Hello Magento Friends, In Magento 2, the checkout process allows customers to choose multiple shipping…

1 week ago