Just like Magento 1, Magento 2 has blocks. For those who don’t know what Magento blocks are: they are classes that template (parts) can use to gain some specific functionality. Blocks are used throughout Magento and are a core part of it’s design and will most likely also be a part of your customisations.
So let’s just see how we can create and use these blocks to their fullest.
Please note that we use the boilerplate module from the article ‘Creating a module in Magento 2‘ as the entry point for this article.
Let’s talk a bit about Magento 2’s layout first
Before we get started with blocks, you need to be familiair with Magento 2’s layout mechanism. This will be discussed more thoroughly in an article later on, but for now there are some core principles you need to know:
- Magento 2’s layout is determined by each individual module (look in the view/frontend/layout -folder of any given module for example).
- In contrast with Magento 1, each Magento 2’s ‘page type’ is determined by it’s own layout XML-file. For example, layout updates that apply to all pages are set in default.xml , but layout updates that are only applied on product detail pages are set in catalog_product_view.xml .
Knowing these 2 rules, create a file called default.xml in the folder view/frontend/layout of your module and add the following content:
1 2 3 4 5 6 7 |
<?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> </body> </page> |
This will be the entry point for our layout updates.
Utilising existing blocks
As I said, Magento already has a whole bunch of blocks that you can already use out of the box. Take a look at any Magento module and look inside it’s Block -folder, and you’ll see the blocks that you can use. For example, if you want to render a static block with the identifier ‘example’ in the footer, we can add the following line inside our <body> -tag in our layout file:
1 2 3 4 5 6 7 |
<referenceContainer name="footer"> <block class="Magento\Cms\Block\Block" name="example.staticblock"> <arguments> <argument name="block_id" xsi:type="string">example</argument> </arguments> </block> </referenceContainer> |
Let me explain what happens here:
- We reference the container called ‘footer’.
- In this container we create a new block of the class Magento\Cms\Block\Block .
- In this block, we pass a parameter called ‘block_id’, and we give it the value ‘example’ (If you want to know how this parameter is used in the block, I’d suggest that you take a look at the _toHtml() -method inside the class).
If you now flush your cache and reload your page, you’ll notice that we now have successfully added the static block to our footer. This method is great if you want to give your customer the possibility to be able to edit some chunks of text here and there.
But let’s take it one step further …
Writing your own block classes in Magento 2
Let’s create a block that – let’s say – shows us the current date. This can be done easily by creating a file called Date.php inside the Block -folder of your module:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php namespace Gielberkers\Example\Block; use Magento\Framework\View\Element\AbstractBlock; /** * Class Date * @package Gielberkers\Example\Block */ class Date extends AbstractBlock { /** * Return the HTML * @return string */ protected function _toHtml() { return 'Today\'s date is ' . date('Y-m-d'); } } |
Now in our layout XML file, we can add the following block inside our <body> -tag:
1 2 3 |
<referenceContainer name="footer"> <block class="Gielberkers\Example\Block\Date" name="example.date"/> </referenceContainer> |
Note that we don’t really need to re-declare our reference to the footer again, you could also add the block to the same container as our previous example.
Clear the cache and reload the page. Voila: we’ve inserted some text in our page. Note that we don’t have any HTML output, it’s just the raw output as declared in our _toHtml() -method.
What about template files?
Good question. Simple answer.
You’ve probably already seen a lot of .phtml -files throughout the codebase of Magento 2. Wouldn’t it be nice if we could just write those template files, but use the methods of our own blocks? Luckily for us, this is really simple.
Simply make your PHP class extend the class Magento\Framework\View\Element\Template and declare your methods in the class (so don’t overwrite the _toHtml() -method):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php namespace Gielberkers\Example\Block; use Magento\Framework\View\Element\Template; /** * Class Date * @package Gielberkers\Example\Block */ class Date extends Template { /** * Return the HTML * @return string */ public function getDateString() { return 'Today\'s date is ' . date('Y-m-d'); } } |
And in your layout XML file, add a template attribute:
1 |
<block class="Gielberkers\Example\Block\Date" name="example.date" template="example.phtml"/> |
Create a file called example.phtml inside view/frontend/templates :
1 2 3 4 |
<?php /** @var \Gielberkers\Example\Block\Date $block */ ?> <h3>Howdy folks!</h3> <p>Let's just see what our getDateString()-method has to say today:</p> <p><?php echo $block->getDateString(); ?></p> |
Note that we call a variable called $block inside our template. Whereas in Magento 1 we needed to use $this to reference our block class, in Magento 2 it’s the $block -variable that references it. For completion: in Magento 2, $this references to the template engines’ class, which is Magento\Framework\View\TemplateEngine\Php by default.
All this trouble for such a simple method. Why not write PHP inside the template itself?
This is a fair question and I will discuss this one in more detail in a later article, but the main reason is to keep your code and your template separated. It’s true that .phtml -files are fully valid PHP-files and you could do stuff like access the file system or execute complete database queries in it. But this is very very bad practice (although I’ve seen plenty of third party modules do this and even Magento itself does this from time to time). When it comes to writing templates, always keep in mind that even a junior developer with very little PHP / HTML skills must be able to write templates. That means:
- Only use very basic PHP functions (if/else, case, echo, etc.)
- Let more complex task be done by blocks (this way you keep design and logic separated).
Like I said, more on this will be discussed later on, but it’s important to know this so you can better understand the position and the role of blocks in Magento.
This post is part of the series Magento 2 Development from Scratch.
Visitors give this article an average rating of 4.4 out of 5.
How would you rate this article?
★ ★ ★ ★ ★
Thank you very much!!!
I have spent around 5 hours with trying to set my custom block to HEAD section with this way:
but it only your solution helped me!!!!
I can’t get the template part to work. I think it’s because of my _toHtml function what are we suppose to put in it ?
Make sure your php class in your .php file extends Template rather then AbstractBlock, and make sure it doesn’t have any _toHtml function at all. (The system will use the _toHtml function of the Template class that you’re extending.)
My block files must be in app/code/Vendor/Module/ … or it can be in app/design/Vendor/Theme/Module_Name/ … ?
I was having problem while creating block, and your article helped me a lot but for customizing layout i had issue with template path hints and i was looking for help then found your post and this one, https://www.cloudways.com/blog/magento-2-layouts-blocks-templates/ , so i got help regarding path hint from this blog post. Thanks for producing this article.