How To

Magento 2: How to Add Dynamic Field in Product Create/Edit Form

Hello Magento Friends,

In this Magento tutorial, we will find out How to Add Dynamic Field in Admin Product Edit Form.

Magento provides flexibility to customize product attributes and forms according to specific business needs. By adding dynamic fields in admin product edit form you can tailor your product information to match your unique requirements without modifying the core code.

So let’s get started.

Steps to Add Dynamic Field in Product Create/Edit Form in Magento 2:

Here city and related shipping cost is saved on product. We can use this data on phtml file, controller file . 

Step 1: Create product attribute using below code. Using attributes we can save data of dynamic fields.

Add code at the below path

{{magento_root}}/app/code/Vendor/Extension/Setup/Patch/Data/Shippingdataattribute.php

<?php

namespace Vendor\Extension\Setup\Patch\Data;

use Magento\Catalog\Model\Category;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

class Shippingdataattribute implements DataPatchInterface
{
    private $moduleDataSetup;
    private $eavSetupFactory;

    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }

    public function apply()
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $eavSetup->addAttribute(
            Product::ENTITY,
            'custom_shippingdata',
            [
                'group' => 'Shipping Data',
          'label' => 'Shipping Data',
    'type'  => 'text',
    'default'  => '0',
          'input' => 'text',
                'required' => false,
                'sort_order' => 1,
    'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
                'used_in_product_listing' => true,
                'visible_on_front' => false,
                'visible' => false
            ]
        );

    }

    public static function getDependencies()
    {
        return [];
    }

    public function getAliases()
    {
        return [];
    }
}

Step 2: Add code in the Model file

{{magento_root}}/app/code/Vendor/Extension/Model/System/Config/Shipingmethod.php

<?php
namespace Vendor\Extension\Model\System\Config;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Shipping\Model\Config;

class Shipingmethod extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
    protected $scopeConfig;
    protected $shipment;

    public function __construct(
        Config $shippingmodelconfig, 
        ScopeConfigInterface $scopeConfig
    )
    {
        $this->scopeConfig = $scopeConfig;
        $this->shipment = $shippingmodelconfig;
    }

    public function getAllOptions()
    {
        
        $options = [
            0 => [
                'label' => 'Bhavnagar',
                'value' => 10
            ],
            1  => [
                'label' => 'Surat',
                'value' => 20
            ],
            2 => [
                'label' => 'Rajkot',
                'value' => 30
            ],
        ];

        return $options;
    }
}

Step 3: Create di.xml file at the following path.

{{magento_root}}/app/code/Vendor/Extension/etc/di.xml

And add the below-mentioned 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\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool">
        <arguments>
            <argument name="modifiers" xsi:type="array">
                <item name="advanced-supplier-pricing" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Extension\Ui\DataProvider\Product\Form\Modifier\AdvancedSupplierPrices</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>

Step 4: Create ui component file at the following path 

{{magento_root}}/app/code/Vendor/Extension/Ui/DataProvider/Product/Form/Modifier/AdvancedSupplierPrices.php

Now, add the below code snippet

<?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\Ui\Component\Form\Element\DataType\Price;
use Magento\Ui\Component\Form\Fieldset;
use Magento\Ui\Component\Form\Field;
use Magento\Ui\Component\Form\Element\Input;
use Magento\Ui\Component\DynamicRows;
use Magento\Ui\Component\Container;
use Magento\Ui\Component\Form\Element\Select;
use Magento\Ui\Component\Form\Element\DataType\Text;
use Vendor\Extension\Model\System\Config\Shipingmethod;

class AdvancedSupplierPrices extends AbstractModifier
{

    const FIELD_IS_DELETE = 'is_delete';
    const FIELD_SORT_ORDER_NAME = 'sort_order';
    private $locator;

    public function __construct(
        LocatorInterface $locator,
        Shipingmethod $shipingmethod
    ) {
        $this->locator = $locator;
        $this->shipingmethod = $shipingmethod;
    }

    
    public function modifyData(array $data)
    {
        $fieldCode = 'shipping_fieldset';

        $productId = $this->locator->getProduct()->getId();

        if($this->locator->getProduct()->getCustomShippingdata()){
            
            $array = json_decode($this->locator->getProduct()->getCustomShippingdata(),true);
            $fields = [];

            if(isset($array['shipping_field'])){
                foreach($array['shipping_field'] as $key => $value){
                    $fields[$key] =  $value;
                }           
            $data[$productId]['product'][$fieldCode]['shipping_field'] =  $fields;
            }
        }
        return $data;
    }
    public function modifyMeta(array $meta)
    {
        $meta = array_replace_recursive(
            $meta,
            [
                'shipping_fieldset' => [
                    'arguments' => [
                        'data' => [
                            'config' => [
                                'label' => __('Shipping Mehtods'),
                                'componentType' => Fieldset::NAME,
                                'dataScope' => 'data.product.shipping_fieldset',
                                'collapsible' => true,
                                'sortOrder' => 5,
                            ],
                        ],
                    ],
                    'children' => [
                        "shipping_field" => $this->getSelectTypeGridConfig(10)
                    ],
                ]
            ]
        );

        return $meta;
    }
    protected function getSelectTypeGridConfig($sortOrder) {
        return [
            'arguments' => [
                'data' => [
                    'config' => [
                        'addButtonLabel' => __('Add Shipping Price'),
                        'componentType' => DynamicRows::NAME,
                        'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows',
                        'additionalClasses' => 'admin__field-wide',
                        'deleteProperty' => static::FIELD_IS_DELETE,
                        'deleteValue' => '1',
                        'renderDefaultRecord' => false,
                        'sortOrder' => $sortOrder,
                    ],
                ],
            ],
            'children' => [
                'record' => [
                    'arguments' => [
                        'data' => [
                            'config' => [
                                'componentType' => Container::NAME,
                                'component' => 'Magento_Ui/js/dynamic-rows/record',
                                'positionProvider' => static::FIELD_SORT_ORDER_NAME,
                                'isTemplate' => true,
                                'is_collection' => true,
                            ],
                        ],
                    ],
                    'children' => [
                        'shipment' => [
                            'arguments' => [
                                'data' => [
                                    'config' => [
                                        'formElement' => Select::NAME,
                                        'componentType' => Field::NAME,
                                        'dataType' => Text::NAME,
                                        'dataScope' => 'shipment',
                                        'label' => __('Shipping Methods'),
                                        'options' => $this->shipingmethod->getAllOptions(),
                                        'value' => 0,
                                        'sortOrder' => 20,
                                        'additionalClasses' => 'select-shipping-methods',
                                    ],
                                ],
                            ],
                        ],
                        'ship_price' => [
                            'arguments' => [
                                'data' => [
                                    'config' => [
                                        'componentType' => Field::NAME,
                                        'formElement' => Input::NAME,
                                        'dataType' => Price::NAME,
                                        'label' => __('Shipping Price'),
                                        'enableLabel' => true,
                                        'dataScope' => 'ship_price',
                                        'sortOrder' => 40,
                                        'validation' => [
                                            'required-entry' => true,
                                            'validate-zero-or-greater' => true,
                                            'validate-number' => true,
                                        ],
                                    ],
                                ],
                            ],
                        ],
                        'actionDelete' => [
                            'arguments' => [
                                'data' => [
                                    'config' => [
                                        'componentType' => 'actionDelete',
                                        'dataType' => Text::NAME,
                                        'label' => '',
                                        'sortOrder' => 55,
                                    ],
                                ],
                            ],
                        ],
                    ]
                ]
            ]
        ];
    }
}

Step 5: Create an event file at the path as follows to save attribute data. 

{{magento_root}}/app/code/Vendor/Extension/etc/events.xml

And include the following piece of code

<?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_before">
        <observer name="custom_shipping_observet" instance="Vendor\Extension\Observer\Saveshippingdata" />
    </event>
</config>

Step 6: Create observer file at the following path to save attribute data

{{magento_root}}/app/code/Vendor/Observer/Saveshippingdata.php

Then add the below code

<?php
namespace Vendor\Extension\Observer;
 
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;
 
class Saveshippingdata implements ObserverInterface
{
    protected $request;
 
    public function __construct(
        RequestInterface $request
    )
    {
        $this->request = $request;
    }
 
    public function execute(Observer $observer)
    {
        $product = $observer->getEvent()->getDataObject();
        $post = $this->request->getPost();
        $post = $post['product'];

        if($post['shipping_fieldset']){
            $shippingdata =  json_encode($post['shipping_fieldset']);
            $product->setCustomShippingdata($shippingdata);
        }

    }
 
}

Output:

You can add multiple fields by clicking “Add Shipping Price”. 

Conclusion:

So this way, you can add dynamic fields in the product edit form in Magento 2. Utilize this capability to enhance your e-commerce store’s product management experience and gain a competitive edge in the market.

Happy Coding!

Click to rate this post!
[Total: 4 Average: 4]
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 Create a Shopify Draft Order in Shopify Remix Using GraphQL?

Shopify's Draft Orders feature is an essential tool for merchants, allowing them to create orders…

16 hours ago

How to Use CSS with Shopify Remix Vite?

CSS (Cascading Style Sheets) is essential in web development to create visually appealing and responsive…

2 days ago

Latest Hyvä Theme Trends to Elevate your Magento UI/UX

Your eCommerce website theme is highly important for your business's online success as it reflects…

2 days ago

Use Hyvä Products at their Full Potential

Hyvä represents more than just a theme; it is a comprehensive suite of extensions and…

3 days ago

Magento 2: Add Number of Products Displayed Per Page in Invoice PDF

Hello Magento mates, Invoices are critical documents in every eCommerce business, providing details of product…

4 days ago

Magento 2: How to Call phtml Based on Selection of Payment Method at Multishipping Payment

Hello Magento Friends, Multishipping in Magento 2 allows customers to split their orders into multiple…

7 days ago