Table of content

Magento 2 Certified Professional Front End Developer Guide


Section 3: Layout XML in Themes

3.1. Demonstrate knowledge of all layout XML directives and their arguments

What layout XML elements exist and what is their purpose?

To connect different components and manage their interactions, Magento 2 uses XML templates and XML configurations for the page.

XML template serves to position the containers on the page, as well as set the view and structure options.

XML configuration distributes each block separately among the containers and assigns its configurations to each.

Below is the example of XML file:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
       <referenceContainer name="columns.top">
           <container name="category.view.container" htmlTag="div" htmlClass="category-view" after="-">
               <block class="Magento\Catalog\Block\Category\View" name="category.image" template="Magento_Catalog::category/image.phtml"/>
               <block class="Magento\Catalog\Block\Category\View" name="category.description" template="Magento_Catalog::category/description.phtml"/>
               <block class="Magento\Catalog\Block\Category\View" name="category.cms" template="Magento_Catalog::category/cms.phtml"/>
           </container>
       </referenceContainer>
       <referenceContainer name="content">
           <block class="Magento\Catalog\Block\Category\View" name="category.products" template="Magento_Catalog::category/products.phtml">
               <block class="Magento\Catalog\Block\Product\ListProduct" name="category.products.list" as="product_list" template="Magento_Catalog::product/list.phtml">
                   <container name="category.product.list.additional" as="additional" />
                   <block class="Magento\Framework\View\Element\RendererList" name="category.product.type.details.renderers" as="details.renderers">
                       <block class="Magento\Framework\View\Element\Template" name="category.product.type.details.renderers.default" as="default"/>
                   </block>
                   <block class="Magento\Catalog\Block\Product\ProductList\Item\Container" name="category.product.addto" as="addto">
                       <block class="Magento\Catalog\Block\Product\ProductList\Item\AddTo\Compare"
                              name="category.product.addto.compare" as="compare"
                              template="Magento_Catalog::product/list/addto/compare.phtml"/>
                   </block>
                   <block class="Magento\Catalog\Block\Product\ProductList\Toolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
                       <block class="Magento\Theme\Block\Html\Pager" name="product_list_toolbar_pager"/>
                   </block>
                   <action method="setToolbarBlockName">
                       <argument name="name" xsi:type="string">product_list_toolbar</argument>
                   </action>
               </block>
           </block>
           <block class="Magento\Cookie\Block\RequireCookie" name="require-cookie" template="Magento_Cookie::require_cookie.phtml">
               <arguments>
                   <argument name="triggers" xsi:type="array">
                       <item name="compareProductLink" xsi:type="string">.action.tocompare</item>
                   </argument>
               </arguments>
           </block>
       </referenceContainer>
       <referenceBlock name="page.main.title">
           <arguments>
               <argument name="id" xsi:type="string">page-title-heading</argument>
               <argument name="add_base_attribute_aria" xsi:type="string">page-title-heading toolbar-amount</argument>
           </arguments>
           <block class="Magento\Catalog\Block\Category\Rss\Link" name="rss.link" template="Magento_Catalog::category/rss.phtml"/>
       </referenceBlock>
   </body>
</page>

These files have the .xml extension and are located at the layout folder of the module (module_name/view/frontend/layout).

The main layout elements are blocks and containers.

Template containers can contain blocks, and their aim is to effectively position them inside the page. The following DOM elements are the most common containers:

  • head;
  • header;
  • main;
  • aside (left or right).

These elements divide the page template into the containers, in which we will place our blocks. By default, Magento 2 has five page template types:

  • empty (page without containers);
  • 1 column (one container for content);
  • 2 column with left bar (container for content and a left sidebar);
  • 2 column with right bar (container for content and a right sidebar);
  • 3 column (3 containers optionally).

Magento 2 Certified Professional Front End Developer Guide Screenshot 16

The highlighted elements at the picture above are the containers in which we can insert any blocks we wish. The placement of blocks within itself is the main distinguishing feature of the <container> element, however, it is worth noting that, if necessary, the <block> element can also contain other elements and even containers, and thereby it automatically becomes a container for its child element.

Based on everything said above, one can get an impression that <container> and <block> elements are identical to each other. However, there is sufficient difference between them in realization and operating methods (this will be explained further in the text).

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
       <referenceBlock name="page.main.title">
           <arguments>
               <argument name="id" xsi:type="string">page-title-heading</argument>
               <argument name="add_base_attribute_aria" xsi:type="string">page-title-heading toolbar-amount</argument>
           </arguments>
           <block class="Magento\Catalog\Block\Category\Rss\Link" name="rss.link" template="Magento_Catalog::category/rss.phtml"/>
       </referenceBlock>
   </body>
</page>

In the piece of code above we used xml tags <page> and <body> to configure containers for our page, and their syntax is very similar to <html> syntax. The same as in HTML markup, all tags must be closed (in the example above, we used </page> and </body> closing tags) or they can be self-closing, like <block name=”blockName”/> tag.

All elements can have special attributes for their parameters management. For blocks and containers, the list of attributes and their purpose is similar:

Block and container common attributes

AttributeValueDescription
name0-9, A-Z, a-z и (-)(_)(.)

*Should begin with a letter

name=”current_name”

A unique name for addressing is recorded.
before(-) displays the element before all in the current block or container

(element name) element display before the element with the specified name

() when the parameter is absent, the element is considered not positioned and is displayed in the order set by the current template

before=”-”

Applied to position elements inside the page template or inside the container itself.
after(-) element display after all in the current block or container

(element name) element display after the element with the specified name

() when the parameter is absent, the element is considered not positioned and is displayed in the order set by the current template

after=”target_elemement”

Applied to position elements inside the page template or inside the container itself.

Has priority over before.

as0-9, A-Z, a-z и (-)(_)(.)

*Should begin with a letter\

name=”current_allias”

The set name serves to identify the current element in the parent.
cacheabletrue, false

cacheable=”false”

Enables and disables the caching of the pages which contain elements with the current attribute; the attribute is necessary for creation of the dynamic elements, widgets and pages.

Attribute values and their functional load is identical for blocks and containers as well.

However, containers have the methods that are inherent for them solely. Below is the table of the main attributes together with their unique values:

Container attributes

AttributeValueDescription
output0 / 1 or true / false

output=”1”

Is set to determine whether it is necessary to render the parent container, which contains a false element by default.
HtmlTagHtml 5 tags (aside, main, div …)

HtmlTag=”div”

Everything that is inside the container will be displayed to the user inside the specified tag.
htmlId0-9, A-Z, a-z и (-)(_)(.)

*Functions only when the HtmlTag value is set

htmlId=”current_id_name”

html Id selector is set for the specified wrap.
htmlClass0-9, A-Z, a-z и (-)(_)(.)

*Functions only when the HtmlTag value is set

htmlClass=”current_class_name”

html class selector is  set for the specified wrap.
labelAny valueA voluntary container name is set for display in the browser.
layoutThe name value of the page layout template

layout=”grid_name”

It is written to indicate an explicit indication of the applicable template grid for the current layout.

*the values are not required

Let us also consider the parameters for specifying in the attributes, inherent to blocks only:

Block attributes

AttributeValueDescription
classThe path to the class and the class name:

class=”Vendor\Folder_Name\Block\Class_Folder\Class_Name”

The path to the class that is responsible for processing information for the current block of the template is indicated. It is applied to indicate its handler for a new element or to overwrite the current handler for a program block with a user one.
templateThe path to the template and the template name:

template=”Vendor_Name::folder_template/name_template.phtml”

Specified the path to the template, which is responsible for rendering the information for the current layout block. It is applied to specify a template for the new element or override the default template for the user one.

For blocks, the “class” attribute is required for Magento 2.1 version and earlier.

For containers, the “name” attribute is required for Magento 2.1 version and earlier.

What is the purpose of the attributes that are available on blocks and other elements?

An additional tool for working with layout XML files and page configurations in Magento 2 are the so-called instructions, which can be attributes of elements or new elements. These include the <block> and <container> tags, as well as a number of additional tags. Below is a list of the main ones.

ReferenceBlock and referenceContainer

The instruction that applies to a block or container correspondingly in order to pass the necessary parameters using the following attributes:

AttributeValueDescription
nameThe name of the destination block or containerSpecified the name of the block or container to which the instructions will be passed.
removetrue/falseRemoves or cancels removal of the current block or container. When a container is removed, all child elements are deleted as well.
displaytrue/falseTurns on or off the rendering off on the page of the current container or block. When an element is disabled, the further possibility of configuring it and its child elements remains.

Nested attributes

Magento 2 has several attributes that can be nested; their syntax is similar to the containers and blocks declaration and looks the following way:

<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
   <move element="category.cms" destination="page.wrapper" after="category.view.container"/>
</layout>

Example of move instructions to override the position of the ‘category.view.container’ container

Move

Move is a perfect assistant for positioning elements at the page and migrating it from a container to a container.

Let us consider the example of title block migration that displays the current tab in the user account above the main container:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" >
   <body>
       <move element="page.main.title" destination="main" before="-"/>
   </body>
</page>

Migration of title block from account-nav into main container

Magento 2 Certified Professional Front End Developer Guide Screenshot 17
Before
Magento 2 Certified Professional Front End Developer Guide Screenshot 18
After

Using a single command in the layout, we can easily modify the whole pages structure without using styles and templates. The instruction includes the following attributes:

  • element – the name of the target element for passing the instruction;
  • destination – the name of the parent element that will perform the moving;
  • as – an alias name for the element; set after the element is moved;
  • after/before – used for positioning inside the target parent element.

Remove

It allows to remove static resource elements, like blocks with script files connection and styles in <head> container.

Below is the example of such modification:

<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
   <head>
       <remove src="css/style-m.css"/>
   </head>
</layout>

Removal of the previously connected mapping CSS file

Update

The attribute is recommended to apply in cases when you need to duplicate one or several containers and blocks from the parent page template.

The instruction is specified in the beginning of XML template and applied with handle attribute, in which the path and parent template filename is set. This method has similar functionality to the super() method in the prototype-oriented programming and performs the same functions. The target template file will be updated recursively, or in a sequential order.

For example, you need to connect a slider with certain information to a number of pages in your project. In this case, we need to create a template file with XML markup, which is necessary for connecting a slier. It may look the following way:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
       <referenceContainer name="page.wrapper">
           <!--rev slider-->
           <container name="page.index.slider.container" htmlTag="div" htmlClass="page-slider-container" before="main.content">
               <block class="Nwdthemes\Revslider\Block\Revslider">
                   <arguments>
                       <argument name="alias" xsi:type="string">Midleton</argument>
                   </arguments>
               </block>
           </container>
       </referenceContainer>
   </body>
</page>

Example of page template with slider connection

Further, we can apply this template as a prototype for the child files. To do this, set the path to the parent template file in the update directive of each target document.

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
       <update handle="{name_of_handle_to_include}"/>
       <!-- CONTENT -->
   </body>
</page>

Recursive template update

This way, our slider will display at each page where the update directive with slider connection file as a prototype is specified.

Argument

This tag is used to pass arguments to a block or container. It contains a required name and type tags. Type contains the passed element’s type:

  • string;
  • boolean;
  • object;
  • number;
  • null;
  • array.

For example, earlier we moved the title from the header container into main in the user account, and now we need to set a custom string for the main tab myDashboard. For this, we open the template, responsible for myDashboard page and using action directive and setPageTitle method, we pass as an argument the string with the title we want our page to have:

<referenceBlock name="page.main.title">
   <action method="setPageTitle">
       <argument translate="true" name="title" xsi:type="string">Hello, Customer!</argument>
   </action>
</referenceBlock>

Passing the parameter as a string for page-title

We set string for the type and the necessary text we passed as a string. Due to all this, we got the desired result.
Magento 2 Certified Professional Front End Developer Guide Screenshot 19

Also, the passed values can be obtained from the current template file using get() method. This functionality perfectly corresponds to the modularity principle in Magento. Using it, you can create a universal but dynamic template and use it in several places in our store, just like with the example of a universal layout with connecting a slider on pages, using the update method inheritance.

As an example, consider the creation of a template with a button rendering and any functionality on the client. The dynamism will lie in the fact that on different pages we will use the same template, but depending on the requirements, in the page template file, we can pass a css class to it, to which some style from the stylesheet can be attached or even a functional load implemented on js. In the markup, it will look the following way:

<block class=”Magento\Framework\View\Element\Template" name="button" template="Magento_Theme::buttons/dynamic_button.phtml" >
   <arguments>
       <argument name="css_class" xsi:type="string">white</argument>
   </arguments>
</block>

Passing of a custom argument into the template

To pass the class, we declare our block and set our template in the template attribute. Then we simply pass any parameters to our template as arguments, and <arguments> container and <argument> blocks enclosed in it are used to pass several parameters . We passed our class with an argument and the name css_class, in order to get it in the template file, we need to resort to php knowledge and write the following construction:

$_className = $block->getCssClass();

<div class="actions-toolbar <?= $_className ?>">
   <button class="action primary">Button</button>
</div>

Example of the method for getting the argument, passed from the template

Then, depending on the logic we set, the button can take different modifications from page to page; in this example, it is white.
Magento 2 Certified Professional Front End Developer Guide Screenshot 44

In fact, this is the simplest example of using this functionality, which is necessary to familiarize yourself with the principle of its operation. If we limit ourselves only to our imagination, then applying the method of passing arguments, you can do many things, up to passing an argument that will determine the controller for processing our template.

Arguments can be different and have different names, and you can pass not only a string, but, as previously stated, 6 basic data types. In order to get the attributes in the template, the function takes the following form:

getCssClass();

The name parameter passed in xml in the form of “css_class” takes the form of CamelCase and looks like “СssClass”. This method is similar to the method of passing arguments  using data attributes, applied in JavaScript.

3.2. Describe page layouts and their inheritance

How can the page layout be specified?

To select a page layout for a certain page, log in to the admin panel and navigate at the following path for the settings:

Content ⇒  Pages ⇒ Target_Page_Edit ⇒ Design ⇒ Layout
Magento 2 Certified Professional Front End Developer Guide Screenshot 22

Another way to change the page layout is by applying an XML layout of the target page. For this, we can use a special layout attribute for <page> container, in which we will specify the layout we want to apply to the page:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
	// Page layout handles // 
   </body>
</page>

Specify the page layout from which you inherit in  <page> tag of the layout attribute. As a result, the module page with this layout file will have a one column grid; the same as the default Magento 2 theme Luma uses for the main page, but with custom additions and modifications inside the <body> tag.

What is the purpose of page layouts?

The main purpose of page layouts is to create a structured and united set of template layouts for the page display.

If we apply any of the standard layouts to the main page of the default Luma theme, we get the following results:

Magento 2 Certified Professional Front End Developer Guide Screenshot 49
1 column
Magento 2 Certified Professional Front End Developer Guide Screenshot 46
2 columns with left sidebar
Magento 2 Certified Professional Front End Developer Guide Screenshot 47
2 columns with right sidebar
Magento 2 Certified Professional Front End Developer Guide Screenshot 48
3 columns

It is worth mentioning that module-checkout uses a default empty template in the structure of the pages, but modified, and its markup will look the following way:

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
   <update handle="empty"/>
   <referenceContainer name="page.wrapper">
       <container name="checkout.header.container" as="checkout_header_container" label="Checkout Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content">
           <container name="checkout.header.wrapper" label="Checkout Page Header" as="checkout_header_wrapper" htmlTag="div" htmlClass="header content"/>
       </container>
   </referenceContainer>
   <move element="logo" destination="checkout.header.wrapper"/>
</layout>

How can a custom page layout be created?

By default, the standard layout files are located at the following path:

vendor ⇒ magento ⇒ module-theme ⇒ view ⇒ frontend ⇒ page_layout

Here stored the layout files that we examined above:

Magento 2 Certified Professional Front End Developer Guide Screenshot 31
Default files in the file system

This is how they look in the admin panel:

Magento 2 Certified Professional Front End Developer Guide Screenshot 32
Default grid alternatives in the admin panel

In order to apply the custom template file to the custom theme, apply template files at the following address:

app ⇒ design ⇒ [vendor_name] ⇒ [module_theme] ⇒ Magento_Theme ⇒ page_layout

For example, many store pages will have two-column structure, without a side menu and breadcrumbs. Therefore, it would be reasonable to create a custom template (let’s call it 2columns-not-breadcrumbs.xml and place it at the path we specified above) with the following markup in it:

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
   <update handle="2columns-left"/>
   <referenceContainer name="page.wrapper">
       <referenceBlock name="breadcrumbs" remove="true"/>
   </referenceContainer>
   <referenceContainer name="columns">
       <referenceContainer name="div.sidebar.main" remove="true"/>
   </referenceContainer>
</layout>

Example of the page with inheritance template markup

Then, all we need is to apply it to all the pages we need.

In the markup we described above, we applied the method of inheritance from the parent layout. The update directive passes the handle attribute with the layout template name value, which is the same as in the vendor folder of the standard theme, but without “.xml” extension:

Magento 2 Certified Professional Front End Developer Guide Screenshot 33
How the pages layouts are displayed in the vendor folder

The newly created layout file will recursively adapt the parent markup during the inheritance process, yet it will change all the overridden blocks for the ones set in the child file.

To complete the creation of the custom page layout, declare it in the layout configuration file. In the standard Magento module, it is located at the following path:

vendor ⇒ magento ⇒ module-theme ⇒ view ⇒ frontend ⇒ layouts.xml

To save it for further work with the composer, place it in the theme file:

app ⇒ design ⇒ [vendor_name] ⇒ [module_theme] ⇒ Magento_Theme ⇒  layouts.xml

Then, in layouts.xml file template, using the <layout> tag, pass the displayed template name by wrapping it in the <label> tag and, using id attribute, set the value that will be applied at the client side:

<?xml version="1.0" encoding="UTF-8"?>
<page_layouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/PageLayout/etc/layouts.xsd">
   <layout id="2columns-not-breadcrumbs">
       <label translate="true">2 columns without breadcrumbs</label>
   </layout>
</page_layouts>

Enhancement of layout configuration file

In the end, we will see a similar result at the admin panel:

Magento 2 Certified Professional Front End Developer Guide Screenshot 34
A custom grid in the admin panel

The passed id attribute for tag will be the value of a new layout.

Magento 2 Certified Professional Front End Developer Guide Screenshot 50
The displayed value at the client side

This is not the only way to override or overwrite the layout file. In the example above described the way to create a custom layout file for all the shop pages; you can also overwrite the existing current layout file the same way by applying the necessary modifications to it. For example, we can create a one-column layout, but without breadcrumbs:

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
   <update handle="empty"/>
   <referenceContainer name="page.wrapper">
       <container name="header.container" as="header_container" label="Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content"/>
       <container name="page.top" as="page_top" label="After Page Header" after="header.container"/>
       <container name="footer-container" as="footer" before="before.body.end" label="Page Footer Container" htmlTag="footer" htmlClass="page-footer"/>
   </referenceContainer>
   <referenceContainer name="breadcrumbs" remove="true" />
</layout>

File template markup for overriding the standard one-column layout

Placing the file in the theme folder with the name of the target layout and current markup, we have it applied to all the store pages, where this type of grid is used. So, in this case, all the pages that use the one column layout file as a template will use the new overwritten copy of it. Bear in mind that, according to the described above inheritance rules and all the priorities, all the layout files that are located in the current theme and inherited from 1 column layout, will have the overwritten file as the parent.

Magento 2 Certified Professional Front End Developer Guide Screenshot 35
Position of the template file for override of the 1 column template

Where are the existing page layouts used?

Magento 2 has 5 default page layout files; using the Luma theme as an example, let us examine what store pages they are applied on.

  • empty (page without containers)
    checkout pages (update from empty)
  • 1 column (one common column for the content)
    home page,product-view, all-cms-pages, cart, login-page, success page
  • 2 column with left bar  (content container and a left aside bar)
    what-is-new, category-view, subcategory-view, account-pages
  • 2 column with right bar (content container and a right aside bar)
  • 3 column (3 containers optionally)

How can the root page layout be specified for all pages and for specific pages?

As we have already mentioned, we can apply one of the existing or created page layouts (from page_layout folder) using <page> layout tag directive. This can be done for certain pages as well as for all the website pages. For example, we can apply the layout page file for all the catalog products (using catalog_product_view.xml file), while we also can apply it only for a certain product by using its ID (in catalog_product_view_id_xxx.xml file, where xxx stands for product id) or for a product of a certain type (for example, catalog_product_view_type_simple.xml file is used for simple product type).

3.3. Demonstrate understanding of layout handles and corresponding files

What is the purpose of layout handles?

Handle is the tag similar to the <block> and <container>, inserted into theme xml configuration with an aim to target the application of the nested instructions to a certain page or element category.

Handles can have the form of not only tags in xml configuration, but separate files placed in layout modules’ folder as well. The example of such file:
catalog_product_view_id_112.xml.

This method is more useful for mass modifications, when there are too many records in one descriptor to place it in a common document. Also, this way is better for data structuring. Instead of searching through one large document with a number of descriptors, looking for the one you need, you can create an orderly data structure in the file system, where looking for the needed descriptor will be a simple task.

How can the available layout handles for a given page be determined?

In order to determine how to set the descriptor name for the custom page or help find the tag of the existing, let us get into the details of its name creation. This is what we use as an example:
<cms_index_index>

cms – route identifier.

It is applied to compare the URL addresses with the controller from the module folder which is responsible for the given descriptor. In this case, this is a standard CMS-module.

Bear in mind that the final URL address сan be re-assinged,while the current one is used solely for working with a controller.

  • index – the folder on the physical path to the controller
  • index – controller file

When we examine the directory structure in the module folder more closely, the principle of descriptor forming becomes clear:

Magento 2 Certified Professional Front End Developer Guide Screenshot 36
Module-cms controller structure

This principle is embedded in forming of any name, so knowing it will significantly simplify the descriptor search for the needed page. However, in case a developer needs help with searching for a new descriptor or in the situation when it is unclear what layout file has a priority over the given page, there is a more reliable way of displaying all the current descriptors directly at the screen. Add the following php script to any template file connected to the needed page:

<?php var_dump ($block -> getLayout() -> getUpdate() -> getHandles())?>

PHP script for displaying all the descriptors for the current page

Taking the default Luma theme homepage as an example, let us have a look on what we got:
Magento 2 Certified Professional Front End Developer Guide Screenshot 37

Each template has a method that allows to get the name of the root file template:

getLayout()

On this page, it’s default.xml, then using the method:

getUpdate()

We get the list of the layout files from which inheritance is performed (cms_index_index and cms_page_view) with the method:

getHandles()

As a result, we get cms_index_index_id_home descriptor.

It is worth mentioning that they are listed according to their priority.

How do you add a new layout handle?

To create a new custom layout handle, use in the new layout file the handle directive we are already acquainted with:

<update handle = "handle_name" />

When the Layouts cache is disabled, we can use a new descriptor name for working with layouts.

What are the most commonly used layout handles?

Below is a table with the most commonly used layout handled:

XML descriptorTarget categorySource
<default>All pagesdefault.xml
<cms_index_index>Main page of the websitecms.xml
<catalog_category_default>Product categoriescatalog.xml
<customer_account>Customer accountcustomer.xml
<catalog_product_view>Product view pagecatalog.xml
<cms_page>Custom pages created with WYSIWYG editor ir in a file system, or so called CMS pagecms.xml
<1column>

<2column>

Only the pages with the target grid type1column.xml

2column.xml

catalog_product_view_type_simple(configurable)Configured or simple product view pagescatalog.xml
catalog_product_view_id_(number_id)

catalog_product_view_sku_(number_sku)

View pages of the product with a certain ID or SKU numbercatalog.xml

Layout descriptor type

How can layout handles be used during theme customization?

Layout handles are applied to group layout instructions for certain pages and elements. This is a very useful functionality, for it allows to quickly create and configure page and page elements structure. It can be applied for a number of similar product pages as well as for the selected pages.

For example, we use layout handle  catalog_product_view.xml for all the products in the catalog. Let us imagine we want to add a CMS block for all simple product pages. For this, we use layout handle catalog_product_view_type_simple.xml. Or, let us imagine another situation, when we wish to modify the layout of a single page; for this, we will use layout handle catalog_product_view_id_112.xml.

3.4. Understand the differences between containers and blocks

What is the purpose of blocks?

Content is added to containers by means of blocks, which are files with templates, in which html code is generated. Site navigation, product list, category list, footer links are some of the most frequently used page blocks.
Magento 2 Certified Professional Front End Developer Guide Screenshot 38

What is the purpose of containers?

Containers are what page framework is built from. They are the basic elements of Magento page structure. Header, footer, left sidebar, main column are the main containers of a Magento webpage.
Magento 2 Certified Professional Front End Developer Guide Screenshot 39

How can containers be used in theming?

Containers make up the page framework. They can contain child elements, such as blocks and other containers, but can stay empty as well. Here you can see an example of a container and block applied in layout:

<container name="category.view.container" htmlTag="div" htmlClass="category-view" after="-">
<block class="Magento\Catalog\Block\Category\View" name="category.image" template="Magento_Catalog::category/image.phtml"/>
<block class="Magento\Catalog\Block\Category\View" name="category.description" template="Magento_Catalog::category/description.phtml"/>
<block class="Magento\Catalog\Block\Category\View" name="category.cms" template="Magento_Catalog::category/cms.phtml"/>
</container>

Containers have their own attributes that allow you to manage it. Let us briefly examine each of them.

  • Name.  An obligatory attribute. This identifier can be used to address a certain container. Name attribute should be unique within a single page. This attribute could be compared with id for html tags.
  • Label. The signature that will be displayed in the browser.
  • Before/after. These attributes allow placing the current container before or after an element, which name is specified in this attribute. If the attribute has “-” value, then the container is placed according to the first or last one on its level of nesting.
  • As. Assigns with an alias, on which the current container is identified in the range of its parent.
  • Output. Defines whether to output the root element.
  • Html Tag. Specifies which tag to use to wrap a container.
  • HtmlId. Specifies id attribute value for a tag that wraps a container.
  • HtmlClass. Specifies class attribute value for the tag that wraps a container.

How can blocks be used in theming?

Blocks are applied to output a content according to the template. In the code we placed above, you can see how are the blocks displayed in the layout file. Each block, as well as a container, has its own attributes, that allows to manage it. Let’s consider these attributes.

  • Class.  Specifies a class on which rendering of this block is implemented.
  • Name. This attribute is obligatory. This is an identifier which can be used to address to the certain block. Name attribute should be unique within a single page. This attribute could be compared with id for html tags.
  • Before/after. These attributes allow placing the current block before or after an element, which name is specified in this attribute. If the attribute has “-” value, then the block is placed according to first or last on its level of nesting.
  • Template. Specifies a path to a template of the current block.
  • As. Assigns with an alias, on which the current block is identified in the range of its parent.
  • Cacheable. Decides whether to cache the current block or not.

What is the default block type?

Block type is defined by “class” attribute.

For example, for <block class=”Magento\Framework\View\Element\Template” name=”store_account” template=”Magento_Theme::html/account.phtml”/> block it will be class=”Magento\Framework\View\Element\Template”.

In this attribute, we set the name of the class that realizes the block rendering. The object of this class is responsible for the block output visualization. The default block class in Magento 2: “Magento/Framework/View/Element/Template”.

There are other classes in Magento as well; moreover, you can create a custom class. Bear in mind that all custom classes should extend from the default class. To view the file content for the class, follow the path “/vendor/magento/framework/View/Element/Template.php”.

Or go to github – https://github.com/magento/magento2/blob/2.2-develop/lib/internal/Magento/Framework/View/Element/Template.php

How can the order of rendered child blocks be influenced both in containers and in blocks?

There is a Before/after attribute both for container and blocks. This attribute sets the order in which blocks and containers are displayed on a page.

3.5. Describe layout XML override technique

How can layout overriding be used in theming?

Typically, the extension of the file layout is good enough to solve most of the development tasks. However, if you need to make a lot of changes or the layout file contains an instruction that can not be changed in the file extension, then the only option left will be to override such file.

How can layout XML be overridden?

To perform overriding, create an overriding layout file in the directory of your theme. You can override base layouts and theme layouts as well. The mechanism is pretty similar, but there are still some differences. Let us consider the examples to understand the processes better.

Creating overriding base layout file

For instance, we need to override base file checkout_cart_index.xml in Checkout_Module (see the picture below)
Magento 2 Certified Professional Front End Developer Guide Screenshot 40

For that, we must create a file with the same name in our theme directory:
Magento 2 Certified Professional Front End Developer Guide Screenshot 41

Similarly, it is possible to do so for other modules.

Creating overriding theme layout file

For example, we need to override checkout_cart_index.xml file in Magento_Checkout module of parent theme.
Magento 2 Certified Professional Front End Developer Guide Screenshot 42

To achieve that, we must create a file with the same name in our theme directory:
Magento 2 Certified Professional Front End Developer Guide Screenshot 43

Similarly, it is possible to do the same for the other modules.

What are consequences of layout overrides during upgrades?

When Magento is updated, the layout modules’ root files can be updated as well. New blocks and containers may appear in them and can be referenced by other modules. If you have overridden a file where such blocks or containers appeared during the update, the modules referring to these elements can not access them, which will lead to errors in the operation of the modules and eventually hinder their functionality. In order to avoid this, you will be forced to add these new elements to your overriding layout file. You need to remember this when you override some layout file in your theme and are going to update Magento after that.

What is the effect of layout overrides on compatibility?

Overriding layout files provides ample opportunities for flexible theme customization. However, you need to remember that the overridden layout file is not affected by any changes to the main files, which in turn can lead to future problems with upgrade if you do not keep a close watch on the updated files.

Therefore, overriding should be used very carefully and only when it can not be done without.

Here are some guidelines that we want to share with you:

  • Use overriding in case you can not afford the desirable effect through extending;
  • Do not change names and aliases of blocks;
  • Do not change handle inheritance.

3.6. Understand layout merging

What is layout merging?

To explain the notion of layout merging, let us consider its process. First, all layout XML files are united into one XML document with “_loadFileLayoutUpdatesXml”. Then, all layout instructions for certain handles are found with “_fetchPackageLayoutUpdates” method and merged. As a result, we get a final XML document. Magento reviews this document and creates PHP classes for each block. Afterward, the result for each certain page is rendered, forming the html-tree of the page and adding css-styles and JavaScript files.

Bear in mind that during the process of layout merging, the layouts are merged in a certain order. The order is determined by the modules loading order (to learn more about it, follow the link https://devdocs.magento.com/guides/v2.2/extension-dev-guide/build/module-load-order.html). In the “app/etc/config.php” file, you can also see the order in which the modules are currently loaded. In case when in layout files two or more conflicting instructions from different modules meet, then the upper hand has the instruction whose module is loaded the latest.

What is also worth mentioning in the context of layout merging is layout files extending and overriding. When we create extending layout file, it will complement the file that it extended. In case the extending file will contain the instructions that contradict the initial file instructions, the contradicting ones will be overridden during the layout merging. For example, when the initial layout file had the following instruction

<move element=”form.subscribe” destination=”footer_row” after=”footer_column_4″/>

And the file from our theme, that extended the initial file, will have the following instruction:

<move element=”form.subscribe” destination=”footer_row” after=”footer_column_5″/>

As a result, the “form.subscribe” element will be placed into a “footer_row” after  “footer_column_5” element, not the “footer_column_4” one.

In case we use overriding layout files, then the initial file that we have overridden is not included into the layout merging at all. Still, one must use overriding carefully; otherwise, certain issues may occur during Magento update (learn how to override a layout in Magento 2 in our article).

On the surface of it, it may be unclear how the final merged XML should look like. To see the layout merging merging, do the following:

  • Enter the “magento\framework\View\Result\Page.php” file;
  • Find $output = $this->renderPage() line in render() method;
  • Add the $output .= $this->getLayout()->getXmlString() command after this line.

Afterward, go to your store’s front end and find the final XML for a certain page in the “Source” folder in the browser development instruments (after <html> tag).

How do design areas influence merging?

After the request to the current page (either front end or admin panel) is received, Magento first merges layout files into the base area and then into the area applied to the current request (frontend or adminhtml correspondingly).

For the sake of clarity, let us overview the general order of layout merging:

  1. Basic module files are loaded.
  2. Request area modules are loaded (frontend or adminhtml).
  3. Theme (basic, parent or current) files are loaded. The more recent the theme is, the higher priority its instructions have during extending and overriding files. The current theme has the highest priority.

How can merging remove elements added earlier?

The “remove” attribute for “referenceBlock” and “referenceContainer” tags correspondingly is applied to remove the elements added earlier.

It looks the following way:

<referenceBlock name=”breadcrumbs” remove=”true”/>

and

<referenceContainer name=”header.container” remove=”true”/>.

What are additive changes and what are overriding changes during layout merging?

Additive changes is adding new elements to the existing XML elements (for example, adding new arguments to the existing element). Overriding changes, in its turn, is when you change the existing element for a new one (for example, the current argument value for a custom one).

Let us demonstrate additive changes with the following example.

For instance, we have “register-link” block with “label” attribute that has “Create an Account” value:

<block class="Magento\Customer\Block\Account\RegisterLink" name="register-link">
	<arguments>
		<argument name="label" xsi:type="string" translate="true">
Create an Account
</argument>
</arguments>
</block>

To add a new “test-argunemt” argument for “register-link” block, add the following code to your existing layout file:

<referenceBlock name="register-link">
<arguments>
<argument name="test-argunemt" xsi:type="string" translate="true">
Value Test Argument
</argument>
</arguments>
</referenceBlock>

Below is the example of overriding changes.

To modify the existing “label” argument for the “register-link” block, write the following code in existing layout file:

<referenceBlock name="register-link">
<arguments>
<argument name="label" xsi:type="string" translate="true">
New label value
</argument>
</arguments>
</referenceBlock>

 

3.7. Understand processing order of layout handles and other directives

In what order are layout handles processed?

First, default.xml handles of all modules are loaded, regardless of that website page is loaded at the moment (the order of default.xml handle merger for the corresponding modules will be outlined in the next paragraph). Then, the rest of the handles are loaded in the order they are called for a certain page.

The order of handle calls corresponds to the order in which the handles are added to Merge class (you can see the class file here – https://github.com/magento/magento2/blob/2.2-develop/lib/internal/Magento/Framework/View/Model/Layout/Merge.php).

In this file, load() method reviews and merges all the connected layout handles. Also, bear in mind that handles can be added to other handles via the layout instruction update. In this case, the content of the added handle will be added to the layout handle.

In what order is layout XML merged within the same handle?

In short, Layout XML is merged in the order in which the corresponding modules are loaded. In case two conflicting layout instructions from different modules meed, the one from the most recently loaded module will have the priority. If the same-name layout files meet in several inherited themes, they will be merged, and in case the layout instructions conflict occurs, the theme closest in terms of inheriting to the current theme will have priority over all (the maximum priority has the current theme).

Get to know more about Magento 2 layout merging in our blog.

How can the processing order be influenced?

As it was mentioned before, the order of layout instruction execution is determined by the order of modules loading. Therefore, when you change the order of modules loading, you influence the layout instructions execution. The order of modules loading is determined by the <sequence> parameter in <Module_folder>/etc/module.xml module file.

To learn more, follow the link: https://devdocs.magento.com/guides/v2.2/extension-dev-guide/build/module-load-order.html

Using plugins, you can also embed your layout handles into any place of the layout handles loading process. For example, you can add a custom layout handle before the handle of the catalog category page is loaded – catalog_category_view. For this, create a corresponding before plugin.

To learn more about creating such plugins, follow the link: https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/layouts/xml-manage.html#layout_markup_modify_with_plugins

What are common problems arising from the merge order of layout declarations?

If you follow all given recommendations for working with layout files, then no problem will occur with merging. However, one can make an error due to the lack of attention during the development. Let us consider the most common mistakes that occur this way.

  1. Blocks and containers naming. When you make a mistake in the name of a block or container you want to override or create, you do not get the result you intended for and created additional errors instead. Here are a couple of typical examples of this error:
    – You mistakenly name the new block with the name of the existing block. As a result, the existing block is deleted.
    – You want to override the existing block and create a new block with the same name as the existing, but you make a mistake in spelling and simply create a new block.
    – You want to add a block into the existing container, but you make a mistake and the block is not added anywhere (if there is no container with such a name), or added into the container where you did not want it to be.
  2. When you remove or rename certain blocks during the layout files overriding, errors can occur due to the fact that the blocks will be used in other layout files and will not be accessible to you. Keep this in mind when you decide to override a layout file.

3.8. Set values on block instances using layout XML arguments

How can arguments be set on blocks?

The arguments can be set on blocks with the help of the following code in layout:

<arguments>
    <argument name="..." xsi:type="...">
       ...
    </argument>
</arguments>

For examples, to set an argument named “example_argument” with the value “Example argument value” on a block named “example-block”, you should use the following code in layout:

<referenceBlock name="example-block">
      <arguments>
          <argument name="example_argument" xsi:type="string">
             Example argument value
          </argument>
      </arguments>
</referenceBlock>

Get more details in this article in the section “Argument”:

https://belvg.com/blog/layout-xml-directives-and-their-arguments-in-magento-2.html

Which data types are available?

The following data types are available for an argument:

  • string
  • boolean
  • object
  • number
  • null
  • array

Get more details in this article in the section “Argument”:

https://belvg.com/blog/layout-xml-directives-and-their-arguments-in-magento-2.html

What are common arguments for blocks?

Let’s take a look at the most common arguments for blocks and discuss where you can use them:

css_class – it is used to set a “class” attribute on element.

Example:

Let’s say you want to add a class “product-test-example” to the title of the product page.

In order to do it, you need to add the following code in your theme (file app/design/frontend/Example_Vendor/Example_Theme/Magento_Catalog/layout/catalog_product_view.xml) in product page layout:

<referenceBlock name="page.main.title">
     <arguments>
         <argument name="css_class" xsi:type="string">product-test-example</argument>
     </arguments>
</referenceBlock>

As a result, the title of the product page acquires a class “product”:

<div class="page-title-wrapper product-test-example">
     <h1 class="page-title">
         <span class="base" data-ui-id="page-title-wrapper" itemprop="name">
            Product example name
         </span>    
     </h1>
</div>

title – it is used to set titles on different blocks.

Example:

Let’s say you need to change the title of the section with the full description on the product page. In order to do it, you need to add the following code in your theme (file app/design/frontend/Example_Vendor/Example_Theme/Magento_Catalog/layout/catalog_product_view.xml) in product page layout:

<referenceBlock name="product.info.description">
     <arguments>
        <argument name="title" translate="true" xsi:type="string">Details - Test example</argument>
     </arguments>
</referenceBlock>

As result, the section with the full product description will be titled “Details – Test example”:

Magento-2-Certified-Professional-Front-End-Developer-Guide-Screenshot-44

label – it is used to label different blocks.

Example:

Let’s say you need to change the name of the link to Privacy policy in the footer. In order to do it, you need to add the following code to layout default.xml in your theme (CMS app/design/frontend/BelVG/belvgtheme/Magento_Cms/layout/default.xml):

<referenceBlock name="privacy-policy-link">
     <arguments>
         <argument name="label" xsi:type="string" translate="true">Privacy Policy - Test example</argument>
     </arguments>
</referenceBlock>

As a result, the name of the link in footer will change to “Privacy Policy – Test example”:

Magento-2-Certified-Professional-Front-End-Developer-Guide-Screenshot-45

path – it is used to set the path for different links.

Example:

Let’s say, you want to change the path to the Privacy policy page from the previous example. In order to do it, you need to add the following code to layout default.xml in your theme (for example, module file Theme app/design/frontend/BelVG/belvgtheme/Magento_Theme/layout/default.xml):

<referenceBlock name="privacy-policy-link">
     <arguments>
         <argument name="path" xsi:type="string">privacy-policy-test-example</argument>
     </arguments>
</referenceBlock>

As a result, the site address in footer changes:

<ul class="footer links">
    <li class="nav item">
        <a href="your-site-address/privacy-policy-test-example/">Privacy Policy - Test example</a>
    </li>
...
</ul>

type – it is used to set different block types. Depending on which block type is set, certain block template will be uploaded.

Example:

Depending on which “type” argument is set on the block, the templates for product display will differ:

<referenceContainer name="content.aside">
    <block class="Magento\Catalog\Block\Product\ProductList\Related" name="catalog.product.related" template="Magento_Catalog::product/list/items.phtml">
      <arguments>
         <argument name="type" xsi:type="string">related</argument>
      </arguments>
    ...
    </block>
</referenceContainer>

In the example described above, related products will be displayed according to the template which corresponds to the “related” argument value in the template file:

vendor/magento/module-catalog/view/frontend/templates/product/list/items.phtml”.

Besides the block arguments, there are plenty of other arguments. Moreover, you can create your own argument and use it in templates .phtml with the help of get{ArgumentName}() and has{ArgumentName}() methods, as it was described above.

3.9. Customize a theme’s appearance with etc/view.xml

What is the etc/view.xml file used for?

The etc/view.xml file is located in theme folder:

<theme_folder>/etc/view.xml

Properties of the product catalog’s images, settings of the product catalog’s image gallery and settings of JavaScript bundling are located in this file. We are going to take a closer look at these settings and properties in the next section of our tutorial.

Based on the above, this file is used to set themes, to create and to use custom properties when working with a theme.

How can it be used to customize a theme?

In order to use this file, you need to create it in your theme. For example, in theme Example_Theme of the vendor Example_Vendor, it can be found at:

app/design/frontend/Example_Vendor/Example_Theme/etc/view.xml

After you have created a file in your theme, you can change the properties value and this way customize the theme as you want.

Let’s see what properties are available for us in this file (the example of such a file you can see in the default Blank theme https://github.com/magento/magento2/blob/2.0/app/design/frontend/Magento/blank/etc/view.xml).

In order to change the image properties, you need to use <images module=”Magento_Catalog”>…</images> element content. Elements act as content for this element <image id=”image_id” type=”image_type”>…</image>.

Here is an example of how it looks in the etc/view.xml file:

<images module="Magento_Catalog">
   ...
      <image id="category_page_list" type="small_image">
         <width>240</width>
         <height>300</height>
      </image>
   ...
</images>

Here id and type are attributes of the <image> element.

id is a unique identifier for image properties (it should not be repeated). With the help of this identifier, you can get the image and its properties in the .phtml template.

type is the type of the image. There are the following types in Magento: image, small_image, swatch_image, swatch_thumb, thumbnail. The role of the image in the website page templates depends on the image type (as, for example, the image with the thumbnail type will be used as a thumbnail image –  shrinked view of a picture).

In the example above, width and height are the properties of the <image> element and there can be more of these properties. Let’s take a look at all the available properties of the <image> element:

width is the image width in pixels.

height is the image height in pixels.

constraint property is responsible for how the image acts when its size is smaller than the one set by “width” and “height” properties. Possible values true and false. If the value true is selected, the image will not get bigger up to the required size when it starts losing quality. If the false value is selected, it will do so. By default, the value true is selected.

aspect_ratio property is responsible for whether the aspect ratio of an image will change to match the values set by the “width” and “height” properties. Possible values true and false. If the value true is selected, the image’s aspect ratio will not change. If the false value is selected, it will do so. By default, the value true is selected.

frame property is responsible for whether the image will be cropped to match the values set by the “width” and “height” properties. Possible values true and false. If the value true is selected, the image will not be cropped. If the false value is selected, it will happen. By default, the value true is selected. This property is applicable only if the aspect_ratio property has the the value true.

transparency property is responsible for keeping transparency by the downloaded image. Possible values true and false. If the value true is selected, the transparency remains. If false is selected, the background will be as it is set in background property. By default, the value true is selected.

background is the background color for downloaded images. It is set in rgb format [xxx, xxx, xxx]. By default, the value is [255, 255, 255] which means the white color in rgb format. This property is applicable only if the transparency property has a false value.

In variables in the <vars module=”Magento_Catalog”>…</vars> element, you can set the properties for the image gallery on the product page. It looks like this:

<vars module="Magento_Catalog">
    <var name="gallery">
      ...
         <var name="nav">thumbs</var>
      ...
    </var>
</vars>

In this example, name=”nav” property is responsible for the style of the gallery navigation (there can be thumbnails, dots or just nothing). Here we see thumbnails.

There is a variety of such properties for the gallery. You can find them in the file of one of a standard theme (the property comments will help you find out what they are needed for) or you can read about them here –

https://devdocs.magento.com/guides/v2.3/javascript-dev-guide/widgets/widget_gallery.html

Also, there are settings for JavaScript bundling in the etc/view.xml file. In a nutshell, it is a feature that gathers multiple JavaScript files in one. Eventually, it splits into several set sizes and loads when the website loads. It is necessary to reduce the number of file requests and as a result, to increase page loading speed.

There are the following settings in this file:

  • The list of files which are excluded from JavaScript bundling (They are loaded by a separate request and are not included into output files). This list is in the <exclude>…</exclude> element and the path to every JS file from this list is in the <item type=”file”>…</item> element:
    <exclude>
        <item type="file">path_to_JS_file</item>
    </exclude>
    
  • The size of the file which the output JavaScript file splits into while loading. (It increases the load speed of the output file). The following property is responsible for it:
    <vars module="Js_Bundle">
        <var name="bundle_size">1MB</var>
    </vars>
    

    Here the bundle_size is the size of this file.

Get more details about JavaScript bundling here – https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/themes/js-bundling.html

How can values from etc/view.xml be used during theming?

You can use the value of the properties from etc/view.xml in the .phtml files of module templates.

You can get the value of any property from the etc/view.xml file with the help of getVar() method.

Here is an example. Let’s say you need to get the value type of the gallery navigation. In the etc/view.xml file, this property is set in the following way:

<vars module="Magento_Catalog">
    <var name="gallery">
    ...
      <var name="nav">thumbs</var>
    ...
      </var>
</var>

In the gallery.phtml file, we can get this value in the following way:

$block->getVar("gallery/nav")

You can also create your own variables in etc/view.xml and use them in .phtml template files.

How does theme inheritance influence values from etc/view.xml?

The way inheritance works in Magento for the etc/view.xml files for current and parent themes is similar to the inheritance of extending layout files for current and parent themes. In other words, if there are no variables or properties in the etc/view.xml file of your theme, then Magento will search for these variables or properties in its parent theme and then in the parent theme of the parent theme and so on until it reaches the theme without the parent one. It means that there is no point in copying the etc/view.xml file fully, it should be enough to copy the part which will differ in comparison with your theme’s parent themes. The rest Magento will get from the parent themes.

If the inherited themes will include the properties and variables, the values of which are different, the value which is the closest to the current theme in the inheritance chain will be set (the current theme has the highest priority)

Vlad-Yunusov banner
Vlad-Yunusov

Tell us about your project

Get in touch with our team. Send us an email at [email protected] or call us 1 650 353 2301

Send request