Creating Block Classes
Basic Block
<?php
namespace Amazon\Prep\Block;
use Magento\Framework\View\Element\Template;
class PrepInfo extends Template
{
public function __construct(
Template\Context $context,
array $data = []
) {
parent::__construct($context, $data);
}
public function getPrepTitle(): string
{
return $this->getData('title') ?? 'Prep Information';
}
public function getPrepItems(): array
{
return $this->getData('items') ?? [];
}
}
Block with Dependencies
<?php
namespace Amazon\Prep\Block;
use Magento\Framework\View\Element\Template;
use Amazon\Prep\Model\ResourceModel\Item\CollectionFactory;
class ItemList extends Template
{
public function __construct(
Template\Context $context,
private CollectionFactory $collectionFactory,
array $data = []
) {
parent::__construct($context, $data);
}
public function getItems(): array
{
return $this->collectionFactory->create()
->addFieldToSelect('*')
->setPageSize(10)
->getItems();
}
public function getItemCount(): int
{
return count($this->getItems());
}
public function formatPrice(float $price): string
{
return $this->helper('Magento\Framework\View\Element\AbstractBlock')
->formatPrice($price);
}
}
Block with Registry Access
<?php
namespace Amazon\Prep\Block;
use Magento\Framework\View\Element\Template;
class ProductPrep extends Template
{
public function __construct(
Template\Context $context,
private \Magento\Framework\Registry $registry,
array $data = []
) {
parent::__construct($context, $data);
}
public function getCurrentProduct(): ?\Magento\Catalog\Model\Product
{
return $this->registry->registry('current_product');
}
public function getProductSku(): string
{
$product = $this->getCurrentProduct();
return $product ? $product->getSku() : '';
}
}
Writing .phtml Templates
Template File Structure
Place templates in view/frontend/templates/:
view/frontend/templates/
├── prep_info.phtml
├── item/
│ ├── list.phtml
│ └── view.phtml
└── widget/
└── custom.phtml
Basic Template
<!-- prep_info.phtml -->
<?php
/** @var Amazon\Prep\Block\PrepInfo $block */
$title = $block->getPrepTitle();
$items = $block->getPrepItems();
?>
<div class="prep-info">
<h2><?= $block->escapeHtml($title) ?></h2>
<?php if (!empty($items)): ?>
<ul class="prep-list">
<?php foreach ($items as $item): ?>
<li><?= $block->escapeHtml($item) ?></li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p><?= __('No prep items available.') ?></p>
<?php endif; ?>
</div>
Accessing Block Methods
In templates, $block refers to the current block:
// Call block methods
$block->getProductName();
$block->formatPrice(29.99);
$block->escapeHtml($text);
// Access layout
$layout = $block->getLayout();
// Access request
$request = $block->getRequest();
$param = $request->getParam('id');
// Access URL builder
$url = $block->getUrl('vendor/module/action', ['id' => 1]);
$baseUrl = $block->getBaseUrl();
// Access store
$storeId = $block->getStoreManager()->getStore()->getId();
$storeName = $block->getStoreManager()->getStore()->getName();
// Access helper
$helper = $block->helper('Vendor\Module\Helper\Data');
Template Variables from Layout
<block class="Amazon\Prep\Block\PrepInfo"
name="prep.info"
template="Amazon_Prep::prep_info.phtml">
<arguments>
<argument name="title" xsi:type="string">Custom Title</argument>
<argument name="show_header" xsi:type="number">1</argument>
</arguments>
</block>
Access in block:
public function shouldShowHeader(): bool
{
return (bool)$this->getData('show_header');
}
Output Escaping
Why Escape Output?
Unescaped output enables XSS (Cross-Site Scripting) attacks. Always escape user-provided or dynamic data.
Escape Functions
// Text escaping (removes all HTML)
echo $block->escapeHtml($text);
// Allow specific HTML tags
echo $block->escapeHtml($richText, ['b', 'i', 'em', 'strong', 'p', 'br']);
// URL escaping
echo $block->escapeUrl($url);
// CSS escaping
echo $block->escapeCss($cssValue);
// JavaScript escaping
echo $block->escapeJs($jsString);
// HTML attribute escaping
echo $block->escapeHtmlAttr($attributeValue);
// Quote escaping
echo $block->escapeQuote($stringValue);
Escaping Examples
<!-- Product name (user input) -->
<h1><?= $block->escapeHtml($product->getName()) ?></h1>
<!-- URL (could be malicious) -->
<a href="<?= $block->escapeUrl($product->getProductUrl()) ?>">
<?= $block->escapeHtml($product->getName()) ?>
</a>
<!-- Image src -->
<img src="<?= $block->escapeUrl($block->getViewFileUrl('images/logo.png')) ?>"
alt="<?= $block->escapeHtmlAttr($product->getName()) ?>">
<!-- Style attribute -->
<div style="<?= $block->escapeCss($customStyle) ?>">
Content
</div>
<!-- JavaScript variable -->
<script>
var productName = '<?= $block->escapeJs($product->getName()) ?>';
</script>
<!-- Rich text with allowed tags -->
<div class="description">
<?= $block->escapeHtml($product->getDescription(), ['p', 'br', 'strong', 'em']) ?>
</div>
Escaping in Different Contexts
| Context | Function |
|---|---|
| HTML body | escapeHtml() |
| HTML attributes | escapeHtmlAttr() |
| URLs | escapeUrl() |
| CSS | escapeCss() |
| JavaScript | escapeJs() |
| JSON | json_encode() (PHP) |
Common Mistakes
// WRONG: No escaping
echo $product->getName();
// WRONG: Wrong escaping function
echo $block->escapeHtml($product->getUrl()); // URL in HTML context
// RIGHT: Match escaping to context
echo $block->escapeHtml($product->getName());
echo $block->escapeUrl($product->getUrl());
Child Blocks and Template Inheritance
Rendering Child Blocks
In Layout XML
<block class="Amazon\Prep\Block\Container" name="container">
<block class="Amazon\Prep\Block\Header" name="header" template="header.phtml"/>
<block class="Amazon\Prep\Block\Content" name="content" template="content.phtml"/>
<block class="Amazon\Prep\Block\Footer" name="footer" template="footer.phtml"/>
</block>
In Parent Template
<!-- container.phtml -->
<div class="wrapper">
<?= $block->getChildBlock('header')->toHtml() ?>
<?= $block->getChildBlock('content')->toHtml() ?>
<?= $block->getChildBlock('footer')->toHtml() ?>
</div>
Render All Children
<!-- container.phtml -->
<div class="wrapper">
<?= $block->getChildHtml() ?>
</div>
<!-- With specific order -->
<div class="wrapper">
<?= $block->getChildHtml('header') ?>
<?= $block->getChildHtml('content') ?>
<?= $block->getChildHtml('footer') ?>
</div>
Adding Child Blocks Programmatically
// In block _prepareLayout()
public function _prepareLayout(): void
{
$this->setChild('custom_block',
$this->getLayout()->createBlock(
\Amazon\Prep\Block\Custom::class,
'custom_block_name'
)
);
parent::_prepareLayout();
}
// In template
echo $block->getChildBlock('custom_block')->toHtml();
Template Inheritance
<!-- parent.phtml -->
<html>
<head><title><?= $block->pageTitle ?></title></head>
<body>
<header><?= $block->getChildHtml('header') ?></header>
<main><?= $block->getChildHtml('content') ?></main>
<footer><?= $block->getChildHtml('footer') ?></footer>
</body>
</html>
<!-- child.phtml (extends parent) -->
<?php $this->extend('parent.phtml') ?>
<?php $this->blockContent('header') ?>
<h1><?= $block->escapeHtml($block->getTitle()) ?></h1>
<?php $this->blockContent() ?>
<?php $this->blockContent('content') ?>
<div class="main-content">
<?= $block->getChildHtml() ?>
</div>
<?php $this->blockContent() ?>
<?php $this->blockContent('footer') ?>
<p>© 2024 Amazon Prep</p>
<?php $this->blockContent() ?>
Block Caching with Templates
// Block class
public function getCacheKey(): string
{
return 'amazon_prep_list_' . $this->getStoreId();
}
public function getCacheLifetime(): ?int
{
return 3600; // 1 hour
}
public function getCacheTags(): array
{
return ['amazon_prep_list'];
}
Quiz
1. What variable refers to the current block in a .phtml template?
2. Which function escapes HTML to prevent XSS attacks?
3. How do you render a child block named 'header' in a template?
Flashcards
Question
What is the base class for template blocks?
Click to reveal answer
Answer
Magento\Framework\View\Element\Template
Question
How do you access a block method in a template?
Click to reveal answer
Answer
$block->methodName()
Question
What escapes HTML for safe output?
Click to reveal answer
Answer
$block->escapeHtml($text)
Question
How do you render all child blocks?
Click to reveal answer
Answer
$block->getChildHtml()
Question
Where do template files go?
Click to reveal answer
Answer
view/frontend/templates/
Revision Notes
Key Takeaways
- 1. Blocks extend Template and prepare data for .phtml templates
- 2. Always escape output with escapeHtml(), escapeUrl(), escapeJs() etc.
- 3. Use $block to access block methods in templates
- 4. Child blocks are rendered with getChildHtml('name')
- 5. Block caching prevents re-rendering unchanged content
Interview Tips
- • Explain the block → template data flow
- • Know all escaping functions and when to use each
- • Be ready to create a block with template and child blocks
- • Discuss block caching strategies
Cheat Sheet
Block: extends Template
Template: $block->methodName()
Escaping:
escapeHtml() → HTML body
escapeUrl() → URLs
escapeJs() → JavaScript
escapeCss() → CSS
escapeHtmlAttr() → attributes
Child blocks:
$block->getChildHtml('name')
$block->getChildHtml() // all