What is a custom layout processor in Magento? To answer this question, we’ll need to take a step back and first learn how a page layout is rendered in Magento. Specifically, pages rendered with JavaScript, such as Magento’s one page checkout.
Overview of the JavaScript initialization process for Magento’s checkout
Magento’s checkout page is considered a “one page” checkout, because the initial page is loaded with a server-side route, and rendered with layout XML. We can confirm this by opening up Magento Checkout’s routes.xml
file:
And confirm the frontName="checkout"
, which will control all URLs starting with /checkout
, including Magento’s checkout.
Since we know the /checkout
route loads layout XML files with the naming convention of checkout_index_index.xml
, the appropriate layout file within this Checkout module is applied to this route:
You’ll notice this layout XML file references the main content
container, adding a sole <block>
to this container named checkout.root
. This block loads the onepage.phtml
template file, which then initializes the JavaScript process with the script
tag:
This magical little piece of code is what hands off the remainder of the checkout rendering process to JavaScript.
If this intrigues, you, it may help learning more about block classes to understand how they work compared to view models.
Where does jsLayout come from?
In this PHTML template above, the $block
variable is type-hinted to the Onepage
class:
This tells us that $block->getJsLayout()
references \Magento\Checkout\Block\Onepage::getJsLayout()
. When we can inspect this function, we can see where this magic takes place:
Here is where we finally see a reference to something called a “layout processor”. This code loops over all layout processors, which in turn continue modifying the jsLayout.
Layout processor: an example
There is a default layout processor located in the Magento Checkout module. If we look in it’s process()
function, we’ll notice it carrying out some extra tasks relating to address attributes, shipping & billing fields:
The $jsLayout
variable is passed in as an argument, modified, and then returned as value to the function call of getJsLayout()
.
In much the same way this jsLayout was modified using a core built-in layout processor, we can create our own layout processor to modify just about any part of the jsLayout.
Why not modify layout components with XML?
If you are familiar with UI Components, you will be familiar with the role that layout XML plays to inject values & properties into JavaScript components.
As a quick summary, values defined within a UI Component’s config
array with XML:
...can be accessed as a property of the related UI Component:
The values within this layout XML can of course be overridden within custom modules, following Magento’s standard XML fallback merging process. This overriding process is one of the great strengths of Magento.
In almost all scenarios, you will want to define properties and value overrides just like this with XML.
In specific circumstances, this may not be possible though, as a large amount of XML will come with the increased risk of introducing either human error or reduced code maintainability. A great example of this scenario is when dealing with fields that are dynamically created during the checkout, such as those related to payment methods. Since payment methods can be toggled on or off from Magento’s admin or created with third-party modules, their dynamic nature creates a liability to updates written in XML.
It's also possible you may have unique client requirements in which you'll need to be able to easily duplicate or move blocks of components to other areas of the jsLayout, and this would be extremely time-consuming process to write or handle with XML.
For these scenarios, you will almost always wish to create your own custom layout processors to process these dynamic situations.
Implementing your own custom layout processor
If you’ve made it this far, give yourself a pat on the back. The checkout is definitely the most complex areas of Magento, and is very difficult to understand without an extensive breakdown of each specific related topic.
Creating your own custom layout processor is actually extremely simple. Your first step is to make Magento aware of your layout processor by adding it as a value to the $layoutProcessors
array of the OnePage
class.
This can easily be done by using argument substitution with a di.xml
file:
Since you depend on the Magento_Checkout
module now, you’ll also want to add that module as a dependency to your module:
Then, you can create a new class which implements the LayoutProcessorInterface
, to apply any update you wish with PHP.
Within your custom layout processor, you have access to the full jsLayout object which will be rendered in the checkout.
In this layout processor, we’re just updating the sort order of the city
, region_id
and postcode
address fields. This code will override any values defined with XML, and update the related address fields sortOrder
value.
The same functionality would be extremely hard to write with XML, because we are iterating through every payment method and applying updates to each of the children form fields. Creating this same functionality with XML would lead to lots of redundant code, making it hard to diagnose & debug in future updates.
Conclusion
I hope this blog post help made sense of exactly how layout processors are created and added to the JavaScript rendering process of Magento's checkout, and how you can create your own layout processor to accomplish dynamic tasks in a more streamlined manner.
Looking to go over layout processors step-by-step in much greater detail? These links may help:
- The Customize the Magento 2 Checkout course (700+ students)
- Grow your Magento expertise with all courses & lessons (700+ students)
- Learn visually with blocks of code & inline comments (3,000+ students)