Move Customer Extension Attribute to new tab
-
15-04-2021 - |
Question
I've successfully created several customer extension attributes that display on the customer form and save and load data.
When I try to move these fields to a new custom tab on the customer admin page, they break. The source models still load, but the data isn't populated or saved. I can see when I inspect that the form name changes from customer['my_attribute']
to my_tab[my_attribute]
.
I suspect I need to change my UpgradeData.php script to use a custom form, but I'm having trouble finding resources on how to go about this.
Relevant snippet from UpgradeData.php:
$exemptionTypeCode = 'my_exemption_type';
$eavSetup->addAttribute(
CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
$exemptionTypeCode,
[
'group' => 'General',
'type' => 'varchar',
'label' => 'Exemption Type',
'input' => 'select',
'required' => false,
'visible' => true,
'user_defined' => true,
'position' => 501,
'system' => 0,
'sort_order' => 50,
'default' => 'non_exempt',
'source' => 'Custom\Module\Model\Attribute\Source\CustomerExemptionType',
'backend' => 'Custom\Module\Model\Attribute\Backend\CustomerExemptionType',
'frontend' => 'Custom\Module\Model\Attribute\Frontend\CustomerExemptionType',
'global' => 'Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL',
'is_used_in_grid' => false,
'is_visible_in_grid' => false,
'is_filterable_in_grid' => false,
'is_html_allowed_on_front' => true,
'visible_on_front' => true
]
);
$eavSetup->addAttributeToSet(
CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
null,
$exemptionTypeCode);
$exemptionType = $this->eavConfig->getAttribute(
CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
$exemptionTypeCode);
$exemptionType->setData('used_in_forms', ['adminhtml_customer']);
$exemptionType->getResource()->save($exemptionType);
Snippet from customer_form.xml, changing fieldset name from 'customer' to 'my_tab' breaks the extension attributes.
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="customer">
<field name="my_exemption_type" formElement="select">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Exemption Type</item>
<item name="source" xsi:type="string">customer</item>
</item>
</argument>
<settings>
<visible>true</visible>
</settings>
</field>
</fieldset>
Any help with either moving attributes to different tabs, creating a new admin form, or a different approach I haven't considered are appreciated!
Solution
I know this post is old, but decided to add my findings of a working solution, after spending hours looking at this.
First off, I had to try and understand the concepts of Magento's UI components and find a simple way to achieve this, without writing additional classes and data models. Here is some good reading material if anyone is interested:
https://devdocs.magento.com/guides/v2.4/ui_comp_guide/concepts/ui_comp_data_source.html
The solution:
Programatically install the customer attributes. I wont go into detail for this since everyone has their on way of installing customer attributes and the install / update script in the original question should be sufficient. The only thing you would need to change is
'visible' => false,
so that the attribute does not show under the default "Account Information" tab.Add "view/adminhtml/ui_component/customer_form.xml" to your module with the following (obviously update the fieldset names and field name to whatever you require):
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> <fieldset name="rfm"> <settings> <collapsible>false</collapsible> <label translate="true">RFM Information</label> <componentType>fieldset</componentType> <dataScope>customer</dataScope> </settings> <fieldset name="rfm_group"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="label" xsi:type="string" translate="true">General Information</item> <item name="dataScope" xsi:type="string">customer</item> <item name="sortOrder" xsi:type="number">1</item> <item name="collapsible" xsi:type="boolean">true</item> <item name="opened" xsi:type="boolean">true</item> </item> </argument> <field name="rfm_recency" formElement="input"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="source" xsi:type="string">customer</item> </item> </argument> <settings> <label translate="true">Recency</label> <dataType>text</dataType> <visible>true</visible> <imports> <link name="value">${ $.provider }:data.customer.rfm_recency</link> </imports> <exports> <link name="value">${ $.provider }:data.customer.rfm_recency</link> </exports> </settings> </field> </fieldset> </fieldset>
You will notice i have a nested fieldset with a single input field, where the input field name would be composed like rfm[rfm_group][rfm_recency]
. In order to compose the field name like customer[rfm_recency]
, we need to set a <dataScope>
in each fieldset nodes and field nodes. You will see how I do this in my example above.
Next you will notice I have included imports and exports nodes under the field node.
- The imports node (read) is telling the Magento UI which data value I want to link to my attribute value.
- The exports node (write) is telling the Magento UI where I want to save my attribute value to.
Once you have implemented the customer_form.xml
, clear the caches and reload your customer edit page. You should see something similar to this:
You will just need to make sure that the attribute is not visible in the "Account information" tab and the value actually saves as expected.