Create a dynamic row system configuration
This tutorial shows you how to add a new dynamic rows system configuration in the Admin, by extending the Magento/Config/Block/System/Config/Form/Field/FieldArray/AbstractFieldArray class.
Step 1: Add a new system field
etc/adminhtml/system.xml
Copied to your clipboard<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"><system><section id="general" type="text"><group id="quantity_ranges" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"><label>Quantity Ranges</label><field id="ranges" translate="label" sortOrder="5" showInDefault="1" showInWebsite="1" showInStore="1"><label>Ranges</label><frontend_model>Vendor\Module\Block\Adminhtml\Form\Field\Ranges</frontend_model><backend_model>Magento\Config\Model\Config\Backend\Serialized\ArraySerialized</backend_model></field></group></section></system></config>
This code adds a new system configuration in STORES > Settings > Configuration > GENERAL > General > Quantity Ranges.
Step 2: Create the block class to describe custom field columns
File: app/code/Vendor/Module/Block/Adminhtml/Form/Field/Ranges.php
Copied to your clipboard<?phpnamespace Vendor\Module\Block\Adminhtml\Form\Field;use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray;use Magento\Framework\DataObject;use Magento\Framework\Exception\LocalizedException;use Vendor\Module\Block\Adminhtml\Form\Field\TaxColumn;/*** Class Ranges*/class Ranges extends AbstractFieldArray{/*** @var TaxColumn*/private $taxRenderer;/*** Prepare rendering the new field by adding all the needed columns*/protected function _prepareToRender(){$this->addColumn('from_qty', ['label' => __('From'), 'class' => 'required-entry']);$this->addColumn('to_qty', ['label' => __('To'), 'class' => 'required-entry']);$this->addColumn('price', ['label' => __('Price'), 'class' => 'required-entry']);$this->addColumn('tax', ['label' => __('Tax'),'renderer' => $this->getTaxRenderer()]);$this->_addAfter = false;$this->_addButtonLabel = __('Add');}/*** Prepare existing row data object** @param DataObject $row* @throws LocalizedException*/protected function _prepareArrayRow(DataObject $row): void{$options = [];$tax = $row->getTax();if ($tax !== null) {$options['option_' . $this->getTaxRenderer()->calcOptionHash($tax)] = 'selected="selected"';}$row->setData('option_extra_attrs', $options);}/*** @return TaxColumn* @throws LocalizedException*/private function getTaxRenderer(){if (!$this->taxRenderer) {$this->taxRenderer = $this->getLayout()->createBlock(TaxColumn::class,'',['data' => ['is_render_to_js_template' => true]]);}return $this->taxRenderer;}}
This block prepares the desired columns for inclusion in the new configuration.
Step 3: Create the block class to describe a column with drop-down input
File: app/code/Vendor/Module/Block/Adminhtml/Form/Field/TaxColumn.php
Copied to your clipboard<?phpdeclare(strict_types=1);namespace Vendor\Module\Block\Adminhtml\Form\Field;use Magento\Framework\View\Element\Html\Select;class TaxColumn extends Select{/*** Set "name" for <select> element** @param string $value* @return $this*/public function setInputName($value){return $this->setName($value);}/*** Set "id" for <select> element** @param $value* @return $this*/public function setInputId($value){return $this->setId($value);}/*** Render block HTML** @return string*/public function _toHtml(): string{if (!$this->getOptions()) {$this->setOptions($this->getSourceOptions());}return parent::_toHtml();}private function getSourceOptions(): array{return [['label' => 'Yes', 'value' => '1'],['label' => 'No', 'value' => '0'],];}}
This block sets values for the drop-down option.
Step 4: Set default values - OPTIONAL
It is possible to set defaults for a dynamic row configuration, this is done by adding additional XML to the defaults block in the config.xml
file for the module.
Add a block to the <default>
section of the config.xml
file and do not include any values:
Copied to your clipboard<general><quantity_ranges><ranges></ranges></quantity_ranges></general>
For each complete line of configuration, create an XML block with a repeating node that has a different value to all the others and contains XML tags for each sub-option and value.
For example, you can use <item1>, <item2>
.
The sub-options are the columns defined in the _prepareToRender()
method as described in Step 2.
In the following excerpt, a single row for item1
contains 4 sub-options:
Copied to your clipboard<item1><from_qty>5</from_qty><to_qty>6</to_qty><price>10.00</price><tax>1</tax></item1>
Continue building the default block by adding 3 items to the ranges
configuration option in the config.xml
file:
Copied to your clipboard<general><quantity_ranges><ranges><item1><from_qty>1</from_qty><to_qty>5</to_qty><price>10.00</price><tax>1</tax></item1><item2><from_qty>6</from_qty><to_qty>10</to_qty><price>20.00</price><tax>1</tax></item2><item3><from_qty>11</from_qty><to_qty>15</to_qty><price>30.00</price><tax>0</tax></item3></ranges></quantity_ranges></general>
To verify the default values for the configuration are correct, do the following :
- Ensure that this configuration option has no entry in the database.
- Continue with Step 5
Step 5: Clean cache
Clean the cache with the following command:
Copied to your clipboardbin/magento cache:clean
and clean the config with this command:
Copied to your clipboardbin/magento cache:clean config
Result
The result is a new dynamic system row field in the Admin panel. If you have set optional default values, these should also appear.