I'm trying to define a new customer address attribute that will be available in all the customer address forms (backend, frontend, checkout). I've used the information provided here:
https://devdocs.magento.com/guides/v2.2/howdoi/checkout/checkout_new_field.html
I've also read and tried to apply a lot of posts and articles I found in sources like Stack Exchange and in other websites found via Google. So far I've managed to get the attribute in all forms, but the value is only saved to the database in the admin address form; in the frontend address forms (customer section and checkout section) the attribute value is simply ignored. All the posts, articles and answers I've checked haven't helped. Could anyone please tell me if I'm missing something?
Here are all the relevant code snippets:
1.- Install script:
class InstallData implements InstallDataInterface
{
public function install(
ModuleDataSetupInterface $setup,
ModuleContextInterface $context
) {
$customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
$customerSetup->addAttribute('customer_address', 'address_email', array(
'type' => 'varchar',
'input' => 'text',
'label' => 'Address E-mail',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 1,
'system'=> 0,
'group'=> 'General',
'visible_on_front' => 1,
));
$customerSetup->getEavConfig()->getAttribute('customer_address', 'address_email')
->setUsedInForms(array('adminhtml_customer_address', 'customer_address_edit', 'customer_register_address', 'customer_address'))
->save();
}
}
2.- di.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Rokanthemes\OpCheckout\Block\Checkout\LayoutProcessor">
<plugin name="changeAddressFields" type="Vendor\AddressCustomization\Plugin\Block\Checkout\LayoutProcessor" sortOrder="100" disabled="false"/>
</type>
<type name="Magento\Framework\Api\DataObjectHelper">
<plugin name="move-extension-attributes" type="Vendor\AddressCustomization\Plugin\Api\DataObjectHelper" sortOrder="20"/>
</type>
<type name="Magento\Sales\Block\Adminhtml\Order\View\Info">
<plugin name="render-address-email" type="Vendor\AddressCustomization\Plugin\Block\Adminhtml\Order\View\Info" sortOrder="20"/>
</type>
3.- Plugins
namespace Vendor\AddressCustomization\Plugin\Api;
class DataObjectHelper
{
public function beforePopulateWithArray($helper, $dataObject, array $data, $interfaceName)
{
switch ($interfaceName) {
case 'Magento\Sales\Api\Data\OrderAddressInterface':
if (isset($data['extension_attributes']) && ($data['extension_attributes'] instanceof \Magento\Quote\Api\Data\AddressExtensionInterface)) {
$data['extension_attributes'] = $data['extension_attributes']->__toArray();
}
break;
case 'Magento\Customer\Api\Data\AddressInterface':
if (isset($data['extension_attributes']) && ($data['extension_attributes'] instanceof \Magento\Quote\Api\Data\AddressExtensionInterface)) {
$data['extension_attributes'] = $data['extension_attributes']->__toArray();
if (isset($data['extension_attributes']['address_email'])){
$data['address_email'] = $data['extension_attributes']['address_email'];
}
if (isset($data['extension_attributes']['is_company'])){
$data['is_company'] = $data['extension_attributes']['is_company'];
}
}
break;
case 'Magento\Quote\Api\Data\TotalsInterface':
unset($data['extension_attributes']);
break;
}
return array($dataObject, $data, $interfaceName);
}
}
–
namespace Vendor\AddressCustomization\Plugin\Block\Adminhtml\Order\View;
class Info
{
public function beforeGetFormattedAddress($block, $address)
{
if ($attributes = $address->getExtensionAttributes()) {
$address->setAddressEmail($attributes->getAddressEmail());
}
return array($address);
}
}
–
namespace Vendor\AddressCustomization\Plugin\Block\Checkout;
class LayoutProcessor
{
....
public function afterProcess(
\Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
array $jsLayout
)
{
....
$customAttributes = array(
'address_email' => array(
'component' => 'Magento_Ui/js/form/element/abstract',
'config' => [
'additionalClasses' => 'one-field',
'placeholder' => 'Shipping destination e-mail',
// customScope is used to group elements within a single form (e.g. they can be validated separately)
'customScope' => 'shippingAddress.custom_attributes',
'customEntry' => null,
'template' => 'ui/form/field',
'elementTmpl' => 'ui/form/element/input',
],
'dataScope' => 'shippingAddress.custom_attributes.address_email',
'label' => __('Destination E-mail'),
'provider' => 'checkoutProvider',
'sortOrder' => 1000,
'validation' => [
'required-entry' => false
],
'options' => [],
'filterBy' => null,
'customEntry' => null,
'visible' => false,
),
);
foreach ($customAttributes as $customAttributeCode => $customField) {
$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] = $customField;
}
}
}
4.- Javascript mixins
file app/code/Vendor/AddressCustomization/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
'Magento_Checkout/js/action/set-shipping-information': {
'Vendor_AddressCustomization/js/action/set-shipping-information-mixin': true
},
}
}
};
–
file app/code/Vendor/AddressCustomization/view/frontend/web/js/action/set-shipping-information-mixin.js
/*jshint browser:true jquery:true*/
/*global alert*/
define([
'jquery',
'mage/utils/wrapper',
'Magento_Checkout/js/model/quote'
], function ($, wrapper, quote) {
'use strict';
return function (setShippingInformationAction) {
return wrapper.wrap(setShippingInformationAction, function (originalAction) {
var shippingAddress = quote.shippingAddress();
if (shippingAddress['extension_attributes'] === undefined) {
shippingAddress['extension_attributes'] = {};
}
if (shippingAddress.customAttributes === undefined) {
shippingAddress.customAttributes = {};
}
if (shippingAddress.customAttributes['address_email'] instanceof Object) {
shippingAddress.customAttributes['address_email'] = shippingAddress.customAttributes['address_email'].value;
}
shippingAddress['extension_attributes']['address_email'] = shippingAddress.customAttributes['address_email'];
// pass execution to original action ('Magento_Checkout/js/action/set-shipping-information')
return originalAction();
});
};
});
5.- Extension attributes
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
<extension_attributes for="Magento\Quote\Api\Data\AddressInterface">
<attribute code="address_email" type="string" />
</extension_attributes>
<extension_attributes for="Magento\Sales\Api\Data\OrderAddressInterface">
<attribute code="address_email" type="string"/>
</extension_attributes>
<extension_attributes for="Magento\Customer\Api\Data\AddressInterface">
<attribute code="address_email" type="string"/>
</extension_attributes>
</config>
Best Answer
Please check below code to save custom address attribute in customer,checkout shipping and billing form and also save in order table.
Module Name : Ccc_Checkout
Script to create custom attribute for address and order
app/code/Ccc/Checkout/Setup/UpgradeData.php
app/code/Ccc/Checkout/etc/di.xml
app/code/Ccc/Checkout/etc/events.xml
app/code/Ccc/Checkout/etc/extension_attributes.xml
Create Plugin to display custom attribute in checkout billing and shipping form
app/code/Ccc/Checkout/Plugin/Block/Checkout/LayoutProcessor
To save custom attribute in checkout
app/code/Ccc/Checkout/Plugin/Magento/Quote/Model/ShippingAddressManagement
app/code/Ccc/Checkout/Plugin/Magento/Quote/Model/BillingAddressManagement
app/code/Ccc/Checkout/Ccc/Checkout/Plugin/Magento/Quote/Model/Quote/Address
To set custom attribute in extension attribute
app/code/Ccc/Checkout/view/frontend/requirejs-config.js
app/code/Ccc/Checkout/view/frontend/web/js/action/create-shipping-address-mixin.js
app/code/Ccc/Checkout/view/frontend/web/js/action/set-billing-address-mixin.js
app/code/Ccc/Checkout/view/frontend/web/js/action/set-shipping-information-mixin.js
To save custom attribute in orders
app/code/Ccc/Checkout/Observer/SaveUnitNumberInOrder.php
To display custom attribute in customer account you need to overright customer edit.phtml file from vendor to your theme like below :
app/design/frontend/custom_theme/theme_name/Magento_Customer/templates/address/edit.phtml