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

Mastering Tailwind CSS in Laravel: A Comprehensive Guide

Tailwind CSS has emerged as a powerful utility-first CSS framework, offering developers a unique approach…

2 days ago

React Native or Flutter in 2024

The mobile app development field has witnessed a rapid revolution over the past few years.…

3 days ago

Magento 2: How To Call JS on the Checkout Page?

Hello Magento mates, Today we will learn to add a call JS on the checkout…

6 days ago

Boost Your SEM Game: Unveiling the Top 10 Tools for Marketers in 2024

Business survival in today’s digital world has become extremely difficult. Using traditional marketing techniques is…

1 week ago

Five Essential Payroll Compliance Tips for eCommerce Startups

Are you setting up a payroll system for your eCommerce startup? Ensuring compliance with myriad…

1 week ago

Optimizing Laravel Blade: Unlocking Advanced Fetcher Techniques

In the expansive universe of Laravel development, Blade serves as the stellar templating engine, propelling…

1 week ago