hi Mujahidh Haseem,

Thanks for your question. I will try to answer you question first part.

create QaisarSatti/HelloWorld/etc/extension_attributes.xml

<?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\Checkout\Api\Data\ShippingInformationInterface">
        <attribute code="testingfield" type="string"/>
    </extension_attributes>
</config>

create QaisarSatti/HelloWorld/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Checkout\Model\ShippingInformationManagement">
        <plugin name="custom_field" type="QaisarSatti\HelloWorld\Plugin\Checkout\Model\ShippingInformationManagement" sortOrder="1"/>
</type>
</config>

Create plugin QaisarSatti/HelloWorld/Plugin/Checkout/Model/ShippingInformationManagement.php

namespace QaisarSatti\HelloWorld\Plugin\Checkout\Model;
class ShippingInformationManagement
{
    protected $quoteRepository;
    public function __construct(
        \Magento\Quote\Model\QuoteRepository $quoteRepository
    ) {
        $this->quoteRepository = $quoteRepository;
    }
    /**
     * @param \Magento\Checkout\Model\ShippingInformationManagement $subject
     * @param $cartId
     * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
     */

    public function beforeSaveAddressInformation(
        \Magento\Checkout\Model\ShippingInformationManagement $subject,
        $cartId,
        \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
    ) {
        $extAttributes = $addressInformation->getExtensionAttributes();
        $customfield = $extAttributes->getCustomfield();
        $quote->setCustomfield($customfield);
    }
}

Render the component shippingAdditional section.

QaisarSatti/HelloWorld/view/frontend/layout/checkout_index_index.xml

    <?xml version="1.0"?>
    <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" 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">
                                                <item name="shippingAddress" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="shippingAdditional" xsi:type="array">
                                                            <item name="component" xsi:type="string">uiComponent</item>
                                                            <item name="displayArea" xsi:type="string">shippingAdditional</item>
                                                            <item name="children" xsi:type="array">
                                                                <item name="additional_block" xsi:type="array">
                                                                    <item name="component" xsi:type="string">QaisarSatti_HelloWOrld/js/view/checkout/shipping/additional-fields</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
    </page>

Now create component.

QaisarSatti/HelloWorld/view/web/js/view/checkout/shipping/additional-fields.js

    define([
        'uiComponent'
   
    ], function (Component) {
        'use strict';
   
        return Component.extend({
            defaults: {
                template: 'QaisarSatti_HelloWorld/checkout/shipping/additional-fields'
            }    
        });
    });

Now create component html file.
QaisarSatti/HelloWorld/view/web/template/checkout/shipping/additional-fields.html

    <div >
        <div class="field">
            <label class="label" for="testingfield">
                <span data-bind="i18n: 'Test Field'"></span>
            </label>
            <div class="control">
                <input class="input-text" id="testingfield" name="testingfield" type="text" />
            </div>
        </div>
    </div>

Now overwrite following js

Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js

create QaisarSatti/HelloWorld/view/frontend/requirejs-config.js

var config = {
    "map": {
        "*": {
            'Magento_Checkout/js/model/shipping-save-processor/default': 'QaisarSatti_HelloWorld/js/model/shipping-save-processor/default'
        }
    }
};

Create default.js top add your field

QaisarSatti/HelloWorld/view/frontend/web/js/model/shipping-save-processor/default.js

define(
    [
        'jquery',
        'ko',
        'Magento_Checkout/js/model/quote',
        'Magento_Checkout/js/model/resource-url-manager',
        'mage/storage',
        'Magento_Checkout/js/model/payment-service',
        'Magento_Checkout/js/model/payment/method-converter',
        'Magento_Checkout/js/model/error-processor',
        'Magento_Checkout/js/model/full-screen-loader',
        'Magento_Checkout/js/action/select-billing-address'
    ],
    function (
        $,
        ko,
        quote,
        resourceUrlManager,
        storage,
        paymentService,
        methodConverter,
        errorProcessor,
        fullScreenLoader,
        selectBillingAddressAction
    ) {
        'use strict';

        return {
            saveShippingInformation: function () {
                var payload;

                if (!quote.billingAddress()) {
                    selectBillingAddressAction(quote.shippingAddress());
                }

                payload = {
                    addressInformation: {
                        shipping_address: quote.shippingAddress(),
                        billing_address: quote.billingAddress(),
                        shipping_method_code: quote.shippingMethod().method_code,
                        shipping_carrier_code: quote.shippingMethod().carrier_code,
                        extension_attributes:{
                            testingfield: $('[name="testingfield"]').val()
                        }
                    }
                };

                fullScreenLoader.startLoader();

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

Create observer to get the data.

create QaisarSatti/HelloWorld/etc/events.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_model_service_quote_submit_before">
        <observer name="customfield" instance="QaisarSatti\HelloWorld\Observer\SaveCustomFieldObserver"/>
    </event>
</config>

create QaisarSatti/HelloWorld/Observer/SaveCustomFieldObserver.php

<?php
namespace QaisarSatti\HelloWorld\Observer;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
class SaveCustomFieldObserver implements ObserverInterface
{
    /**
     * @var \Magento\Framework\ObjectManagerInterface
     */

    protected $_objectManager;
    /**
     * @param \Magento\Framework\ObjectManagerInterface $objectmanager
     */

    public function __construct(\Magento\Framework\ObjectManagerInterface $objectmanager)
    {
        $this->_objectManager = $objectmanager;
    }
    public function execute(EventObserver $observer)
    {
        $order = $observer->getOrder();
        $quoteRepository = $this->_objectManager->create('Magento\Quote\Model\QuoteRepository');
        /** @var \Magento\Quote\Model\Quote $quote */
        $quote = $quoteRepository->get($order->getQuoteId());
        echo $quote->getCustomfield();
 
        return $this;
    }
}

Qaisar Satti

Hi, I'm Qaisar Satti! I've been a developer for over 20 years, and now I love sharing what I've learned through tutorials and guides. Whether you're working with Magento, PrestaShop, or WooCommerce, my goal is to make your development journey a bit easier and more fun. When I'm not coding or writing, you can find me exploring new tech trends and hanging out with the amazing developer community. Thanks for stopping by, and happy coding!

© Copyrights 2025. All rights reserved.