6

To add a custom field, I can create a plugin and it will add input on the checkout.

1) Create plugin LayoutProcessor::process

Exapmle :

Namespace/Module/etc/frontend/di.xml

<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_custom_field_checkout_form" type="Namespace\Module\Model\Plugin\Checkout\LayoutProcessor" sortOrder="100"/>
    </type>
</config>

Namespace/Module/Model/Plugin/Checkout/LayoutProcessor.php

<?php
namespace Namespace\Module\Model\Plugin\Checkout;
class LayoutProcessor
{
    public function afterProcess(
    \Magento\Checkout\Block\Checkout\LayoutProcessor $subject,
    array $jsLayout
    ) {
        $jsLayout['components']['checkout']['children']['steps']
        ['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']
        ['children']['custom_field'] = [
            'component' => 'Magento_Ui/js/form/element/abstract',
            'config' => [
                'customScope' => 'shippingAddress.custom_attributes',
                'template' => 'ui/form/field',
                'elementTmpl' => 'ui/form/element/input',
                'options' => [],
                'id' => 'custom-field'
            ],
            'dataScope' => 'shippingAddress.custom_attributes.custom_field',
            'label' => 'Custom Field',
            'provider' => 'checkoutProvider',
            'visible' => true,
            'validation' => [],
            'sortOrder' => 250,
            'id' => 'custom-field'
        ];

        return $jsLayout;
    }

}

2) Override checkout_index_index.xml

But there is another way, when I can expand checkout_index_index.xml. For example, I'll add a checkbox :

Namespace/Module/view/frontend/layout/checkout_index_index.xml

<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">
                                        <!-- Modifying an existing step-->
                                        <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="before-form" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="newsletter" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Namespace_Module/js/view/newsletter</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Next, I will create these files :

Namespace/Module/view/frontend/web/js/view/newsletter.js Namespace/Module/view/frontend/web/template/newsletter.html

And get the checkbox on the form.

Question : Tell me please, in order to change the checkout, when should I create plugin LayoutProcessor::process and when to override checkout_index_index.xml?

2 Answers 2

11

XML Checkout. Should think about XML first.

1) A standard practice

Most of the developer will take a look the XML first to check the XML layout.

2) Maintenance

If you're familiar with checkout XML, you will see that it's easy to change. On the other hand, LayoutProcessor::process() will be "messy" if there are one more changes from different extensions.

When do we need to use LayoutProcessor::process() plugin?

1) Complex logic

It's hard to say in this case. But for example:

\Magento\Checkout\Block\Checkout\LayoutProcessor::process($jsLayout)

......
['payment']['children'] = $this->processPaymentChildrenComponents(
                $jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
                ['payment']['children'],
                $elements
            );
......

We need to assign the billing info to each payment. As we can see, it's impossible to use XML.

2) Remove component completely

We can use XML to disable a component, but component still is rendered. We can remove this component completely.

XML:

<item name="%the_component_to_be_disabled%" xsi:type="array">
    <item name="config" xsi:type="array">
        <item name="componentDisabled" xsi:type="boolean">true</item>
    </item>
</item>

LayoutProcessor::process()

unset($jsLayout['components']['checkout']['children']['steps'][%path_to_target_node%]); //%path_to_target_node% is the path to the component's node in checkout_index_index.xml
return $jsLayout;

3) Can do what XML cannot do...

Don't need to explain more here.

1
  • How to add css to the new field? Oct 25, 2019 at 12:19
1

First of all you do not obligatory need to create a plugin as "Customizations implemented through plugins SHOULD be adjusted respectively" according to Magento 2 Technical Guidelines: https://devdocs.magento.com/guides/v2.2/coding-standards/technical-guidelines.html.

The problem with plugins is that they influence the performance. Plugins SHOULD NOT be used within own module. Besides plugins can impact the sort order and your plugin can be called before necessary layout processor.

That's why if you want to customize Magento 2 checkout think about either:

  1. Usage of checkout_index_index.xml in your module. Check https://devdocs.magento.com/guides/v2.3/howdoi/checkout/checkout_customize.html for more details.
  2. Implementing \Magento\Checkout\Block\Checkout\LayoutProcessorInterface::process in your module through di.xml. Check \Magento\Checkout\Block\Checkout\LayoutProcessor.php::process for more details.

Usage of LayoutProcessorInterface gives you ability to handle dynamic attributes. For example, you need to customize billing step on checkout and display custom component on all payment methods. In your implementation of LayoutProcessorInterface you can get all payment methods and build layout configuration with your custom component for all of them dynamically.

Or for example in your implementation of LayoutProcessorInterface you can dynamically add or not add your custom components to the js block Layout depending on configuration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.