Assuming that you already understand how to save a custom field value to a database, the next step in order to provide a complete saving/loading solution to any custom field, without creating product attributes, is to develop a mechanism for reading the value from the database and displaying it to our custom form field every time the product form is being loaded.
In Magento we can develop our own data provider that will help us modify the product form; for this, we need to add new arguments to the Magento’s modifier pool in the /etc/adminhtml/di.xml file as follows:
<virtualTypename=”Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Pool“>
<arguments>
<argument name=”modifiers” xsi:type=”array”>
<item name=”advancedCustomOptions” xsi:type=”array”>
<item name=”class” xsi:type=”string”>Module\Vendor\Ui\DataProvider\ProductForm</item>
<item name=”sortOrder” xsi:type=”number”>20</item>
</item>
</argument>
</arguments>
</virtualType>
And inside the AstralWeb\DirectCheckout\Ui\DataProvider file, we need to create our data provider, in this case, the data provider will be called ProductForm:
<?php
namespace Module\Vendor\Ui\DataProvider;
use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier;
use Magento\Catalog\Model\Locator\LocatorInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Exception\NoSuchEntityException;
class ProductForm extends AbstractModifier
{
protected $locator;
protected $request;
public function __construct(
LocatorInterface $locator,
RequestInterface $request)
{
$this->locator = $locator;
$this->request = $request;
}
/**
* {@inheritdoc}
*/
// This function modifies the form fields before being rendered.
public function modifyMeta(array $meta)
{
return $meta;
}
/**
* {@inheritdoc}
*/
// This function requires to be imported but we don’t need it.
public function modifyData(array $data)
{
return $data;
}
}
After declaring our data provider we will be able not only to inject our custom value into the form but also help in conditionally displaying the field according to the data being read from the database.
Conditional rendering
Some merchants would require us to display the custom field for only some specific products, let’s say that we only want to show the custom field when opening any configurable product form only, so it means that for any other non-configurable product form the field will not be displayed.
For defining the above behavior we can add the following lines to the modifyMeta function in order to override the arguments for the amounts container:
public function modifyMeta(array $meta)
{
$product = $this->locator->getProduct();
if ($productType != “configurable”)
{
$meta[“amounts”] = [
“arguments” => [
“data” => [
“config” => [
“collapsible” => false,
‘opened’ => false,
‘canShow’ => false,
‘visible’ => false
]
]
]
];
}
Please take note of the index amounts, previously declared when extending the product form:
<argument name=”data” xsi:type=”array”>
<item name=”config” xsi:type=”array”>
<item name=”label” xsi:type=”string”>
Min. Amount of Products
</item>
<item name=”collapsible” xsi:type=”boolean”>true</item>
<item name=”dataScope” xsi:type=”string”>data.amounts</item>
<item name=”sortOrder” xsi:type=”number”>10</item>
</item>
</argument>
In the data provider, we are overriding the display characteristics for the whole container when the product’s type is not configurable. When opening a non-configurable product form, the whole field container in this case will not be displayed, just like it is shown below after overriding the container properties.
Injecting the custom value
In the same way, we override the whole container display for any non-configurable product, we can also do the same for any element inside the container when we need to inject a custom value into the product form; we just need to go down one to the children index and override the field we need to, in this case, the qty field, so, following the same example, we can add an else statement as follow:
public function modifyMeta(array $meta)
{
$product = $this->locator->getProduct();
if ($productType != “configurable”)
{
…
}else{
// Any logic for loading the qty value from database goes here
// $qty = …
$meta[“amounts”] = [
“arguments” => [
“data” => [
“config” => [
“sortOrder” => 1,
]
]
],
‘children’ => [
‘qty’ => [
‘arguments’ => [
‘data’ => [
‘config’ => [
‘value’ => (string)$qty
]
]
]
]
]
];
}
return $meta;
}
In the above example, we are just overriding the value sample, in this way the value we get from the database will be displayed in the product form.
This will finally finish the most basic saving/loading flow for any custom field in the product form without creating product attributes. You are welcome to experiment with any other field types rather than text input, but for most of them, the steps are very similar, just being different in the elements needed to be overridden for a particular project.
In the next article, we will describe how to customize the style of any field from the product form, allowing us to make it distinctive from others.