How To Add Magento Custom Checkout Fields Using Codes

by admin

This article show you how to add Magento Custom Checkout Fields without using any third-party extension. And here’s how!

As you know, cart abandonment is a big problem for any business. And in eCommerce stores, the cart abandonment rate varies between 60% and 80%.

Luckily, there are a lot of practices to help you reduce the cart abandonment rate. And adding custom fields to the Magento checkout page is one of the best solutions. By collecting additional information, you can fulfill customers’ demands better. Therefore they would be more likely to complete their orders.

However, if you know little to nothing about coding or want to save your time, we strongly recommend using Magento 2 Checkout Custom Field by BSS. This extension provides you with many advanced features to add custom check fields and improve checkout experiences.

Add Custom Checkout Field Magento 2

 

The Downside Of Default Magento 2 Checkout Page

By default, the Magento checkout page only shows mandatory informative fields, and it doesn’t offer extra checkout fields.

However, your business usually requires more than that basic information to:

  • Understand your customers better
  • Collect data to do some research
  • Fulfill customers’ additional demands

Therefore, the default checkout page can bring down the competitiveness of your store.

EXPLORE NOW 9 Magento 2 Checkout Customization Techniques to improve the process!

Instruction To Add Magento Custom Checkout Fields Programmatically

Note: In this intrusion, we will show you how to add the “Delivery Date” field as an example. But you can add any custom checkout field following these steps.

Step 1: Create a module

The first step you need to do is to create the registration.php file as below:

registration.php

<?php
use \Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Deliverydate', __DIR__);

etc\module.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magezon_Deliverydate" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Sales"/>
        </sequence>
    </module>
</config>

You can change the Module name accordingly to the additional field you want to add.

In the code, we are using the name “Deliverydate.”

Step 2: Add a new column to some tables

Next, you need to add a new column for your new custom field to the following tables:

  • quote
  • sales_order
  • sales_order_grid
<?php
namespace Magezon\Deliverydate\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;

class InstallSchema implements InstallSchemaInterface
{
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        $installer = $setup;
        $installer->startSetup();

        $installer->getConnection()->addColumn(
            $installer->getTable('quote'),
            'delivery_date',
            [
                'type' => 'datetime',
                'nullable' => false,
                'comment' => 'Delivery Date',
            ]
        );

        $installer->getConnection()->addColumn(
            $installer->getTable('sales_order'),
            'delivery_date',
            [
                'type' => 'datetime',
                'nullable' => false,
                'comment' => 'Delivery Date',
            ]
        );

        $installer->getConnection()->addColumn(
            $installer->getTable('sales_order_grid'),
            'delivery_date',
            [
                'type' => 'datetime',
                'nullable' => false,
                'comment' => 'Delivery Date',
            ]
        );

        $setup->endSetup();
    }
}

Because we are creating a “Delivery Date” checkout field in this example, the field type is set as “datetime.”

You can also set the input type to “text” to collect string data.

Step 3: Add this order attribute field to the checkout page

etc\frontend\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\Block\Checkout\LayoutProcessor">
        <plugin name="add_delivery_date_field"
                type="Magezon\Deliverydate\Plugin\Checkout\LayoutProcessorPlugin" sortOrder="10"/>
    </type>
</config>


Magezon\Deliverydate\Plugin\Checkout\LayoutProcessor.php:

<?php
namespace Magezon\Deliverydate\Plugin\Checkout;

class LayoutProcessorPlugin
{
    /**
     * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $subject
     * @param array $jsLayout
     * @return array
     */
    public function afterProcess(
        \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
        array  $jsLayout
    ) {

        $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']
        ['shippingAddress']['children']['before-form']['children']['delivery_date'] = [
            'component' => 'Magento_Ui/js/form/element/date',
            'config' => [
                'customScope' => 'shippingAddress',
                'template' => 'ui/form/field',
                'elementTmpl' => 'ui/form/element/date',
                'options' => [],
                'id' => 'delivery_date'
            ],
            'dataScope' => 'shippingAddress.delivery_date',
            'label' => __('Delivery Date'),
            'provider' => 'checkoutProvider',
            'visible' => true,
            'validation' => [],
            'sortOrder' => 200,
            'id' => 'delivery_date'
        ];


        return $jsLayout;
    }
}

After this step, you can check how it looks in the front end.

Step 4: Save the selected attribute value of the custom field

There are several ways to do this, but we use Knockout JS as the simplest way in this instruction.

First, override some .js files by adding them to the requirejs-config.js.

var config = {
config: {
    mixins: {
        'Magento_Checkout/js/action/place-order': {
            'Magezon_Deliverydate/js/order/place-order-mixin': true
        },
    }
};

For the place-order-mixin.js file, save the attribute value of your new custom field to the quote by using Ajax.

define([
    'jquery',
    'mage/utils/wrapper',
    'Magento_CheckoutAgreements/js/model/agreements-assigner',
    'Magento_Checkout/js/model/quote',
    'Magento_Customer/js/model/customer',
    'Magento_Checkout/js/model/url-builder',
    'mage/url',
    'Magento_Checkout/js/model/error-processor',
    'uiRegistry'
], function (
    $, 
    wrapper, 
    agreementsAssigner,
    quote,
    customer,
    urlBuilder, 
    urlFormatter, 
    errorProcessor,
    registry
) {
    'use strict';

    return function (placeOrderAction) {

        /** Override default place order action and add agreement_ids to request */
        return wrapper.wrap(placeOrderAction, function (originalAction, paymentData, messageContainer) {
            agreementsAssigner(paymentData);
            var isCustomer = customer.isLoggedIn();
            var quoteId = quote.getQuoteId();

            var url = urlFormatter.build('mgzcustom/quote/save');

            var deliveryDate = $('[name="delivery_date"]').val();

            if (deliveryDate) {

                var payload = {
                    'cartId': quoteId,
                    'delivery_date': deliveryDate,
                    'is_customer': isCustomer
                };

                if (!payload.delivery_date) {
                    return true;
                }

                var result = true;

                $.ajax({
                    url: url,
                    data: payload,
                    dataType: 'text',
                    type: 'POST',
                }).done(
                    function (response) {
                        result = true;
                    }
                ).fail(
                    function (response) {
                        result = false;
                        errorProcessor.process(response);
                    }
                );
            }

            return originalAction(paymentData, messageContainer);
        });
    };
});

Then create the Controller\Quote\Save.php file.

<?php

namespace Magezon\Deliverydate\Controller\Quote;

class Save extends \Magento\Framework\App\Action\Action
{
    protected $quoteIdMaskFactory;

    protected $quoteRepository;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory,
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
    ) {
        parent::__construct($context);
        $this->quoteRepository = $quoteRepository;
        $this->quoteIdMaskFactory = $quoteIdMaskFactory;
    }

    /**
     * @return \Magento\Framework\Controller\Result\Raw
     */
    public function execute()
    {
        $post = $this->getRequest()->getPostValue();
        if ($post) {
            $cartId       = $post['cartId'];
            $deliveryDate = $post['delivery_date'];
            $loggin       = $post['is_customer'];

            if ($loggin === 'false') {
                $cartId = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id')->getQuoteId();
            }

            $quote = $this->quoteRepository->getActive($cartId);
            if (!$quote->getItemsCount()) {
                throw new NoSuchEntityException(__('Cart %1 doesn\'t contain products', $cartId));
            }

            $quote->setData('delivery_date', $deliveryDate);
            $this->quoteRepository->save($quote);
        }
    }
}

Now we need to create a file etc/frontend/routes.xml to set up a router so that Ajax can send the data of your new custom checkout field to the controller.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="mgzcustom" frontName="mgzcustom">
            <module name="Magezon_Deliverydate" />
        </route>
    </router>
</config>

After that, you save the selected values of your custom field to the sale_order.table.

It’s time to create the etc/events.xml file.

<?xml version="1.0"?>
<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="save_delivery_date_to_order" instance="Magezon\Deliverydate\Observer\SaveToOrder" />
    </event>
</config>

And file Observer\SaveToOrder.php

<?php
namespace Magezon\Deliverydate\Observer;
class SaveToOrder implements \Magento\Framework\Event\ObserverInterface
{   
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $event = $observer->getEvent();
        $quote = $event->getQuote();
     $order = $event->getOrder();
           $order->setData('delivery_date', $quote->getData('delivery_date'));
    }
}

Step 5: Display the attribute value in the sales order grid

To show the attribute value of the custom field in the order grid, you need to create the sales_order_grid.xml.

Then you add an extra column named as the name of your custom field (it’s Delivery Date in this example) to the path: View\adminhtml\ui_component\sales_order_grid.xml.

<?xml version="1.0"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="sales_order_columns">
        <column name="delivery_date">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="label" xsi:type="string" translate="true">Delivery Date</item>
                    <item name="dateFormat" xsi:type="string">Y-MM-dd</item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item>
                    <item name="dataType" xsi:type="string">date</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

As you can see in the image below, we have had a new column named Delivery Date.

Checkout Magento 2

Conclusion

Above, we have shown you how to add Magento Custom Checkout Fields programmatically.

We hope this article is helpful and good luck to you!

CHECK OUT guide to Remove Magento 2 Checkout Fields without using third-party extensions HERE!

BSS Commerce is one of the leading Magento extension providers and web development services in the world. With experienced and certified Magento developers, we commit to bringing high-quality products and services to optimize your business effectively. Furthermore, we offer FREE Installation – FREE 1-year Support and FREE Lifetime Update for every Magento extension.

CONTACT NOW to let us know your problems. We are willing to support you every time.

Next Reading Suggestions

© 2019 BSS Commerce owned by THANH CONG INTER ., JSC. All Rights Reserved.
Business registration certificate no. 0106064469 issued by Hanoi Department of Planning and Investment on 19 December 2019.
Legal Representative: Mr. Nguyen Quang Trung.