Adding a static CMS block to the Magento 2 checkout
Magento
/Tue Oct 24 2017
Adding static CMS blocks to the checkout in Magento used to be an easy task. In Magento 2 however, the whole checkout is dynamically generated with Knockout on the client side. Adding a simple CMS block is now overly complex (which seems to be the overall theme of Magento 2). Magento now requires you to create a module that provides a Knockout variable containing the CMS block content. To prevent someone else from struggling with it, I wrote a guide on how to do this.
Creating the module
The easiest way to create a module skeleton from the command line is to use n98-magerun
. Get it from here if you don't already have it. Create the module in your Magento 2 root folder and change directory using the following commands:
n98 dev:module:create VendorName ModuleName cd app/code/VendorName/ModuleName/
Replace vendor and module names to something cool if you like. I'll assume app/code/VendorName/ModuleName/
as your working directory from now on. I had some problems with the empty etc/event.xml
file, so I'd suggest you just remove it.
Creating the model
First thing we'll do is create a new model. Create and open the file Model/ConfigProvider.php
. Its contents should be:
<?php namespace VendorName\ModuleName\Model; use Magento\Checkout\Model\ConfigProviderInterface; use Magento\Framework\View\LayoutInterface; class ConfigProvider implements ConfigProviderInterface { /** @var LayoutInterface */ protected $_layout; protected $cmsBlock; public function __construct(LayoutInterface $layout, $blockId) { $this->_layout = $layout; $this->cmsBlock = $this->constructBlock($blockId); } public function constructBlock($blockId){ $block = $this->_layout->createBlock('Magento\Cms\Block\Block') ->setBlockId($blockId)->toHtml(); return $block; } public function getConfig() { return [ 'cms_block' => $this->cmsBlock ]; } }
This model will create a CMS block upon calling the __construct
function. The $blockID
argument will determine what block it will load. This can be both the (numeric) block ID or the identifier.
Constructor arguments
Next we're going to create and open the file: etc/frontend/di.xml
. Its contents should be:
<?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\Model\CompositeConfigProvider"> <arguments> <argument name="configProviders" xsi:type="array"> <item name="cms_block_config_provider" xsi:type="object">VendorName\ModuleName\Model\ConfigProvider</item> </argument> </arguments> </type> <type name="VendorName\ModuleName\Model\ConfigProvider"> <arguments> <argument name="blockId" xsi:type="string">checkout_block</argument> </arguments> </type> </config>
Here we're telling Magento that it has to load our ConfigProvider
model and should use the value 'checkout_block'
for the $blockId
argument in its __construct
function. You can now create a CMS block from the backend with identifier name checkout_block
or alternatively, change the value to an already existing block identifier.
Calling the CMS block
At this point, you can use paste the following in one of the checkout template files and the the CMS block will appear:
<div data-bind="html: window.checkoutConfig.cms_block"></div>
However, this isn't a very portable solution since it requires you to edit or override the theme files. That's why we're going to create this layout file: view/frontend/layout/checkout_index_index.xml
. It should contain the following:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="checkout" 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="cms-block" xsi:type="array"> <item name="component" xsi:type="string">VendorName/ModuleName/js/view/cms-block</item> <item name="sortOrder" xsi:type="string">0</item> </item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page>
This layout file defines a new step in the checkout called cms-block
that is rendered by the VendorName_ModuleName/js/view/cms-block
view. I've set the sort order to 1 in this example so the block appears above the shipping address fields, but you can choose a higher number to move it down if you like.
Next, we're going to create the javascript view we've just defined: view/frontend/web/js/view/cms-block.js
. It should contain this:
define( [ 'jquery', 'ko', 'uiComponent' ], function( $, ko, Component ) { 'use strict'; return Component.extend({ defaults: { template: 'VendorName_ModuleName/cms_block' }, initialize: function () { var self = this; this._super(); } }); } );
This view function renders the VendorName_ModuleName/cms_block
when called, so let's create it: view/frontend/web/template/cms_block.html
. This template should contain the cms block variable we created earlier:
<div data-bind="html: window.checkoutConfig.cms_block"></div>
And voila! Your CMS block should now be visible at the top of the Magento 2 checkout. If anything went wrong, please ensure that you have the following directory structure:
app └── code └── VendorName └── ModuleName ├── Model │ └── ConfigProvider.php ├── etc │ ├── config.xml │ ├── crontab.xml │ ├── di.xml │ ├── frontend │ │ └── di.xml │ └── module.xml ├── registration.php └── view └── frontend ├── layout │ └── checkout_index_index.xml └── web ├── js │ └── view │ └── cms-block.js └── template └── cms_block.html
If you want to review any of files used in this guide, or just install the module and be done with it, please checkout this Github page.