Creating Customizable Options for products programatically in magento 2

There may be a situation when one wants to create some predetermined customizable options for products, while creating new products from admin.
There may be different event where one wants to add this customizable options, in my case i am going to add customizable options to products on ‘checkout_onepage_controller_success_action’ event.

Let’s dive deep into step by step process.

Creating a new module skeleton :

you need to create a new module for implementing (basically two files registration.php and module.xml files)

Vendor: Excellence
Module : GiftCard

registration.php (magento_root/vendor/module/registration.php)

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

module.xml (magento_root/vendor/module/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="Excellence_GiftCard" setup_version="1.0.0"/>
</config>

events.xml (magento_root/vendor/module/etc/events.xml)

Now here i am defining my observer to trigger on save after event of product.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_after">
        <observer name="add_giftcard_custom_options" instance="Excellence\GiftCard\Observer\Adminhtml\GiftCardOptions" />
    </event>    
</config>

GiftCardOptions.php (magento_root/vendor/module/Observer/Adminhtml/GiftCardOptions.php)

Now i am defining observer file mentioned into event file at specified loaction to create pre-determined customizable options to create along with products.

<?php
namespace Excellence\GiftCard\Observer\Adminhtml;
use Magento\Framework\Event\ObserverInterface;
 
class GiftCardOptions implements ObserverInterface
{
    protected $_productOptions;
    protected $_productRepository;
    protected $_giftCardHelper;
 
    public function __construct(
        \Magento\Catalog\Model\Product\Option $productOptions,
        \Magento\Catalog\Model\Product $productRepository,
        \Excellence\GiftCard\Helper\Data $giftCardHelper
    ){
        $this->_productOptions = $productOptions;
        $this->_productRepository = $productRepository;
        $this->_giftCardHelper = $giftCardHelper;
    }
 
    public function execute(\Magento\Framework\Event\Observer $observer){
        $product = $observer->getProduct();
            $optionsStatus = $this->isOptionsExists($product);
            if(!$optionsStatus){
                $productId = $observer->getProduct()->getId();
                $productFromRepo = $this->_productRepository->load($productId);
                $values = [
                            [
                                'record_id'=>0,                                        
                                'title'=>'Gift Card',
                                'price'=>10,
                                'price_type'=>"fixed",
                                'sort_order'=>1,
                                'is_delete'=>0
                            ],
                            [
                                'record_id'=>1,                    
                                'title'=>'Gift Card',
                                'price'=>20,
                                'price_type'=>"fixed",
                                'sort_order'=>1,
                                'is_delete'=>0
                            ],
                            [
                                'record_id'=>2,                    
                                'title'=>'Gift Card',
                                'price'=>30,
                                'price_type'=>"fixed",
                                'sort_order'=>1,
                                'is_delete'=>0
                            ]
                ];

                $options = [
                            [
                                "sort_order"    => 0,
                                "title"         => "Gift Card Value",
                                "price_type"    => "fixed",
                                "type"          => "drop_down",
                                "is_require"    => 1,
                                "values"        => $values
                            ],[
                                "sort_order"    => 1,
                                "title"         => "Sender Name",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "field",
                                "is_require"    => 1
                            ],[
                                "sort_order"    => 2,
                                "title"         => "Sender Email",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "field",
                                "is_require"    => 1
                            ],[
                                "sort_order"    => 3,
                                "title"         => "Receiver Name",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "field",
                                "is_require"    => 1
                            ],[
                                "sort_order"    => 4,
                                "title"         => "Receiver Email",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "field",
                                "is_require"    => 1
                            ],[
                                "sort_order"    => 5,
                                "title"         => "Message",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "area",
                                "is_require"    => 0
                            ],[
                                "sort_order"    => 6,
                                "title"         => "Scheduled Date",
                                "price_type"    => "fixed",
                                "price"         => "",
                                "type"          => "date",
                                "is_require"    => 1
                            ]
                ];

                $productFromRepo->setHasOptions(1);
                $productFromRepo->setCanSaveCustomOptions(true);
                foreach ($options as $arrayOption) {
                    $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); //instance of Object manager
                    $option = $objectManager->create('\Magento\Catalog\Model\Product\Option')
                    ->setProductId($productId)
                    ->setStoreId($product->getStoreId())
                    ->addData($arrayOption);
                    $option->save();
                    $productFromRepo->addOption($option);
                }
                $productFromRepo->save();
        }        
    }
    
    public function isOptionsExists($product){
        foreach ($product->getOptions() as $value) {
            return true;
    }
        return false;
    }
}

The above file creates product customizable options along with product which can be visible under product customizable options tab.

Product Customizable Options View

You can also browse this product on store front to verify the same

Store Front View