How to add new fields in address form

Magento 2 stores might need different information from customers that the existing fields in Magento default forms do not support. Luckily, in default checkout forms of Magento 2, you are given the power to add new fields such as shipping address and billing address forms. In today’s post, I’m going to show you five simple steps on how to add a new field in the address form.

Steps to add new fields in an address form in Magento 2:

Step 1: Add field to layout

As both shipping address and billing address forms are created dynamically, to customize their layouts, you need to create a plugin for the method \Magento\Checkout\Block\Checkout\LayoutProcessor::process and then declare it in the di.xml file which is in your module.

Here is a sample code for adding a Custom Attribute field to the shipping address form:

<?php
$customAttributeCode = 'custom_field';
$customField = [
    'component' => 'Magento_Ui/js/form/element/abstract',
    'config' => [
        // 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',
        'tooltip' => [
            'description' => 'this is what the field is for',
        ],
    ],
    'dataScope' => 'shippingAddress.custom_attributes' . '.' . $customAttributeCode,
    'label' => 'Custom Attribute',
    'provider' => 'checkoutProvider',
    'sortOrder' => 0,
    'validation' => [
       'required-entry' => true
    ],
    'options' => [],
    'filterBy' => null,
    'customEntry' => null,
    'visible' => true,
];

$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] = $customField;

In this example, the field is added to the customAttributes property of Magento_Checkout/js/model/new-customer-address.js, which is a JavaScript object listing all predefined address attributes and matching the corresponding server-side interface \Magento\Quote\Api\Data\AddressInterface.

The customAttributes property is related to the method \Magento\Quote\Model\Quote\Address\CustomAttributeListInterface::getAttributes. Besides, it was designed to hold custom EAV address attributes. The sample code that I have just provided above will help you handle storage persistence on the frontend automatically.

However, instead of adding a plugin, there is another way which is using a dependency injection also known as DI. In order to use a DI, you need to add the LayoutProcessor, that adds the custom field to the address form class, to directory <your_module_dir>/Block/Checkout/. The \Magento\Checkout\Block\Checkout\LayoutProcessorInterface interface must be implemented by the class. The code sample can be used as an example of the method implementation \Magento\Checkout\Block\Checkout\LayoutProcessorInterface::process().

For the LayoutProcessor class to be added to the corresponding pool of processors, you need to specify the following code (in here, you need to replace %unique_name% and %path\to\your\LayoutProcessor% by your real value) in the <your_module_dir>/etc/frontend/di.xml file:

<type name="Magento\Checkout\Block\Onepage">
        <arguments>
            <argument name="layoutProcessors" xsi:type="array">
                <item name="%unique_name%" xsi:type="object">%path\to\your\LayoutProcessor%</item>
            </argument>
        </arguments>
</type>

Step 2: Add JS mixin to modify data submission

To change the component responsible’s behavior for the data submission, add a JS mixin to the server side.

First of all, in your custom module, you need to define a mixin as a separate AMD module which returns a callback function. The mixin file can be added anywhere as long as it is in the <your_module_dir>/view/frontend/web directory. You can also freely name the file as you want.

Below is a sample mixin code which modify the Magento_Checkout/js/action/set-shipping-information’s behavior. The component is responsible for data submission between two steps shipping and billing:

/*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'] = {};
            }

            shippingAddress['extension_attributes']['custom_field'] = shippingAddress.customAttributes['custom_field'];
            // pass execution to original action ('Magento_Checkout/js/action/set-shipping-information')
            return originalAction();
        });
    };
});

When the field is added to the billing address form, the Magento_Checkout/js/action/place-order or Magento_Checkout/js/action/set-payment-information component’s behaviour need to be modified according to the time when you need the custom field valued to be passed to the server side.

If you want to view an example of a mixing which modifies a components, view the place-order-mixin.js which is in the Magento_CheckoutAgreements module.

Step 3: Load mixin

By adding the requirejs-config.js to the <YourModule_dir>/view/frontend/ directory, you will be able to tell Magento to load your mixin for the corresponding JS component.

Below is an example which use the sample mixin which is added earlier:

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/action/set-shipping-information': {
                '<YourNamespace_YourModule>/js/action/set-shipping-information-mixin': true
            }
        }
    }
};

Step 4: Add field to address model

In this stage, you would need to add the extension_attributes.xml file in the <YourModule_dir>/etc/ directory in order to add field to the address model which is on the server side.

Following is an extension_attributes.xml file’s example:

<?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_field" type="string" />
    </extension_attributes>
</config>

Remember to clear the var/generation directory when the setup:di:compile command is run. You will be able to add new getter and setter methods in the file /var/generation/Magento/Quote/Api/Data/AddressInterface.php.

Step 5: Access custom field’s value on server side

Once you have finished all the steps which are mentioned in the previous sections, the interface which includes your custom attribute will be generated, and you will be able to access your field value.

These attributes values can also be set or get when you create an instance of the Magento/Quote/Api/Data/AddressInterface.php interface.

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$addressInformation = $objectManager->create('Magento\Checkout\Api\Data\ShippingInformationInterface');
$extAttributes = $addressInformation->getExtensionAttributes();
$selectedShipping = $extAttributes->getCustomShippingCharge(); //get custom attribute data.

Conclusion

Above is five steps which can help you to add new fields in address form. I hope this tutorial will be helpful for you when managing the address form. If you have any questions or new ideas, feel free to leave a comment below.

Custom fields with One step checkout!

Custom Checkout fields!

Enjoyed the tutorial? Spread it to your friends!