Templates, Blocks, and View Models
Block vs. template vs. view model
A block is a PHP class extending Magento\Framework\View\Element\Template (or a specific block). The template is the .phtml that renders it. A view model is a plain PHP class injected via layout arguments and accessed in the template through $block->getData('view_model'). View models are the recommended place for presentation logic, keeping templates thin and testable.
Escaping and output
Use $block->escapeHtml(), escapeHtmlAttr(), escapeUrl(), and escapeJs() appropriately. escapeHtml does not escape URLs or JS contexts. A common trap: echoing raw getDescription() or trusting getProductUrl() without escapeUrl.
Template resolution
Templates resolve by module/theme fallback: child theme overrides parent theme overrides module view/frontend/templates. The Magento_Theme:: prefix maps to the module's template directory. Overriding a template requires matching the module and path exactly.
Traps to expect
- Assuming
$block->getChildHtml('name')works without the child being declared. - Putting business logic in
.phtmlinstead of a view model or block method. - Forgetting
getViewModel()helper patterns vs.getData('view_model')depending on Magento version. - Mixing up
$block->getPriceHtml()style helpers with raw model calls.
Rule of thumb
If a template needs data transformation, add it to a view model and pass it via layout arguments; keep .phtml to loops, conditionals, and escaped output.
Worked example
Layout: <block name="product.extra" template="Vendor_Module::product/extra.phtml"><arguments><argument name="view_model" xsi:type="object">Vendor\Module\ViewModel\Extra</argument></arguments></block>. Template: $vm = $block->getData('view_model'); echo $block->escapeHtml($vm->getLabel());.