joomla-template-overrides

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Joomla Template Overrides - Complete System

Joomla 模板重写系统完全指南

Introduction

简介

Template overrides allow you to customize the output of components, modules, and plugins without modifying core files. They are stored in
/templates/[name]/html/
and are automatically loaded in place of the original files.
Covers: Joomla 5.x, 6.x | Requirements: Basic knowledge of PHP, Joomla folder structure

模板重写允许你在不修改核心文件的前提下,自定义组件、模块和插件的输出内容。它们存储在
/templates/[name]/html/
目录中,会自动加载以替代原始文件。
适用版本:Joomla 5.x、6.x | 前置要求:具备PHP基础和Joomla目录结构相关知识

Fundamental Concepts

核心概念

Why Use Overrides?

为什么使用模板重写?

  • Customize presentation without modifying core
  • Maintain functionality when updating Joomla
  • Reuse code across views
  • Separate presentation logic
  • 无需修改核心文件即可自定义展示效果
  • Joomla更新时仍能保留原有功能
  • 在多个视图间复用代码
  • 分离展示逻辑

Loading Hierarchy

加载优先级

Joomla looks for files in this order:
  1. /templates/[active]/html/[path]
    → Custom override
  2. /[component]/views/[view]/tmpl/
    → Original file

Joomla会按照以下顺序查找文件:
  1. /templates/[active]/html/[path]
    → 自定义重写文件
  2. /[component]/views/[view]/tmpl/
    → 原始文件

/html/ Folder Structure

/html/ 目录结构

/templates/cassiopeia/html/
├── com_content/              # Components (com_)
│   ├── article/
│   │   └── default.php
│   └── category/
│       ├── blog.php
│       ├── blog_item.php
│       └── default.php
├── mod_login/                # Modules (mod_)
│   ├── default.php
│   └── slim.php
├── plg_content_pagenavigation/ # Plugins (plg_)
│   └── default.php
└── layouts/                  # Reusable JLayouts
    └── joomla/
        └── content/
            ├── intro_image.php
            └── info_block.php
Naming Convention:
  • com_[component]
    → components
  • mod_[module]
    → modules
  • plg_[group]_[plugin]
    → plugins

/templates/cassiopeia/html/
├── com_content/              # Components (com_)
│   ├── article/
│   │   └── default.php
│   └── category/
│       ├── blog.php
│       ├── blog_item.php
│       └── default.php
├── mod_login/                # Modules (mod_)
│   ├── default.php
│   └── slim.php
├── plg_content_pagenavigation/ # Plugins (plg_)
│   └── default.php
└── layouts/                  # Reusable JLayouts
    └── joomla/
        └── content/
            ├── intro_image.php
            └── info_block.php
命名规则:
  • com_[component]
    → 组件
  • mod_[module]
    → 模块
  • plg_[group]_[plugin]
    → 插件

Component Overrides - com_content

组件重写 - com_content

Single Article (article/default.php)

单篇文章 - article/default.php

Original Location:
/components/com_content/views/article/tmpl/default.php
Override:
/templates/cassiopeia/html/com_content/article/default.php
Available variables:
  • $this->item
    → article object
  • $this->params
    → parameters
  • $this->item->jcfields
    → custom fields
php
<?php defined('_JEXEC') or die; ?>
<article class="article-container">
    <header class="article-header">
        <h1><?php echo htmlspecialchars($this->item->title); ?></h1>
    </header>

    <section class="article-body">
        <?php if (!empty($this->item->images)): ?>
            <?php echo JLayoutHelper::render('joomla.content.intro_image',
                ['item' => $this->item]); ?>
        <?php endif; ?>

        <?php echo $this->item->text; ?>
    </section>

    <?php if (!empty($this->item->jcfields)): ?>
        <section class="article-custom-fields">
            <?php foreach ($this->item->jcfields as $field): ?>
                <div class="field-<?php echo htmlspecialchars($field->type); ?>">
                    <strong><?php echo htmlspecialchars($field->label); ?></strong>
                    <?php echo $field->rawvalue; ?>
                </div>
            <?php endforeach; ?>
        </section>
    <?php endif; ?>
</article>
原始路径
/components/com_content/views/article/tmpl/default.php
重写路径
/templates/cassiopeia/html/com_content/article/default.php
可用变量:
  • $this->item
    → 文章对象
  • $this->params
    → 参数配置
  • $this->item->jcfields
    → 自定义字段
php
<?php defined('_JEXEC') or die; ?>
<article class="article-container">
    <header class="article-header">
        <h1><?php echo htmlspecialchars($this->item->title); ?></h1>
    </header>

    <section class="article-body">
        <?php if (!empty($this->item->images)): ?>
            <?php echo JLayoutHelper::render('joomla.content.intro_image',
                ['item' => $this->item]); ?>
        <?php endif; ?>

        <?php echo $this->item->text; ?>
    </section>

    <?php if (!empty($this->item->jcfields)): ?>
        <section class="article-custom-fields">
            <?php foreach ($this->item->jcfields as $field): ?>
                <div class="field-<?php echo htmlspecialchars($field->type); ?>">
                    <strong><?php echo htmlspecialchars($field->label); ?></strong>
                    <?php echo $field->rawvalue; ?>
                </div>
            <?php endforeach; ?>
        </section>
    <?php endif; ?>
</article>

Category Blog Mode - blog_item.php

分类博客模式 - blog_item.php

Location:
/templates/cassiopeia/html/com_content/category/blog_item.php
Renders each article in the blog:
php
<?php defined('_JEXEC') or die;
$item = $this->item; ?>

<article class="blog-item">
    <h2 class="item-title">
        <?php echo JHtml::_('link', JRoute::_($item->link),
            htmlspecialchars($item->title)); ?>
    </h2>

    <?php if (!empty($item->images)): ?>
        <?php echo JLayoutHelper::render('joomla.content.intro_image',
            ['item' => $item]); ?>
    <?php endif; ?>

    <div class="item-content">
        <?php echo $item->introtext; ?>
    </div>

    <a href="<?php echo JRoute::_($item->link); ?>" class="read-more">
        Read more
    </a>
</article>
路径
/templates/cassiopeia/html/com_content/category/blog_item.php
用于渲染博客中的每一篇文章:
php
<?php defined('_JEXEC') or die;
$item = $this->item; ?>

<article class="blog-item">
    <h2 class="item-title">
        <?php echo JHtml::_('link', JRoute::_($item->link),
            htmlspecialchars($item->title)); ?>
    </h2>

    <?php if (!empty($item->images)): ?>
        <?php echo JLayoutHelper::render('joomla.content.intro_image',
            ['item' => $item]); ?>
    <?php endif; ?>

    <div class="item-content">
        <?php echo $item->introtext; ?>
    </div>

    <a href="<?php echo JRoute::_($item->link); ?>" class="read-more">
        Read more
    </a>
</article>

Category List Mode - default.php

分类列表模式 - default.php

Location:
/templates/cassiopeia/html/com_content/category/default.php
Main container with article table.

路径
/templates/cassiopeia/html/com_content/category/default.php
包含文章列表的主容器。

Module Overrides

模块重写

Structure

结构

Location:
/templates/[template]/html/mod_[module]/[layout].php
Common modules:
  • mod_login
    → login form
  • mod_menu
    → menus
  • mod_custom
    → custom content
  • mod_articles_latest
    → latest articles
  • mod_breadcrumbs
    → breadcrumbs
路径:
/templates/[template]/html/mod_[module]/[layout].php
常见模块:
  • mod_login
    → 登录表单
  • mod_menu
    → 导航菜单
  • mod_custom
    → 自定义内容
  • mod_articles_latest
    → 最新文章
  • mod_breadcrumbs
    → 面包屑导航

Example: mod_login Override

示例:mod_login 重写

Location:
/templates/cassiopeia/html/mod_login/default.php
php
<?php defined('_JEXEC') or die;
$params = $this->params; ?>

<form action="<?php echo JRoute::_('index.php'); ?>" method="post" class="login-form">
    <div class="form-group">
        <label for="login-username">Username</label>
        <input type="text" name="username" id="login-username"
               class="form-control" required>
    </div>

    <div class="form-group">
        <label for="login-password">Password</label>
        <input type="password" name="password" id="login-password"
               class="form-control" required>
    </div>

    <button type="submit" class="btn btn-primary">Log In</button>

    <input type="hidden" name="option" value="com_users">
    <input type="hidden" name="task" value="user.login">
    <input type="hidden" name="return" value="<?php echo base64_encode(JUri::current()); ?>">
    <?php echo JHtml::_('form.token'); ?>
</form>

路径
/templates/cassiopeia/html/mod_login/default.php
php
<?php defined('_JEXEC') or die;
$params = $this->params; ?>

<form action="<?php echo JRoute::_('index.php'); ?>" method="post" class="login-form">
    <div class="form-group">
        <label for="login-username">Username</label>
        <input type="text" name="username" id="login-username"
               class="form-control" required>
    </div>

    <div class="form-group">
        <label for="login-password">Password</label>
        <input type="password" name="password" id="login-password"
               class="form-control" required>
    </div>

    <button type="submit" class="btn btn-primary">Log In</button>

    <input type="hidden" name="option" value="com_users">
    <input type="hidden" name="task" value="user.login">
    <input type="hidden" name="return" value="<?php echo base64_encode(JUri::current()); ?>">
    <?php echo JHtml::_('form.token'); ?>
</form>

Alternative Layouts

替代布局

Selectable variations without fully replacing the view.
可选择的视图变体,无需完全替换原有视图。

Difference vs Template Override

与模板重写的区别

AspectOverrideAlternative Layout
ApplicationAutomatic site-wideSelectable per module
Filedefault.php (replaces)Unique name (e.g.: grid.php)
UsageReplaces original viewOption alongside original
维度模板重写替代布局
应用范围全站自动生效可按模块单独选择
文件名称default.php(替换原有)唯一名称(如:grid.php)
使用方式替换原始视图与原始视图作为选项共存

Creating an Alternative Layout

创建替代布局

For modules: Multiple files in
/html/mod_[module]/
php
// /templates/cassiopeia/html/mod_login/grid.php
// Alternative grid layout for mod_login
<?php defined('_JEXEC') or die; ?>
<div class="login-grid">
    <!-- grid structure -->
</div>
For components: In menu select "Alternative Layout"
Naming rules:
  • Do not use underscores
  • Descriptive names:
    grid.php
    ,
    minimal.php
    ,
    card.php
  • default.php
    = original layout

针对模块:在
/html/mod_[module]/
目录下创建多个文件
php
// /templates/cassiopeia/html/mod_login/grid.php
// mod_login的网格型替代布局
<?php defined('_JEXEC') or die; ?>
<div class="login-grid">
    <!-- grid structure -->
</div>
针对组件:在菜单设置中选择「替代布局」
命名规则:
  • 不要使用下划线
  • 使用描述性名称:
    grid.php
    minimal.php
    card.php
  • default.php
    = 原始布局

JLayout - Reusable Components

JLayout - 可复用组件

System for creating reusable fragments.
Joomla layouts location:
/layouts/joomla/[group]/[layout].php
Override:
/templates/cassiopeia/html/layouts/joomla/[group]/[layout].php
用于创建可复用代码片段的系统。
Joomla布局原始路径
/layouts/joomla/[group]/[layout].php
重写路径
/templates/cassiopeia/html/layouts/joomla/[group]/[layout].php

Creating a Custom Layout

创建自定义布局

php
// /templates/cassiopeia/html/layouts/joomla/custom/article-card.php
<?php defined('_JEXEC') or die;
$title = $displayData['title'] ?? '';
$content = $displayData['content'] ?? '';
$image = $displayData['image'] ?? '';
$link = $displayData['link'] ?? '#';
?>

<article class="card">
    <?php if ($image): ?>
        <figure class="card-image">
            <img src="<?php echo htmlspecialchars($image); ?>"
                 alt="<?php echo htmlspecialchars($title); ?>">
        </figure>
    <?php endif; ?>

    <div class="card-body">
        <h3><?php echo htmlspecialchars($title); ?></h3>
        <div class="card-content">
            <?php echo $content; ?>
        </div>
        <a href="<?php echo htmlspecialchars($link); ?>" class="card-link">
            View more
        </a>
    </div>
</article>
php
// /templates/cassiopeia/html/layouts/joomla/custom/article-card.php
<?php defined('_JEXEC') or die;
$title = $displayData['title'] ?? '';
$content = $displayData['content'] ?? '';
$image = $displayData['image'] ?? '';
$link = $displayData['link'] ?? '#';
?>

<article class="card">
    <?php if ($image): ?>
        <figure class="card-image">
            <img src="<?php echo htmlspecialchars($image); ?>"
                 alt="<?php echo htmlspecialchars($title); ?>">
        </figure>
    <?php endif; ?>

    <div class="card-body">
        <h3><?php echo htmlspecialchars($title); ?></h3>
        <div class="card-content">
            <?php echo $content; ?>
        </div>
        <a href="<?php echo htmlspecialchars($link); ?>" class="card-link">
            View more
        </a>
    </div>
</article>

Usage in blog_item.php

在blog_item.php中使用

php
<?php echo JLayoutHelper::render('joomla.custom.article-card', [
    'title' => $this->item->title,
    'content' => $this->item->introtext,
    'image' => json_decode($this->item->images)->image_intro ?? '',
    'link' => JRoute::_($this->item->link),
]); ?>

php
<?php echo JLayoutHelper::render('joomla.custom.article-card', [
    'title' => $this->item->title,
    'content' => $this->item->introtext,
    'image' => json_decode($this->item->images)->image_intro ?? '',
    'link' => JRoute::_($this->item->link),
]); ?>

Child Templates

子模板

A template that inherits from a parent, only storing changes.
从父模板继承的模板,仅存储修改的内容。

Creating a Child Template

创建子模板

Structure:
/templates/cassiopeia-child/
├── html/
│   └── com_content/article/default.php  (custom override)
├── css/
│   └── custom.css
└── templateDetails.xml
templateDetails.xml:
xml
<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site">
    <name>Cassiopeia Child</name>
    <version>1.0.0</version>
    <description>Child template based on Cassiopeia</description>
    <parent>cassiopeia</parent>

    <files>
        <folder>html</folder>
        <folder>css</folder>
        <filename>templateDetails.xml</filename>
    </files>

    <positions>
        <position>header</position>
        <position>sidebar</position>
        <position>footer</position>
    </positions>
</extension>
Advantages:
  • Automatically inherits non-customized files
  • Only stores modified files
  • Simplifies maintenance and updates
  • Allows multiple variations of the same parent

目录结构:
/templates/cassiopeia-child/
├── html/
│   └── com_content/article/default.php  (custom override)
├── css/
│   └── custom.css
└── templateDetails.xml
templateDetails.xml:
xml
<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site">
    <name>Cassiopeia Child</name>
    <version>1.0.0</version>
    <description>Child template based on Cassiopeia</description>
    <parent>cassiopeia</parent>

    <files>
        <folder>html</folder>
        <folder>css</folder>
        <filename>templateDetails.xml</filename>
    </files>

    <positions>
        <position>header</position>
        <position>sidebar</position>
        <position>footer</position>
    </positions>
</extension>
优势:
  • 自动继承未自定义的文件
  • 仅存储修改过的文件
  • 简化维护和更新流程
  • 允许基于同一父模板创建多个变体

Field Overrides - Custom Fields

字段重写 - 自定义字段

Override how custom fields are displayed.
Location:
/templates/[template]/html/layouts/com_fields/field/[layout].php
php
// /templates/cassiopeia/html/layouts/com_fields/field/render.php
<?php defined('_JEXEC') or die;
$field = $displayData['field'] ?? null;
$value = $displayData['value'] ?? null;

if (!$field || !$value) return;
?>

<div class="field-container" data-field-id="<?php echo (int)$field->id; ?>">
    <label class="field-label">
        <?php echo htmlspecialchars($field->label); ?>
    </label>
    <div class="field-value">
        <?php echo $value; ?>
    </div>
</div>
Select in backend: Field Edit > Render Options > Layout

重写自定义字段的展示方式。
路径
/templates/[template]/html/layouts/com_fields/field/[layout].php
php
// /templates/cassiopeia/html/layouts/com_fields/field/render.php
<?php defined('_JEXEC') or die;
$field = $displayData['field'] ?? null;
$value = $displayData['value'] ?? null;

if (!$field || !$value) return;
?>

<div class="field-container" data-field-id="<?php echo (int)$field->id; ?>">
    <label class="field-label">
        <?php echo htmlspecialchars($field->label); ?>
    </label>
    <div class="field-value">
        <?php echo $value; ?>
    </div>
</div>
在后台选择:字段编辑 > 渲染选项 > 布局

Template Manager - Creating Overrides

模板管理器 - 创建重写

Backend: Extensions > Templates > [Template] > Create Overrides
Advantages:
  • Intuitive visual interface
  • Automatically copies files
  • No manual searching required
  • Ensures correct structure

后台路径:扩展 > 模板 > [对应模板] > 创建重写
优势:
  • 直观的可视化界面
  • 自动复制文件
  • 无需手动查找路径
  • 确保目录结构正确

Best Practices

最佳实践

Code Documentation

代码文档

php
<?php
/**
 * Override: Custom article
 *
 * Component: com_content
 * Original view: article/tmpl/default.php
 *
 * CHANGES:
 * - Improved semantic structure
 * - Added custom fields
 * - Reordered metadata
 *
 * DEPENDENCIES: Custom field 'author-bio'
 * JOOMLA: 5.0+
 * DATE: 2024-03-06
 */
defined('_JEXEC') or die;
php
<?php
/**
 * 重写:自定义文章视图
 *
 * 组件:com_content
 * 原始视图:article/tmpl/default.php
 *
 * 修改内容:
 * - 优化语义化结构
 * - 添加自定义字段展示
 * - 调整元数据顺序
 *
 * 依赖项:自定义字段'author-bio'
 * 适配Joomla版本:5.0+
 * 日期:2024-03-06
 */
defined('_JEXEC') or die;

Security - Escaping

安全 - 输出转义

php
// GOOD: Escape outputs
<?php echo htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8'); ?>
<?php echo JHtml::_('string.truncate', $item->text, 100); ?>

// GOOD: URLs with JRoute
<?php echo JRoute::_('index.php?option=com_content&view=article&id=' . $item->id); ?>

// BAD: Unescaped output
<?php echo $item->title; ?>
php
// 推荐:对输出内容进行转义
<?php echo htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8'); ?>
<?php echo JHtml::_('string.truncate', $item->text, 100); ?>

// 推荐:使用JRoute生成URL
<?php echo JRoute::_('index.php?option=com_content&view=article&id=' . $item->id); ?>

// 不推荐:未转义的输出
<?php echo $item->title; ?>

Post-Update Testing

更新后测试

bash
undefined
bash
undefined

Compare overrides with core files

对比重写文件与核心文件的差异

diff -u /components/com_content/views/article/tmpl/default.php
/templates/cassiopeia/html/com_content/article/default.php
diff -u /components/com_content/views/article/tmpl/default.php
/templates/cassiopeia/html/com_content/article/default.php

Backup overrides before updating

更新前备份重写文件

cp -r templates/cassiopeia/html templates/cassiopeia/html.backup
undefined
cp -r templates/cassiopeia/html templates/cassiopeia/html.backup
undefined

Avoid Unnecessary Overrides

避免不必要的重写

  • Only override if you modify the view
  • Use alternative layouts for variations
  • Use JLayout for reusable components
  • Maintain change tracking (git, documentation)

  • 仅在需要修改视图时才创建重写
  • 使用替代布局实现视图变体
  • 使用JLayout创建可复用组件
  • 维护修改记录(Git、文档)

Troubleshooting

故障排查

Override Not Working

重写未生效

  1. Verify correct path in
    /templates/[active]/html/
  2. Clear cache (System > Clear Cache)
  3. Verify file permissions (755 folders, 644 files)
  4. Verify PHP syntax (php -l file.php)
  5. Check error logs in
    /logs/
  1. 验证
    /templates/[active]/html/
    目录下的路径是否正确
  2. 清除缓存(系统 > 清除缓存)
  3. 验证文件权限(文件夹755,文件644)
  4. 验证PHP语法(执行php -l file.php)
  5. 查看
    /logs/
    目录下的错误日志

File Permissions

文件权限设置

bash
undefined
bash
undefined

Folders: read+execute

文件夹:可读+可执行

chmod 755 /templates/cassiopeia/html/
chmod 755 /templates/cassiopeia/html/

Files: read

文件:可读

chmod 644 /templates/cassiopeia/html/com_content/article/default.php
undefined
chmod 644 /templates/cassiopeia/html/com_content/article/default.php
undefined

Caching Issues

缓存问题

  • Clear cache in backend: System > Clear Cache
  • Template option: Style Edit > Caching
  • Verify router cache in configuration.php

  • 后台清除缓存:系统 > 清除缓存
  • 模板设置:样式编辑 > 缓存
  • 验证configuration.php中的路由缓存配置

Practical Case: Featured Articles

实战案例:特色文章展示

Objective: Display featured articles in card format
Steps:
  1. Create override:
    com_content/article/featured.php
  2. Create JLayout:
    layouts/joomla/custom/featured-card.php
  3. Use in override with JLayoutHelper::render()
  4. Assign custom CSS
See complete examples in
/referencias/

目标:以卡片形式展示特色文章
步骤:
  1. 创建重写文件:
    com_content/article/featured.php
  2. 创建JLayout:
    layouts/joomla/custom/featured-card.php
  3. 在重写文件中使用JLayoutHelper::render()调用
  4. 添加自定义CSS样式
完整示例请查看
/referencias/
目录

Quick Reference

快速参考

Common Paths

常见路径

ElementOriginalOverride
Article
com_content/views/article/tmpl/default.php
html/com_content/article/default.php
Blog item
com_content/views/category/tmpl/blog_item.php
html/com_content/category/blog_item.php
Category list
com_content/views/category/tmpl/default.php
html/com_content/category/default.php
Login module
modules/mod_login/tmpl/default.php
html/mod_login/default.php
JLayout image
layouts/joomla/content/intro_image.php
html/layouts/joomla/content/intro_image.php
Nav plugin
plugins/content/pagenavigation/tmpl/default.php
html/plg_content_pagenavigation/default.php
元素原始路径重写路径
文章
com_content/views/article/tmpl/default.php
html/com_content/article/default.php
博客文章项
com_content/views/category/tmpl/blog_item.php
html/com_content/category/blog_item.php
分类列表
com_content/views/category/tmpl/default.php
html/com_content/category/default.php
登录模块
modules/mod_login/tmpl/default.php
html/mod_login/default.php
JLayout图片
layouts/joomla/content/intro_image.php
html/layouts/joomla/content/intro_image.php
导航插件
plugins/content/pagenavigation/tmpl/default.php
html/plg_content_pagenavigation/default.php

Checklist - Creating an Override

创建重写的检查清单

  • Locate original file in core
  • Create
    /html/
    structure in template
  • Copy file to override location
  • Make modifications
  • Escape outputs correctly
  • Document changes in header
  • Test in browser
  • Clear cache
  • Verify at different resolutions
  • Use Template Manager to verify structure
  • 定位核心文件的原始路径
  • 在模板中创建
    /html/
    目录结构
  • 将核心文件复制到重写路径
  • 进行修改
  • 正确转义输出内容
  • 在文件头部添加修改文档
  • 在浏览器中测试
  • 清除缓存
  • 在不同分辨率下验证效果
  • 使用模板管理器验证目录结构

Useful Variables

常用变量

php
// Articles
$this->item->id
$this->item->title
$this->item->introtext
$this->item->text
$this->item->images (JSON)
$this->item->jcfields (custom fields)

// Parameters
$this->params->get('show_author')
$this->params->get('show_category')

// Modules
$this->module->id
$this->module->title
$this->params

// JLayout
$displayData (array of passed data)

php
// 文章相关
$this->item->id
$this->item->title
$this->item->introtext
$this->item->text
$this->item->images (JSON格式)
$this->item->jcfields (自定义字段)

// 参数相关
$this->params->get('show_author')
$this->params->get('show_category')

// 模块相关
$this->module->id
$this->module->title
$this->params

// JLayout相关
$displayData(传入的参数数组)

Additional Resources

额外资源