3
<fieldset name="product-details">
    <field name="sku">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="notice" xsi:type="string" translate="true" after="product-details.sku">Some note here</item>
            </item>
        </argument>
    </field>
</fieldset>

I have tried this, which should just add notice below existing input, but it is adding new (duplicated) SKU field and displaying notice with that. So how can I override existing field/attribute?

2
  • What you want to do? Please specify clearly. This is confusing..! Nov 27, 2019 at 11:30
  • <item name="notice" in existing product form admin side, which will show "detailed info about field" on right side of input
    – Jinal
    Nov 27, 2019 at 11:31

1 Answer 1

9

The correct way to update the product form in your module (using xml):

app/code/Vendor/Module/view/adminhtml/ui_component/category_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="product-details">
        <container name="container_sku">
            <field name="sku" formElement="input">
                <settings>
                    <notice translate="true">Some note here</notice>
                    <label translate="true">SKU-SKU-SKU</label>
                </settings>
            </field>
        </container>
    </fieldset>
</form>

but it will no work, because the Magento use own modifiers to declare product form fields:

vendor/magento/module-catalog/Ui/DataProvider/Product/Form/ProductDataProvider.php

/**
 * {@inheritdoc}
 * @since 101.0.0
 */
public function getMeta()
{
    $meta = parent::getMeta();

    /** @var ModifierInterface $modifier */
    foreach ($this->pool->getModifiersInstances() as $modifier) {
        $meta = $modifier->modifyMeta($meta);
    }

    return $meta;
}

and meta-data returned by this method merged with .xml declaration with highest priority. It's mean that your data from xml will be overwriten by data with same keys from data provider in this method:

vendor/magento/framework/View/Element/UiComponentFactory.php

/**
 * Merge data provider's metadata to components
 *
 * @param string $identifier
 * @param array $bundleComponents
 * @param bool $reverseMerge
 * @return array
 * @since 100.1.0
 */
protected function mergeMetadata($identifier, array $bundleComponents, $reverseMerge = false)
{
    $dataProvider = $this->getDataProvider($identifier, $bundleComponents);
    if ($dataProvider instanceof DataProviderInterface) {
        $metadata = [
            $identifier => [
                'children' => $dataProvider->getMeta(),
            ],
        ];
        $bundleComponents = $this->mergeMetadataItem($bundleComponents, $metadata, $reverseMerge);
    }

    return $bundleComponents;
}

as a result your component settings declared by same path in xml will be overwritten by empty\null\default values in case it exists in the base Magento declaration.

To get around that problem we need to add own modifier to the product form modifiers pool and update base declaration inside:

Add module sequence:

app/code/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="Vendor_Module" setup_version="0.0.1">
        <sequence>
            <module name="Magento_Catalog"/>
            <module name="Magento_Ui"/>
        </sequence>
    </module>
</config>

Add own modifier to pool:

app/code/Vendor/Module/etc/adminhtml/di.xml

<?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="custom_sku_modifier" xsi:type="array">
                    <item name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Product\Form\Modifier\Sku</item>
                    <item name="sortOrder" xsi:type="number">200</item>
                </item>
            </argument>
        </arguments>
    </virtualType>
</config>

Add modifier class:

app/code/Vendor/Module/Ui/DataProvider/Product/Form/Modifier/Sku.php

<?php
namespace Vendor\Module\Ui\DataProvider\Product\Form\Modifier;

/**
 * Class Sku
 */
class Sku extends \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier
{

    /**
     * @param array $data
     * @return array
     * @since 100.1.0
     */
    public function modifyData(array $data)
    {
        return $data;
    }

    /**
     * @param array $meta
     * @return array
     * @since 100.1.0
     */
    public function modifyMeta(array $meta)
    {
        if (isset($meta['product-details']['children']['container_sku']['children']['sku']
            ['arguments']['data']['config'])
        ) {
            $skuConfig = &$meta['product-details']['children']['container_sku']['children']
            ['sku']['arguments']['data']['config'];
            $skuConfig['notice'] = __('Some note here');
        }

        return $meta;
    }
}

Here is result in admin form:

result example

2
  • its works for me! Nov 27, 2019 at 14:13
  • 1
    The key part here is setting the sortOrder high enough on your modifier to be above the Magento default modifiers. This is mentioned here but not in other tutorials. Thank you! Apr 8, 2021 at 20:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.