This article shows you step by step for Magento 2 add custom field in checkout page without relying on 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 the Magento 2 Order Attributes extension by BSS. This extension provides you with many advanced features to add custom check fields and improve checkout experiences.
The Downside Of Default Magento 2 Checkout Page
Table of Contents
By default, the Magento checkout page only shows mandatory informative fields and 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 8 Essential Tips for Magento 2 Checkout Page Customization to improve the process!
Magento 2 Add Custom Field in Checkout Page: Programmatical Instruction
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="BSS_Deliverydate" setup_version="1.0.0"> <sequence> <module name="Magento_Sales"/> </sequence> </module> </config>
You can change the Module name according to the additional field you want to add. In the code, we are using the name “Deliverydate.”
>>> Looking to boost your online store? >>> EXPLORE NOW: Plugins for Magento Store
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 BSS\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="BSS\Deliverydate\Plugin\Checkout\LayoutProcessorPlugin" sortOrder="10"/> </type> </config> BSS\Deliverydate\Plugin\Checkout\LayoutProcessor.php: <?php namespace BSS\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 frontend.
Make checkout easy with BSS Magento 2 One Step Checkout extension – Create a smoother, faster experience for your customers!
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': { 'BSS_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 BSS\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="BSS_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="BSS\Deliverydate\Observer\SaveToOrder" /> </event> </config>
And file Observer\SaveToOrder.php
<?php namespace BSS\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.
>>> Ready to dive deeper into Magento? Discover our comprehensive guide on Magento 2 tutorial for beginners (2024 update)
Conclusion: Magento 2 Add Custom Field in Checkout Page
Above, we have shown you how to add custom field in checkout page magento 2 programmatically. We hope this article is helpful and good luck to you!
>>> CHECK OUT guide to Customize Checkout Fields in Magento without using third-party extensions HERE!
If the process of Magento 2 adding custom fields in checkout page using code seems too complicated, consider installing the Magento 2 Order Attributes module by BSS Commerce for an easier solution. With this Magento module, you can add as many fields as you want on the checkout page effortlessly, collecting valuable customer insights through field responses for informed decision-making.