How to Add Dynamic Field in Magento 2 Admin Using system.xml
This post offers a programmatic solution to add a dynamic field in Magento 2 admin using system.xml file.
With the increasing use of E-commerce and business requirements that follows, a store owner may want to set dynamic values of a field based on certain conditions.
For example, the value of the order amount can change dynamically at an instance of time for different customer groups.
To configure such fields in Magento 2 admin panel, follow the below steps:
Solution to Add a Dynamic Field in Magento 2 Admin Using system.xml file:
Here, I have added Order Amount as a dynamic product.
If a merchant wishes to set the threshold based on the customer group, a merchant can easily set up using the Order Amount dynamic field.
Create registration.php file at app\code\Vendor\Module directory
1 2 3 4 5 |
<?php use \Magento\Framework\Component\ComponentRegistrar; ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Vendor_Module', __DIR__); |
Create module.xml file at app\code\Vendor\Module\etc directory
1 2 3 4 5 |
<?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="Vendor_Module" setup_version="1.0.0"/> </config> |
Create system.xml file at app\code\Vendor\Module\etc\adminhtml directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> <system> <tab id="extension_name" translate="label" class="extension_name" sortOrder="100"> <label></label> </tab> <section id="section_id" translate="label" type="text" sortOrder="320" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Example</label> <tab>extension_name</tab> <resource>Vendor_Module::module_name</resource> <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Configuration</label> <field id="enable" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0"> <label>Order Amount for Customer Group</label> <source_model>Magento\Config\Model\Config\Source\Enabledisable</source_model> </field> <field id="dynamic_field" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Order Amount</label> <backend_model>Vendor\Module\Block\Adminhtml\Config\Backend\ArraySerialized</backend_model> <frontend_model>Vendor\Module\Block\Adminhtml\DynamicField</frontend_model> </field> </group> </section> </system> </config> |
Create ArraySerialized.php file at app\code\Vendor\Module\Block\Adminhtml\Config\Backend directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php namespace Vendor\Module\Block\Adminhtml\Config\Backend; use Magento\Framework\App\Cache\TypeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Config\Value as ConfigValue; use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Model\Context; use Magento\Framework\Model\ResourceModel\AbstractResource; use Magento\Framework\Registry; use Magento\Framework\Serialize\SerializerInterface; class ArraySerialized extends ConfigValue { protected $serializer; public function __construct( SerializerInterface $serializer, Context $context, Registry $registry, ScopeConfigInterface $config, TypeListInterface $cacheTypeList, AbstractResource $resource = null, AbstractDb $resourceCollection = null, array $data = [] ) { $this->serializer = $serializer; parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); } public function beforeSave() { $value = $this->getValue(); unset($value['__empty']); $encodedValue = $this->serializer->serialize($value); $this->setValue($encodedValue); } protected function _afterLoad() { $value = $this->getValue(); if ($value) { $decodedValue = $this->serializer->unserialize($value); $this->setValue($decodedValue); } } } |
Create DynamicField.php file at app\code\Vendor\Module\Block\Adminhtml directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?php namespace Vendor\Module\Block\Adminhtml; use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray; use Magento\Framework\DataObject; use Vendor\Module\Block\Adminhtml\Form\Field\CustomColumn; class DynamicField extends AbstractFieldArray { private $dropdownRenderer; protected function _prepareToRender() { $this->addColumn( 'attribute_name', [ 'label' => __('Customer Group'), 'renderer' => $this->getDropdownRenderer(), ] ); $this->addColumn( 'dropdown_field', [ 'label' => __('Purchaseover'), 'class' => 'required-entry', ] ); $this->_addAfter = false; $this->_addButtonLabel = __('Add'); } protected function _prepareArrayRow(DataObject $row) { $options = []; $dropdownField = $row->getDropdownField(); if ($dropdownField !== null) { $options['option_' . $this->getDropdownRenderer()->calcOptionHash($dropdownField)] = 'selected="selected"'; } $row->setData('attributes', $options); } private function getDropdownRenderer() { if (!$this->dropdownRenderer) { $this->dropdownRenderer = $this->getLayout()->createBlock( CustomColumn::class, '', ['data' => ['is_render_to_js_template' => true]]); } return $this->dropdownRenderer; } } |
Create CustomColumn.php file at app\code\Vendor\Module\Block\Adminhtml\Form\Field directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php namespace Vendor\Module\Block\Adminhtml\Form\Field; use Magento\Framework\View\Element\Html\Select; use Magento\Customer\Model\ResourceModel\Group\Collection; use Magento\Backend\Block\Template\Context; use Magento\Customer\Model\Customer\Attribute\Source\GroupSourceLoggedInOnlyInterface; use Magento\Framework\App\ObjectManager; class CustomColumn extends Select { protected $groupdata; public function __construct(Context $context, GroupSourceLoggedInOnlyInterface $groupdata = null, array $data = []) { $this->groupdata = $groupdata ?: ObjectManager::getInstance()->get(GroupSourceLoggedInOnlyInterface::class); parent::__construct($context, $data); } public function setInputName($value) { return $this->setName($value); } public function setInputId($value) { return $this->setId($value); } public function _toHtml() { if (!$this->getOptions()) { $this->setOptions($this->getSourceOptions()); } return parent::_toHtml(); } private function getSourceOptions() { $customerGroups = $this->groupdata->toOptionArray(); return $customerGroups; } } |
These are the six steps you need to implement to add a dynamic field in Magento 2 admin using system.xml. You can also implement field dependency from different groups in Magento 2 system.xml.
If you have questions regarding this blog, feel free to ask in the Comment section below.
I would be happy to answer your query.
Help someone by sharing this post to Magento Community via social media.
Thank you.
Sanjay Jethva
Sanjay is the co-founder and CTO of Meetanshi with hands-on expertise with Magento since 2011. He specializes in complex development, integrations, extensions, and customizations. Sanjay is one the top 50 contributor to the Magento community and is recognized by Adobe.
His passion for Magento 2 and Shopify solutions has made him a trusted source for businesses seeking to optimize their online stores. He loves sharing technical solutions related to Magento 2 & Shopify.
10 Comments
How can we retrieve dynamic fields value in fronend model files?
Hey Divyaraj,
You can get that value from core config table,
you may try to unserialise (json decode) value and check that data.
Thank You!
If I want some other attribute in place of consumer group display in drop-down what changes do I have to make?
Hello,
You can change the attribute from app\code\Vendor\Module\Block\Adminhtml\DynamicField.php file where you need to set the appropriate fields under _prepareToRender function.
Thank You
HI
We have followed the same steps but form not saving.
In console we are facing
Uncaught ReferenceError: option_extra_attrs is not defined
Hello Mounika,
The above code is properly working from our end.
Regarding your error, have you used any extra_attrs field in your code?
Thank You.
Hi, How can one add an input to upload images as part of the dynamic fields. (So the user can upload an image per row)
Hello,
I will post the solution in the future.
Do subscribe to Meetanshi’s blog posts to get notified for the same.
Thank You
My admin interface is not responding anymore when I added this to my module. Eg. catelog section does not fold out any more.
Hello,
Please check the error log as the above code is working perfectly for us.
Thanks