Layouts
A layout is an XML file that describes which parts a page consists of and where they stand. The HTML markup itself is not written in a layout: it only arranges blocks. Thanks to that, any module can add a block to another module's page or remove an unneeded one.
Containers and blocks
| Term | What it is |
|---|---|
| Container | A place on the page that holds other elements: header, main area, footer |
| Block | A part of the page with its own template: product name, price, a form |
The main area of a page is the content container. This is where you usually add your blocks.
Where a layout lives
Storefront layouts are in the module's view/frontend/layout folder. The file name is built from the three URL parts joined by underscores: for the /hello/index/index page it is hello_index_index.xml. Such a name is called a layout handle.
app/code/Acme/Hello/
├── Controller/Index/Index.php
├── etc/
└── view/
└── frontend/
├── layout/
│ └── hello_index_index.xml new file
└── templates/
└── greeting.phtml new fileA layout for your page
<?xml version="1.0"?>
<!-- app/code/Acme/Hello/view/frontend/layout/hello_index_index.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block name="hello.greeting" template="Acme_Hello::greeting.phtml"/>
</referenceContainer>
</body>
</page>The layout adds a block named hello.greeting to the content container. The template is written as Module::file — the path is relative to the module's view/frontend/templates folder.
Create the view/frontend/templates/greeting.phtml template with a single line:
<p>Hello from the template!</p>Run bin/magento cache:clean and open /hello: the text "Hello from the template!" appears in the middle of the shop page. The action from the previous lesson must return a TYPE_PAGE result.
Page layout type
The layout attribute of the page tag picks the number of columns:
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">Available values are 1column, 2columns-left, 2columns-right, 3columns.
Changing a core page
To change the product page, create a layout with the same name in your module — catalog_product_view.xml. Magento merges all files of the same name:
<?xml version="1.0"?>
<!-- app/code/Acme/Hello/view/frontend/layout/catalog_product_view.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="product.info.sku" remove="true"/>
<referenceContainer name="product.info.main">
<block name="hello.delivery" template="Acme_Hello::greeting.phtml" after="product.info.price"/>
</referenceContainer>
</body>
</page>After bin/magento cache:clean the SKU disappears from every product page, and a block with your template appears below the price. For the module layout to be applied after the catalog layout, module.xml must list Magento_Catalog in the sequence section.
Layout instructions
| Instruction | What it does |
|---|---|
referenceContainer | Refers to an existing container |
referenceBlock | Refers to an existing block |
block | Adds a new block |
move | Moves an element: element, destination, before or after |
remove="true" | Removes an element from the page |
A file named default.xml applies to all storefront pages — it is used to change the header and the footer.
Common mistake
The layout name does not match the URL: the file is called hello_index.xml, or frontName was used instead of the route id. Magento reports no error — the page simply stays empty. The name always has three parts: route id_controller_action, in lower case.