Skip to content
intermediate Phase 22 · Module Directories Deep Dive

Block Directory - Module Directories Deep Dive

Understanding the Magento 2 Block directory: block classes, template rendering, cache keys, cache lifetimes, and layout integration

45m
0 problems
Topic Progress 0%

Block Architecture

What Blocks Do

Blocks bridge the gap between PHP logic and HTML templates. They prepare data, handle business logic, and pass variables to .phtml template files for rendering.

Block Directory Structure

Vendor/Module/Block/
├── Product/
│   ├── View.php          → handles product view page
│   ├── List.php           → handles product list
│   └── Price.php          → renders price display
├── Category/
│   └── View.php
└── Widget/
    └── CustomWidget.php

Block Class Hierarchy

Magento\Framework\View\Element\AbstractBlock
    ├── Magento\Framework\View\Element\Template
    │       └── Your\Module\Block\ClassName
    └── Magento\Framework\View\Element\Text

Most blocks extend Template which provides template rendering capabilities.

Basic Block Class

namespace Vendor\Module\Block\Product;

use Magento\Framework\View\Element\Template;

class View extends Template
{
    public function __construct(
        Template\Context $context,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }

    public function getProductName(): string
    {
        return $this->_registry->registry('current_product')->getName();
    }
}

Block vs ViewModel

Aspect Block ViewModel
Lifecycle Per-page-render Injected via DI
Caching Built-in support Manual caching
Template access Direct Via accessor
Use case Legacy pattern Modern pattern

Both patterns are valid. Blocks are more common in existing Magento code.

Template Rendering and Data Passing

Setting the Template

In layout XML:

<block class="Vendor\Module\Block\Product\View"
       name="vendor.product.view"
       template="Vendor_Module::product/view.phtml"/>

Or programmatically:

public function _prepareLayout(): void
{
    $this->setTemplate('Vendor_Module::product/view.phtml');
    parent::_prepareLayout();
}

Passing Data to Templates

Method 1: Public Methods

// Block class
public function getProductPrice(): float
{
    return $this->_registry->registry('current_product')->getPrice();
}

// Template (.phtml)
$price = $block->getProductPrice();
echo $this->helper('Magento\Framework\Escaper')->escapeHtml($price);

Method 2: setData in Layout XML

<block class="Vendor\Module\Block\Widget"
       name="vendor.widget"
       template="Vendor_Module::widget.phtml">
    <arguments>
        <argument name="title" xsi:type="string">Custom Widget</argument>
        <argument name="show_header" xsi:type="number">1</argument>
    </arguments>
</block>

Access in block:

public function getTitle(): string
{
    return $this->getData('title');
}

Method 3: Layout Update in Block

public function _prepareLayout(): void
{
    $this->setChild('price_block',
        $this->layoutFactory->create()->createBlock(
            \Vendor\Module\Block\Product\Price::class
        )
    );
    parent::_prepareLayout();
}

Template Variables

In .phtml templates, $block refers to the current block:

// Access block methods
$block->getProductName();
$block->getProductPrice();

// Access layout
$layout = $block->getLayout();

// Access request
$request = $block->getRequest();

// Access URL builder
$url = $block->getUrl('vendor/module/action', ['id' => 1]);

// Access store manager
$storeId = $block->getStoreManager()->getStore()->getId();

Block Caching

Why Cache Blocks?

Block caching prevents re-rendering the same block content on every page load. If the underlying data hasn't changed, Magento serves the cached HTML.

Cache Key

Each block needs a unique cache key:

public function getCacheKey(): string
{
    return 'vendor_module_product_' . $this->getProductId();
}

For complex keys, use the cache key info array:

public function getCacheKeyInfo(): array
{
    return [
        'VENDOR_MODULE_PRODUCT_VIEW',
        $this->getStoreId(),
        $this->getProductId(),
        $this->getCustomerGroupId(),
        $this->isSecure(),
    ];
}

Magento concatenates these with underscores for the final cache key.

Cache Lifetime

Control how long the cache persists:

public function getCacheLifetime(): ?int
{
    return 3600; // 1 hour in seconds
}

// No caching
public function getCacheLifetime(): ?int
{
    return null;
}

// Dynamic lifetime based on data
public function getCacheLifetime(): ?int
{
    $product = $this->_registry->registry('current_product');
    return $product->isSalable() ? 3600 : 300;
}

Cache Tags

Use cache tags for targeted invalidation:

public function getCacheTags(): array
{
    return [
        'vendor_module_product',
        'catalog_product_' . $this->getProductId(),
    ];
}

Complete Caching Example

namespace Vendor\Module\Block\Product;

use Magento\Framework\View\Element\Template;

class ProductList extends Template
{
    public function __construct(
        Template\Context $context,
        private \Vendor\Module\Model\ResourceModel\Product\CollectionFactory $collectionFactory,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }

    public function getProducts(): array
    {
        return $this->collectionFactory->create()
            ->addAttributeToSelect(['name', 'price', 'image'])
            ->setPageSize(10)
            ->getItems();
    }

    public function getCacheKey(): string
    {
        return 'vendor_product_list_' . $this->getStoreId();
    }

    public function getCacheLifetime(): ?int
    {
        return 1800; // 30 minutes
    }

    public function getCacheTags(): array
    {
        return ['vendor_product_list'];
    }
}

Cache Invalidation

Clear block cache programmatically:

$cacheType = 'block_html';
$this->cacheManager->clean($cacheType);

// Or via CLI
bin/magento cache:clean block_html

Block Registry and Layout Integration

Registry Access

Blocks can access the Magento registry for current page context:

// Current product (on product page)
$product = $this->_registry->registry('current_product');

// Current category (on category page)
$category = $this->_registry->registry('current_category');

// Current CMS page
$cmsPage = $this->_registry->registry('current_cms_page');

// Custom registry values
$value = $this->_registry->registry('my_custom_key');

Layout Methods in Blocks

public function _prepareLayout(): void
{
    // Set page title
    $this->pageConfig->setTitle(__('My Page Title'));

    // Add meta keywords
    $this->pageConfig->setKeywords('magento, module, custom');

    // Add breadcrumbs
    $this->getLayout()->getBlock('breadcrumbs')
        ->addCrumb('home', ['label' => __('Home'), 'link' => $this->getBaseUrl()])
        ->addCrumb('category', ['label' => __('Category')]);

    // Add custom head content
    $this->pageConfig->addRemotePageAsset(
        'https://example.com/style.css',
        'rel="stylesheet" type="text/css" media="all"'
    );

    parent::_prepareLayout();
}

Creating Blocks Programmatically

// In a block or controller
$block = $this->layoutFactory->create()->createBlock(
    \Vendor\Module\Block\Custom::class,
    'unique_block_name'
);
$block->setData('my_value', 'hello');
$html = $block->toHtml();

Child Blocks

// Add child block in _prepareLayout()
$this->setChild('child_block_name',
    $this->getLayout()->createBlock(
        \Vendor\Module\Block\Child::class
    )
);

// Render child block in template
echo $block->getChildBlock('child_block_name')->toHtml();

// Or iterate child blocks
foreach ($block->getChildren() as $child) {
    echo $child->toHtml();
}

Sort Order and Aliases

In layout XML:

<block class="Vendor\Module\Block\Custom"
       name="custom_block"
       alias="custom"
       after="-"
       before="-"
       output="1"/>
  • name: Unique identifier in layout
  • alias: Alternative reference name
  • after/before: Sort order relative to other blocks
  • output: If 1, block renders automatically

Quiz

1. What method must a block implement to provide a unique cache key?

Question 1 options

2. How do you access a block method in a .phtml template?

Question 2 options

3. What does getCacheLifetime() return to disable caching?

Question 3 options

Flashcards

Question

What is the base class for most Magento blocks?

Answer

Magento\Framework\View\Element\Template

Question

How do you reference a block in layout XML?

Answer

Use the name attribute: name="vendor.block.name"

Question

What is the difference between getCacheKey() and getCacheKeyInfo()?

Answer

getCacheKeyInfo() returns an array that Magento concatenates into the cache key

Question

How do you access current product in a block?

Answer

$this->_registry->registry('current_product')

Question

What attribute in layout XML makes a block render automatically?

Answer

output="1"

Revision Notes

Key Takeaways

  • 1. Blocks extend Template and prepare data for .phtml templates
  • 2. Use getCacheKey(), getCacheLifetime(), and getCacheTags() for block caching
  • 3. Access data via public methods, layout arguments, or the registry
  • 4. Layout XML controls block placement, arguments, and rendering order
  • 5. Child blocks allow composition of complex page structures

Interview Tips

  • Explain the block → template rendering flow
  • Know how to implement block caching with proper keys and tags
  • Discuss the registry pattern and when to use it vs DI
  • Be ready to explain layout XML block configuration

Cheat Sheet

Block:
  extends Template
  $this->_registry->registry('current_product')
  $block->getMethodName() in .phtml

Caching:
  getCacheKey() → unique identifier
  getCacheLifetime() → seconds (null = no cache)
  getCacheTags() → array for invalidation

Layout:
  <block class="..." name="..." template="..." output="1"/>