How to custom shipping address template

In the previous article, I I have mentioned that the checkout of Magento includes two steps which are Shipping Information and Review and Payment Information.

On the Shipping Information checkout step, all addresses can be previously saved by a shopper. Then that shopper can select one which will be used for shipping just by clicking on that address. Although the default address renderers cover most of the use cases, Magento still allows you to register custom address renderer to create a new address type.

In today post, I will guide you on how to custom shipping address renderer on Magento 2.

Custom shipping address template

Step 1: Create JS renderer component

You should implement your shipping address renderer as a JavaScript UI component. It has to be a RequireJS module, and have to return a factory function, that takes a configurable object.

To ensure the compatibility, upgradability, and easy maintenance, please add your customizations in a separate module instead of the default Magento code. Besides, if you want your checkout customization to be applied correctly, your custom module has to depend on the Magento_Checkout module. The module’s composer.jso is the place where module dependencies are specified. And the Ui should not be used for your custom module name as %Vendor%_Ui notation is required when specifying paths, might lead to some issues.

In the directory of your custom module, generate the file component’s .js. This file must be located under the directory <your_module_dir>/view/frontend/web/js/view/.

Below is a shipping address renderer’s general view:

define([
    'ko',
    'uiComponent',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Checkout/js/model/quote'
], function(ko, Component, selectShippingAddressAction, quote) {
    'use strict';
    return Component.extend({
        defaults: {
            template: '%path to your template%'
        },

        initProperties: function () {
            this._super();
            this.isSelected = ko.computed(function() {
                var isSelected = false;
                var shippingAddress = quote.shippingAddress();
                if (shippingAddress) {
                    isSelected = shippingAddress.getKey() == this.address().getKey();
                }
                return isSelected;
            }, this);

            return this;
        },

        /** Set selected customer shipping address  */
        selectAddress: function() {
            selectShippingAddressAction(this.address());
        },

        /** additional logic required for this renderer  **/

    });
});

Step 2: Create template for shipping address renderer

In this step, you need to create a <your_module_dir>/view/frontend/web/template/<your_template>.html file in your custom module directory. You can use Knockout JS syntax for your template.

A button which is used for setting the address for shipping should be included in the template.

The code from the default template can be used: app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html.

Step 3: Create JS model for shipping rate processor

Retrieving the shipping rates which are available for the given shipping address is responsible by a shipping rate processor.

Create a component’s .js file for the processor in your custom module directory. This file have to be located under the directory <your_module_dir>/view/frontend/web/js/model/

In here, the URL which is used to calculate the shipping rates for your custom address type needs to be specified.

Down here is a shipping rate processor code’s sample:

define(
    [
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/model/shipping-service',
        'Magento_Checkout/js/model/shipping-rate-registry',
        'magento/storage',
        'Magento_Checkout/js/model/error-processor',
        // additional dependencies
    ],
    function (quote, shippingService, rateRegistry, storage, errorProcessor, ...) {
        'use strict';
        return {
            getRates: function(address) {
                var cache = rateRegistry.get(address.getKey());
                if (cache) {
                    shippingService.setShippingRates(cache);
                } else {
                    shippingService.isLoading(true);
                    storage.post(
                        %URL for shipping rate estimation%,
                        JSON.stringify({
                            %address parameters%
                        }),
                        false
                    ).done(
                        function (result) {
                            rateRegistry.set(address.getKey(), result);
                            shippingService.setShippingRates(result);
                        }
                    ).fail(
                        function (response) {
                            shippingService.setShippingRates([]);
                            errorProcessor.process(response);
                        }
                    ).always(
                        function () {
                            shippingService.isLoading(false);
                        }
                    );
                }
            }
        };
    }
);

Step 4: Create JS model for shipping address saving processor

This processor handles sending the shipping address and the selected rate to the server.

In this step, you need to create the component’s .js file for the processor in your custom module directory.

Here is a shipping rate processor code’s sample:

define(
    [
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/model/resource-url-manager',
        'mage/storage',
        'Magento_Checkout/js/model/payment-service',
        'Magento_Checkout/js/model/error-processor',
        'Magento_Checkout/js/model/payment/method-converter'
    ],
    function (quote, resourceUrlManager, storage, paymentService, errorProcessor, methodConverter) {
        'use strict';
        return {
            saveShippingInformation: function() {
                var shippingAddress = {},
                    payload;

                shippingAddress.extension_attributes = {
                    %address extension attributes%
                };

                payload = {
                    addressInformation: {
                        shipping_address: shippingAddress,
                        shipping_method_code: quote.shippingMethod().method_code,
                        shipping_carrier_code: quote.shippingMethod().carrier_code
                    }
                };

                return storage.post(
                    resourceUrlManager.getUrlForSetShippingInformation(quote),
                    JSON.stringify(payload)
                ).done(
                    function (response) {
                        paymentService.setPaymentMethods(methodConverter(response.payment_methods));
                        quote.setTotals(response.totals)
                    }
                ).fail(
                    function (response) {
                        errorProcessor.process(response);
                    }
                );
            }
        }
    }
);

Step 5: Create JS component registering processors

A .js UI component that registers the rate processor and the saving processor need to be created in your custom module directory. And this component need to be located under the <your_module_dir>/view/frontend/web/js/view/ directory.

The content of the file must be similar to this:

define(
    [
        'uiComponent',
        'Magento_Checkout/js/model/shipping-rate-service',
        %custom shipping rate processor%,
        'Magento_Checkout/js/model/shipping-save-processor',
        %custom shipping save processor%
    ],
    function (
        Component,
        shippingRateService,
        customShippingRateProcessor,
        shippingSaveProcessor,
        customShippingSaveProcessor
    ) {
        'use strict';

        /** Register rate processor */
        shippingRateService.registerProcessor(%address type%, customShippingRateProcessor);

        /** Register save shipping address processor */
        shippingSaveProcessor.registerProcessor(%address type%, custormShippingSaveProcessor);

        /** Add view logic here if needed */
        return Component.extend({});
    }
);

Step 6: Declare new components in checkout page layout

A <your_module_dir>/view/frontend/layout/checkout_index_index.xml file need to be created in your custom module directory. Then add the following code in that file:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="shipping-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <!-- Declare the component that registers the shipping address and rates processors -->
                                                <item name="custom-address-provider" xsi:type="array">
                                                    <item name="component" xsi:type="string">%component that registers address/rate processors%</item>
                                                </item>
                                                <!-- Declare the component that renders the shipping address -->
                                                <item name="shippingAddress" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="rendererTemplates" xsi:type="array">
                                                            <item name="%address type%" xsi:type="array">
                                                                <item name="component" xsi:type="string">%address renderer JS component%</item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                           </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Step 7: Add shipping address renderer to Ship-To block

On the Review and Payment Information step, the shipping address is shown in the Ship-To section, which would ensure that everything is set correctly.

If you want the address type to be shown in here also, you need to render it by creating a .html template. And declare in the corresponding location in the layout.

Add template for displaying address in Ship-To section

You need to create a <your_module_dir>/view/frontend/web/template/<your_template>.html file in your custom module directory. You can use Knockout JS syntax for your template.

The code from the default template can be used: app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html.

Declare address to be used in Ship-To section in layout

Add the following code into your <your_module_dir>/view/frontend/layout/checkout_index_index.xml file:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Checkout\Block\Onepage" name="checkout.root" template="onepage.phtml" cacheable="false">
                <arguments>
                    <argument name="jsLayout" xsi:type="array">
                        <item name="components" xsi:type="array">
                            <item name="sidebar" xsi:type="array">
                                <item name="children" xsi:type="array">
                                    <item name="shipping-information" xsi:type="array">
                                        <item name="children" xsi:type="array">
                                            <item name="ship-to" xsi:type="array">
                                                <item name="rendererTemplates" xsi:type="array">
                                                    <item name="%address type%" xsi:type="array">
                                                        <item name="component" xsi:type="string">uiComponent</item>
                                                        <item name="config" xsi:type="array">
                                                                <item name="template" xsi:type="string">%custom template%</item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Conclusion

Above I have just provided you seven steps to help you custom shipping address template in checkout steps, hope this instruction is helpful for you. If you have further questions or new ideas, feel free to leave a comment below.

Enjoyed the tutorial? Spread it to your friends!