How to Add Custom Field in Checkout Page Below Payment Method List in Magento 2

Magento 2 CMS is widely preferred to run online businesses in various niches.

As the CMS is flexible for customization, modern business requirements can be easily fulfilled. One such example is to add custom field in checkout page just after payment method list in Magento 2. Likewise you can also add custom field below Apply Discount code in Magento 2, to make the customers click it and let them explore detailed offer benefits.

Also as being an admin you can get week days list in Magento 2 system configuration for when a customer can book an appointment, or select the days on which the store will offer delivery.

This post shows the programmatic solution for the same.

For example. you need the customer to agree with something apart from the default Magento 2 terms and conditions, you can implement a custom checkbox.

Or, you can add the gift wrap checkbox using the below code. If you want to encourage the customers to donate some amount with each purchase, you can add a checkbox field which when the customer will tick, a fixed amount will be added to the cart total automatically. Or even If you want to restrict access to certain payment methods and make them visible only to the admin, you can use the “Make a Payment Method Visible Only to Admin” feature.

Any of the above scenarios can be implemented or other custom fields can be added as shown in the figure below:

Add custom field in checkout page just after payment method list in Magento 2:

The example here is about adding a custom checkbox in the checkout page, saving its value in the database table, and displaying the same in the admin panel.

Steps to Add custom field in checkout page just after payment method list in Magento 2:

Step 1: To add custom field in the table

Create InstallData.php file under Vendor\Module\Setup\

<?php
namespace Vendor\Module\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetupFactory;

class InstallData implements InstallDataInterface
{

    private $customerSetupFactory;

    /**
     * Constructor
     *
     * @param \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory
     */
    public function __construct(
        CustomerSetupFactory $customerSetupFactory
    ) {
        $this->customerSetupFactory = $customerSetupFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function install(
        ModuleDataSetupInterface $setup,
        ModuleContextInterface $context
    ) {
        $installer = $setup;

        $installer->startSetup();

        $installer->getConnection()->addColumn(
            $installer->getTable('quote'),
            'agree',
            [
                'type' => \Magento\Framework\DB\Ddl\Table::TYPE_BOOLEAN,
                'visible'  => true,
                'default' => 0,
                'comment' => 'Custom Condition'
            ]
        );


        $installer->getConnection()->addColumn(
            $installer->getTable('sales_order'),
            'agree',
            [
                'type' => \Magento\Framework\DB\Ddl\Table::TYPE_BOOLEAN,
                'visible'  => true,
                'default' => 0,
                'comment' => 'Custom Condition'
            ]
        );
    }
}

Step 2: To Create extension attribute and add checkbox just after payment methods and Save that field in Quote table

Create extension_attributes.xml file under Vendor\Module\etc\

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

Create checkout_index_index.xml file under Vendor\Module\view\frontend\layout\

<?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="billing-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="payment" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="afterMethods" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="custom-checkbox" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Vendor_Module/js/checkout/customJs</item>
                                                                    <item name="displayArea" xsi:type="string">before-place-order</item>
                                                                    <item name="sortOrder" xsi:type="string">3</item>
                                                                    <item name="dataScope" xsi:type="string">checkoutcomments</item>
                                                                    <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Create customJs.js file under Vendor\Module\view\frontend\web\js\checkout

define(
    [
        'ko',
        'jquery',
        'uiComponent',
        'mage/url'
    ],
    function (ko, $, Component,url) {
        'use strict';
        return Component.extend({
            defaults: {
                template: 'Vendor_Module/checkout/customCheckbox'
            },
            initObservable: function () {

                this._super()
                    .observe({
                        CheckVals: ko.observable(false)
                    });
                var checkVal=0;
                self = this;
                this.CheckVals.subscribe(function (newValue) {
                    var linkUrls  = url.build('module/checkout/saveInQuote');
                    if(newValue) {
                        checkVal = 1;
                    }
                    else{
                        checkVal = 0;
                    }
                    $.ajax({
                        showLoader: true,
                        url: linkUrls,
                        data: {checkVal : checkVal},
                        type: "POST",
                        dataType: 'json'
                    }).done(function (data) {
                        console.log('success');
                    });
                });
                return this;
            }
        });
    }
);

Create customCheckbox.html file under Vendor\Module\view\frontend\web\template\checkout

<input type="checkbox" name="customCheckbox" value="" data-bind='checked: CheckVals'/><div> Check to Agree </div>

Create saveInQuote.php file under Vendor\Module\Controller\Checkout

<?php

namespace Vendor\Module\Controller\Checkout;

use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\ForwardFactory;
use Magento\Framework\View\LayoutFactory;
use Magento\Checkout\Model\Cart;
use Magento\Framework\App\Action\Action;
use Magento\Checkout\Model\Session;
use Magento\Quote\Model\QuoteRepository;

class saveInQuote extends Action
{
    protected $resultForwardFactory;
    protected $layoutFactory;
    protected $cart;

    public function __construct(
        Context $context,
        ForwardFactory $resultForwardFactory,
        LayoutFactory $layoutFactory,
        Cart $cart,
        Session $checkoutSession,
        QuoteRepository $quoteRepository
    )
    {
        $this->resultForwardFactory = $resultForwardFactory;
        $this->layoutFactory = $layoutFactory;
        $this->cart = $cart;
        $this->checkoutSession = $checkoutSession;
        $this->quoteRepository = $quoteRepository;

        parent::__construct($context);
    }

    public function execute()
    {
        $checkVal = $this->getRequest()->getParam('checkVal');
        $quoteId = $this->checkoutSession->getQuoteId();
        $quote = $this->quoteRepository->get($quoteId);
        $quote->setAgree($checkVal);
        $quote->save();
    }
}

Step 3: To Save that custom field in Sales_Order table

Create events.xml file under Vendor\Module\etc\

<?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="custom_checkbox_code_order_place_before_action" instance="Vendor\Module\Observer\PlaceOrder"/>
    </event>
</config>

Create PlaceOrder.php file under Vendor\Module\Observer\

<?php
namespace Vendor\Module\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Quote\Model\QuoteFactory;
use Psr\Log\LoggerInterface;

class PlaceOrder implements ObserverInterface
{
    /**
    * @var \Psr\Log\LoggerInterface
    */
    protected $_logger;

    /**
    * @var \Magento\Customer\Model\Session
    */
    protected $quoteFactory;

    /**
     * Constructor
     *
     * @param \Psr\Log\LoggerInterface $logger
     */

    public function __construct(LoggerInterface $logger,
        QuoteFactory $quoteFactory) {
        $this->_logger = $logger;
        $this->quoteFactory = $quoteFactory;
    }

    public function execute(Observer $observer)
    {
        $order = $observer->getOrder();
        $quoteId = $order->getQuoteId();
        $quote  = $this->quoteFactory->create()->load($quoteId);
        $order->setAgree($quote->getAgree());
        $order->save();
    }
}

Create routes.xml file at Vendor\Module\etc\frontend

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

Step 4: To Display custom field value in admin side order view

Create sales_order_view.xml file under Vendor\Module\view\adminhtml\layout

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="order_info">
            <block class="Vendor\Module\Block\Adminhtml\Order\View\DisplayCustomValue" name="sales_order_view_custom_value" template="order/view/displayCustomValue.phtml" />
        </referenceBlock>
    </body>
</page>

Create displayCustomValue.phtml file under Vendor\Module\view\adminhtml\templates\order\view

<h4>Custom Condition Added :
<?php $CheckValue = $block->getAgree(); ($CheckValue) ? echo 'Yes' : echo 'No'; ?>
</h4>

Create displayCustomValue.php file under Vendor\Module\Block\Adminhtml\Order\View\

<?php
namespace Vendor\Module\Block\Adminhtml\Order\View;

use Magento\Sales\Api\Data\OrderInterface;
class DisplayCustomValue extends \Magento\Backend\Block\Template
{
    public function __construct(
        \Magento\Backend\Block\Widget\Context $context,
        OrderInterface $orderInterface,
        array $data = []
    ) {
        $this->orderInterface = $orderInterface;
        parent::__construct($context, $data);
    }
    public function getAgree(){
        $orderId = $this->getRequest()->getParam('order_id');
        $order = $this->orderInterface->load($orderId);

        return $order->getAgree();
    }
}

That’s it.

Also, do share the solution with the Magento Community via social media.

Also Read:

Additionally, if you want to add a custom field on the checkout page at a different position with additional features, you may as well use the third-party extension to ease your task!

Thank you.

Sanjay Jethva

Article by

Sanjay Jethva

Sanjay is the co-founder and CTO of Meetanshi with hands-on expertise with Magento since 2011. He specializes in complex development, integrations, extensions, and customizations. Sanjay is one the top 50 contributor to the Magento community and is recognized by Adobe. His passion for Magento 2 and Shopify solutions has made him a trusted source for...