View Directory Structure
Complete View Layout
Vendor/Module/view/
├── frontend/
│ ├── layout/
│ │ ├── default.xml (all frontend pages)
│ │ ├── catalog_product_view.xml (product page only)
│ │ ├── catalog_category_view.xml (category page only)
│ │ └── vendor_module_index.xml (custom route)
│ ├── templates/
│ │ ├── product/
│ │ │ ├── view.phtml
│ │ │ └── list.phtml
│ │ └── widget/
│ │ └── custom.phtml
│ ├── web/
│ │ ├── css/
│ │ │ └── source/
│ │ │ └── _module.less
│ │ ├── js/
│ │ │ └── component.js
│ │ ├── images/
│ │ │ └── logo.png
│ │ └── fonts/
│ └── requirejs-config.js
├── adminhtml/
│ ├── layout/
│ │ ├── default.xml
│ │ └── vendor_module_index.xml
│ ├── templates/
│ │ └── widget/
│ │ └── form.phtml
│ └── web/
│ ├── css/
│ ├── js/
│ └── images/
└── base/
└── web/
└── images/
└── shared-image.png
Area Separation
Magento loads view files based on the current area:
- frontend: Customer-facing storefront
- adminhtml: Admin panel
- base: Shared across all areas
Each area has its own layout handles, templates, and assets.
Frontend Layout and Templates
Layout Files
Layout XML files control page structure:
<!-- default.xml: applies to ALL frontend pages -->
<?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>
<referenceContainer name="content">
<block class="Vendor\Module\Block\Banner"
name="vendor.banner"
template="Vendor_Module::banner.phtml"/>
</referenceContainer>
</body>
</page>
Template Files (.phtml)
<!-- vendor_module::product/view.phtml -->
<?php
/** @var Vendor\Module\Block\Product\View $block */
$product = $block->getProduct();
?>
<div class="product-view">
<h1><?= $block->escapeHtml($product->getName()) ?></h1>
<div class="price">
<?= $block->getFormattedPrice($product->getPrice()) ?>
</div>
<div class="description">
<?= $block->escapeHtml($product->getDescription()) ?>
</div>
</div>
Escaping Output
Always escape output to prevent XSS:
// Text escaping
echo $block->escapeHtml($text);
echo $block->escapeHtml($text, ['b', 'i', 'em', 'strong']); // allow some HTML
// URL escaping
echo $block->escapeUrl($url);
// CSS escaping
echo $block->escapeCss($css);
// JS escaping
echo $block->escapeJs($js);
// Attribute escaping
echo $block->escapeHtmlAttr($attribute);
Template Inheritance
Templates can extend other templates:
<!-- parent.phtml -->
<div class="wrapper">
<?= $this->getChildHtml('content') ?>
</div>
<!-- child.phtml (extends parent) -->
<?php $this->extend('parent.phtml') ?>
<?php $this->blockContent('content') ?>
<p>My content here</p>
<?php $this->blockContent() ?>
Web Assets Directory
CSS/LESS Files
Place stylesheets in view/frontend/web/css/source/:
// _module.less
& when (@media-common = true) {
.vendor-banner {
background-color: @color-blue;
padding: 20px;
text-align: center;
&__title {
font-size: 24px;
color: @color-white;
}
&__subtitle {
font-size: 16px;
margin-top: 10px;
}
}
}
// Responsive styles
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
.vendor-banner {
padding: 10px;
&__title {
font-size: 18px;
}
}
}
JavaScript Files
Place JS in view/frontend/web/js/:
// component.js
define([
'jquery',
'uiComponent'
], function ($, Component) {
'use strict';
return Component.extend({
defaults: {
template: 'Vendor_Module/component'
},
initialize: function () {
this._super();
console.log('Component initialized');
return this;
},
customMethod: function () {
// Custom logic
}
});
});
requirejs-config.js
Configure module dependencies and aliases:
// view/frontend/requirejs-config.js
var config = {
map: {
'*': {
'customComponent': 'Vendor_Module/js/component'
}
},
paths: {
'vendorModule': 'Vendor_Module/js'
},
shim: {
'vendorModule/legacy': {
'deps': ['jquery']
}
}
};
Images and Fonts
view/frontend/web/
├── images/
│ ├── logo.png
│ ├── icons/
│ │ └── sprite.svg
│ └── banners/
│ └── hero.jpg
└── fonts/
└── custom-font.woff2
Reference in templates:
<img src="<?= $block->getViewFileUrl('Vendor_Module::images/logo.png') ?>" alt="Logo">
Adminhtml View Directory
Admin View Structure
Admin templates and layouts mirror the frontend structure but are scoped to the admin area:
Vendor/Module/view/adminhtml/
├── layout/
│ ├── default.xml (all admin pages)
│ ├── vendor_module_index.xml (custom admin page)
│ └── catalog_product_edit.xml (extend product edit)
├── templates/
│ ├── widget/
│ │ └── form.phtml
│ └── warranty/
│ └── grid.phtml
└── web/
├── css/
│ └── source/
│ └── _module.less
├── js/
│ └── grid.js
└── images/
Admin Layout XML
<!-- vendor_module_index.xml -->
<?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"
layout="admin-2columns-left">
<update handle="formkey"/>
<body>
<referenceContainer name="content">
<block class="Vendor\Module\Block\Adminhtml\Warranty\Grid"
name="vendor.warranty.grid"
template="Vendor_Module::warranty/grid.phtml"/>
</referenceContainer>
</body>
</page>
Admin Templates
<!-- warranty/grid.phtml -->
<?php
/** @var Vendor\Module\Block\Adminhtml\Warranty\Grid $block */
$grid = $block->getGrid();
?>
<div class="warranty-grid">
<table class="data-grid">
<thead>
<tr>
<th><?= __('ID') ?></th>
<th><?= __('Name') ?></th>
<th><?= __('Duration') ?></th>
<th><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($grid->getItems() as $item): ?>
<tr>
<td><?= $item->getId() ?></td>
<td><?= $block->escapeHtml($item->getName()) ?></td>
<td><?= $item->getDuration() ?> months</td>
<td>
<a href="<?= $block->getUrl('vendor_warranty/edit', ['id' => $item->getId()]) ?>">
<?= __('Edit') ?>
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
Static Content Deployment
When adding new view files, deploy static content:
# Development
bin/magento setup:static-content:deploy -f
# Clear specific area
bin/magento cache:clean
# Remove old static files
rm -rf pub/static/frontend/Vendor/Module/
bin/magento setup:static-content:deploy -f
Quiz
1. Which directory contains files shared across all areas?
2. How do you reference a template file in layout XML?
3. Where should LESS files be placed in a module?
Flashcards
Question
What are the three view areas in Magento?
Click to reveal answer
Answer
frontend (storefront), adminhtml (admin panel), base (shared)
Question
What is the file extension for Magento templates?
Click to reveal answer
Answer
.phtml
Question
How do you reference a module's static assets?
Click to reveal answer
Answer
Vendor_Module::images/logo.png or $block->getViewFileUrl('Vendor_Module::...')
Question
Where does requirejs-config.js go?
Click to reveal answer
Answer
view/frontend/requirejs-config.js
Question
What escaping function prevents XSS in templates?
Click to reveal answer
Answer
$block->escapeHtml($text)
Revision Notes
Key Takeaways
- 1. View directory is organized by area: frontend, adminhtml, base
- 2. Layout XML controls page structure; templates render HTML
- 3. Web assets (CSS, JS, images) live in view/{area}/web/
- 4. Always escape output in templates with escapeHtml()
- 5. Run static content deploy after adding new view files
Interview Tips
- • Explain the area separation (frontend, adminhtml, base)
- • Know how templates reference blocks and access data
- • Discuss the web asset pipeline (LESS → CSS, RequireJS)
- • Be ready to explain how to add custom CSS/JS to a module
Cheat Sheet
view/
├── frontend/ (storefront)
│ ├── layout/ (XML page configs)
│ ├── templates/ (.phtml files)
│ ├── web/ (CSS, JS, images)
│ └── requirejs-config.js
├── adminhtml/ (admin panel)
└── base/ (shared assets)
Template: Vendor_Module::path/file.phtml
Asset URL: $block->getViewFileUrl('Vendor_Module::images/logo.png')