Contents

Custom layout update for categories or products in Magento 2

In this blog post I would like to show you how to create a custom layout update for multiple categories or products in Magento 2.

No out of box solution

A few years ago in Magento 2 there was a textarea in admin for products or categories where developer could add some XML code if he wanted to. Due the security reasons this field has been removed and replaced with select field. If you want to add some XML changes for a few categories or products there is no out of box solution for it.

There is a easy way to add XML changes for single category or product but for multiple categories/products solution showed in Magento documentation is not good enough.

I will show you the way how I handled this issue with custom module.

Structure of module

VendorName/ModuleName
|-- registration.php
|-- etc
|  |-- module.xml
|  |-- frontend
|     |-- events.xml
|-- Observer
|  |-- LayoutAddHandleObserver.php
|-- view
|  |-- frontend
|     |-- layout
|        |-- example_layout.xml

Event & Observer will do the job

Firstly you need to create a new module. If you don’t know how to do it you can check it here. When you have a empty module you need to add the events.xml file to etc/frontend directory in you module.

<?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="layout_load_before">
        <observer
            name="WyganowskiExampleLayoutAddHandleObserver"
            instance="Wyganowski\Example\Observer\LayoutAddHandleObserver"
        />
    </event>
</config>

This file is setting an observer for an event. In this example if event layout_load_before occurs "Wyganowski\Example\Observer\LayoutAddHandleObserver" class of observer will be executed. If you want to use other event you can easily find it in the Internet.

Now you need to create an observer file. In Observer directory in your module create file named LayoutAddHandleObserver.php. In this file we need to create execute method which will be used when event occurs.

<?php

namespace Wyganowski\Example\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Registry;

class LayoutAddHandleObserver implements ObserverInterface
{
    public function __construct(
        private readonly Registry $registry,
    ) {
    }

    public function execute(Observer $observer): void
    {
        // Your current category
        $category = $this->registry->registry('current_category');

        // Your current product
        $product = $this->registry->registry('current_product');

        // If you want to only change layout for category add this validation:
        if (!$category || $product) {
            return;
        }

        // If you want to only change layout for product add this validation:
        // if (!$product) {
        //     return;
        // }

        $selectedCategoryIds = [1,2,3];
        $categoryId = $category->getId(); // for product use $product->getId()

        if (in_array($categoryId, $selectedCategoryIds)) {
            $layout = $observer->getLayout();

            // Below add your layout XML file
            $layout->getUpdate()->addHandle('example_layout');
        }
    }
}

In this example I choose to use categories IDs for simplicity. If ID of current category matches IDs from $selectedCategoryIds than layout update will be executed. Of course you should use your condition for your case.

Now we can start working on frontend

The last step of adding custom layout update will be adding XML layout file to your module. In view/frontend/layout directory add example_layout.xml file where you can add your frontend changes. In this example I just removed title of category.

<?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="page.main.title" remove="true"/>
    </body>
</page>

In this file you can add changes you want to implement for your multiple products/categories pages.

Sum up

If you followed every step of this post you should have a custom module where you can add layout changes for multiple categories and products. If something is not working you can check my example module here.

TL;DR

Download this module, put it in your app/code and change Wyganowski_Example to VendorName/ModuleName in registration.php,etc/module.xml. After this you need to add your condition in if statement in Wyganowski\Example\Observer\LayoutAddHandleObserver.php and add you layout changes in example_layout.xml file.