I'm trying to add a custom attribute in Customer Address in Magento 2.3.1 with Wamp (PHP 7.2.25).
I created a custom attribute and additional columns in quote, sales_order_address
and quote_address
:
private function createAttribute($code,$desc,$sortOrder)
{
$this->eavSetup->addAttribute(
AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
$code,
[
'label' => $desc,
'type' => 'varchar',
'input' => 'text',
'visible' => true,
'required' => false,
'position' => $sortOrder,
'sort_order' => $sortOrder,
'system' => false
]
);
$attribute = $this->eavConfig->getAttribute(
AddressMetadataInterface::ENTITY_TYPE_ADDRESS,
$code
);
$attribute->setData(
'used_in_forms',
[ 'adminhtml_customer_address',
'adminhtml_customer',
'customer_address_edit',
'customer_register_address',
'customer_address']
);
$attribute->save();
}
private function addTableColumn($tableName,$fieldCode,$length,$fieldDesc)
{
$this->setup->getConnection()->addColumn(
$this->setup->getTable($tableName),
$fieldCode,
[
'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
'length' => $length,
'nullable' => true,
//'default' => '',
'comment' => $fieldDesc
]
);
}
I created layout plugin with /etc/frontend/di.xml --> "Magento\Checkout\Block\Checkout\LayoutProcessor"
:
private function buildJsLayout($customAttributeCode,$customAttributeId,$customAttributeDescription,$sortOrder,$scope,$length)
{
$this->logger->debug('Hrm_OrderCustomization - LayoutProcessorPlugin - buildJsLayout - ' . $customAttributeCode);
$this->jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] =
[
'component' => 'Magento_Ui/js/form/element/abstract',
'config' => [
'customScope' => $scope,
'template' => 'ui/form/field',
'elementTmpl' => 'ui/form/element/input',
'additionalClasses' => ' col-mp mp-6',
'options' => [],
'id' => $customAttributeId
],
'dataScope' => $scope . '.' . $customAttributeCode,
'label' => $customAttributeDescription,
'provider' => 'checkoutProvider',
'sortOrder' => $sortOrder,
'validation' => ['max_text_length' => $length,'min_text_length' => $length],
'visible' => true,
'value' => '',
'id' => $customAttributeId
];
}
extension_attribute
:
<?xml version="1.0"?>
<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="custom_attribute" type="string" />
</extension_attributes>
</config>
I handled the js:
- create-shipping-address --> create-shipping-address-mixin
- set-shipping-information --> set-shipping-information-mixin
- create-billing-address --> set-billing-address-mixin
- place-order --> set-billing-address-mixin
and i added observe event, /etc/events.xml --> "sales_model_service_quote_submit_before", and AddressManagementPlugins, /etc/di.xml --> "Magento\Checkout\Model\ShippingInformationManagement", "Magento\Quote\Model\BillingAddressManagement", "Magento\Quote\Model\Quote\Address\BillingAddressPersister".
I also added the attribute in the admin (and customer account page) like this:
<type name="Magento\Customer\Block\Address\Edit">
<plugin name="customer-edit-plugin" type="Hrm\OrderCustomization\Plugin\Magento\Customer\AddressEditPlugin" sortOrder="10"/>
</type>
public function afterGetNameBlockHtml(
\Magento\Customer\Block\Address\Edit $edit,
$result
) {
$block = $this->layout->createBlock(
'Vendor\Module\Block\Customer\Address\Form\Edit\CustomTemplate',
'vendor_order_customization'
);
return $result . $block->toHtml();
}
CustomTemplate
:
protected function _toHtml()
{
$customWidgetBlock = $this->getLayout()->createBlock(
'Vendor\Module\Block\Customer\Widget\CustomWidget'
);
$customWidgetBlock->setAddress($this->address);
return $customWidgetBlock->toHtml();
}
widget has all get methods (getId, vatLabelDesc ecc...) and getValue():
protected function _construct()
{
parent::_construct();
$this->setTemplate('widget/customerAddress.phtml');
}
public function getValue()
{
$address = $this->getAddress();
if($address instanceOf AddressInterface)
{
$attr = $address->getCustomAttribute('custom_attribute')
? $address->getCustomAttribute('custom_attribute')->getValue()
: null;
return $attr;
}
return null;
}
and the phtml
:
<div class="field custom_attribute<?php if ($block->isRequired()) echo 'required'; ?>">
<label class="label" for="<?php echo $block->escapeHtml($block->getId()); ?>">
<span><?php echo $block->escapeHtml($block->getLabel()); ?></span>
</label>
<div class="control">
<input type="text"
id="<?php echo $block->escapeHtml($block->getId()); ?>"
name="<?php echo $block->escapeHtml($block->getName()); ?>"
value="<?php echo $block->escapeHtml($block->getValue()); ?>"
title="<?php echo $block->escapeHtml($block->getLabel()); ?>"
class="input-text"
<?php /** @escapeNotVerified */ echo $block->getParams() ?>
<?php if ($block->isRequired()) echo ' data-validate="{required:true}"' ?> />
</div>
</div>
and finally i modified the HTML Address Templates in Admin Store --> configuration --> CustomerCustomization, adding:
{{depend custom_attribute}}Attribute: {{var custom_attribute}}{{/depend}}
well... with this code, the field is saved in table sales_order_address and I can see the value in order details, I can change the value from Admin-Customer or Customer-AddressBook and the new value is loaded correctly on the checkout page, but I have 2 problems:
- if I add a new address in checkout page (or I edit an existing one from the checkout), the custom_attribute value is not saved in CustomerAddress but only in that specific order
- if the customer has not any address, in checkout page the custom_attribute value doesn't exist in quote.shippingAddress.customAttribute (js mixin) and it cannot be saved even in the DB table
Instead trying to add the property 'user_defined' => true
to the attribute I can save the value in sales_order_address from the checkout page, even if it's a new address BUT... in Admin CustomerAddress I can't save any value and I can't see the value in Order details anymore.
Sorry for the length of this Question and I hope I have explained myself well, Thanks