Magento2 - Conditional layout directives

Magento2 - Conditional layout directives

June 14, 2020

Introduction #

I consider Magento’s template engine, based on XMLs, .phtmls - as the best one on the world. Sure, entrance barrier is high, especially for frontend developers, but as soon as one learns how to use it properly - whole new world is open. With XMLs approach - templating engine is highly customizable and flexible. Layouts can be extended and altered by 3rd party code.

Sometimes - we need to include block (or exclude), based on some conditions.

Conditional directives #

As you know, Magento collects all layout definition and update xmls from each extension and then merges one big xml file which defines how final structure will look like. There many things that take place during this process, one of them is checking visibility conditions for each block. If you take a look on class Magento\Framework\View\Layout\Reader\Visibility\Condition in method parseConditions you will notice following conditions available by default:

ifconfig condition #

By default Magento comes with directive ifconfig - when specified - Magento will render block only when some config criteria is met. Take a look:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="footer_links">
            <block class="Magento\Framework\View\Element\Html\Link\Current" name="rss-link" ifconfig="rss/config/active">
                <arguments>
                    <argument name="label" xsi:type="string" translate="true">RSS</argument>
                    <argument name="path" xsi:type="string">rss</argument>
                </arguments>
            </block>
        </referenceBlock>
        <block class="Magento\Rss\Block\Feeds" name="head_rss" ifconfig="rss/config/active"/>
    </body>
</page>

Above xml is taken from RSS module - as you can see - blocks will be rendered only when config path rss/config/active is set to true.

ACL condition #

ACL conditions make sure that block is rendered to those users, who are authorized to do so. It works only for layouts rendered in adminhtml context - this conditions check if specific ACL resource is granted for currently logged in admin.

<block class="Magento\AdminNotification\Block\Window"
                   name="notification_window"
                   as="notification_window"
                   aclResource="Magento_AdminNotification::show_toolbar"
                   template="Magento_AdminNotification::notification/window.phtml"/>

Custom condition #

Magento developers gave other developers option to create own conditions - using visibilityConditions node. Let’s assume we want to have option to render block only between 18:00 and 19:00 (happy hour!)

<referenceContainer name="header">
            <block class="Namespace\Module\Block\HappyHour" name="happyhour.banner">
                <visibilityCondition name="happyhour" className="Namespace\Module\Block\HappyHour\Condition" />
            </block>
        </referenceContainer>

In above snippet, we declar new visibility condition on our HappyHour block - we provide it’s name and classname - which will be responsible for decision logic - whether block should be rendered or not. Let’s create new class Namespace\Module\Block\HappyHour\Condition:

<?php

namespace Namespace\Module\Block\HappyHour;

class Condition implements \Magento\Framework\View\Layout\Condition\VisibilityConditionInterface
{
    
    private static $conditionName = 'happy_hour';

    public function isVisible(array $arguments)
    {
        return date('i') == 21;   
    }

    public function getName()
    {
        return self::$conditionName;
    }
}

Please note that class must implement \Magento\Framework\View\Layout\Condition\VisibilityConditionInterface.

You can also pass some arguments through xml by adding <arguments> node within visibilityCondition node. Now, when layout xml is being merged, it will invoke isVisible method on HappyHour block to decide whether to render it or not.

This trick is widely used for ui_components, but it is not so commonly used for regular blocks in frontend.

⚠️ You probably already know, or you will find that out, that this example with happy hour message will not really work - because layout files are merged just once and later cached - our new condition will be checked against just once. To make it work we need to create page variation just for this one hour. It will be described later.

🍺 If you liked this article you might consider buying me a beer? ;)