RustForge 主题开发文档
基于 Tera 模板引擎,打造专属企业网站界面
📖 主题系统介绍
RustForge 使用 Tera 模板引擎渲染前端页面。一个主题就是一组模板文件,通过系统注入的变量展示网站内容。
主题支持模板继承、变量过滤器、动态加载、多语言翻译函数,以及钩子系统,允许插件在主题任意位置注入内容。
📁 主题文件结构
themes/
└── 你的主题名/
├── theme.toml # 主题元信息
└── templates/ # 模板目录
├── base.html # 基础布局(必须)
├── index.html # 首页(必须)
├── category.html # 分类列表页(必须)
├── content.html # 内容详情页(必须)
├── products.html # 产品列表页
├── product.html # 产品详情页
└── search.html # 搜索结果页
theme.toml 示例
name = "默认主题"
version = "1.0.0"
author = "你的名字"
description = "适合企业官网的简洁主题"
📊 可用模板变量
通用变量
| 变量名 | 类型 | 说明 |
|---|---|---|
nav_categories | Array | 导航分类列表(含子分类) |
site_config | Object | 网站设置(名称、SEO、Logo等) |
user_info | Object | 当前登录用户信息 |
lang | String | 当前语言代码(zh/en) |
lang_options | Array | 可用语言列表 |
hooks | Object | 所有钩子内容(键为钩子名,值为 HTML) |
category | Object | 当前分类对象(category.html) |
contents | Array | 当前分类内容列表(category.html) |
post | Object | 当前内容详情(content.html) |
body_html | String | Markdown 渲染后的 HTML |
latest_contents | Array | 最新发布内容(index.html) |
current_page / total_pages / pages | Number / Array | 分页数据 |
产品模块变量
| 变量名 | 类型 | 说明 | 页面 |
|---|---|---|---|
product | Object | 当前产品详情 | product.html |
variants | Array | 产品变体列表 | product.html |
product.images | Array | 产品图片列表 | product.html |
product.categories | Array | 产品分类 | product.html |
product.cover_image | String | 产品封面图 | product.html |
product.fullname | String | 产品全名 | product.html |
product.brand | String | 产品品牌 | product.html |
product.price | String | 产品价格 | product.html |
product.stock | String | 产品库存 | product.html |
product.points | String | 产品卖点(换行分隔) | product.html |
product.summary | String | 产品简介 | product.html |
product.description | String | 产品详细描述(HTML) | product.html |
product.dnote | String | 尺码表原始数据 | product.html |
product.slug | String | 产品 Slug | product.html |
product.sku | String | 产品 SKU | product.html |
products | Array | 产品列表 | products.html |
categories | Array | 产品分类列表(含计数) | products.html |
钩子变量详解
hooks 是一个对象,包含所有已注册的钩子内容。键为钩子名称,值为插件注入的 HTML 内容(支持多语言)。
| 钩子名 | 常见用途 | 示例位置 |
|---|---|---|
nav | 导航栏链接 | 顶部导航菜单 |
sidebar | 侧边栏内容 | 文章页右侧 |
footer | 页脚内容 | 页面底部 |
header | 头部额外内容 | <head> 或顶部横幅 |
body_end | 页面底部脚本 | </body> 前 |
custom_xxx | 自定义钩子 | 任意位置 |
sidebar_contact、home_banner,插件通过同名钩子注入内容即可。
🧱 核心模板详解
1. base.html
所有页面的骨架,定义 HTML 头部、导航栏、页脚。必须包含 {% block title %} 和 {% block content %}。
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{{ site_config.seo_title | default(value='RustForge') }}{% endblock %}</title>
{{ hooks.header | safe }}
</head>
<body>
<nav>
<ul>
<li><a href="/">首页</a></li>
{{ hooks.nav | safe }}
</ul>
</nav>
<main>{% block content %}{% endblock %}</main>
<footer>{{ hooks.footer | safe }}</footer>
{{ hooks.body_end | safe }}
</body>
</html>
2. index.html
变量:latest_contents、nav_categories、site_config、user_info、hooks。
{% extends "base.html" %}
{% block title %}{{ t(key="home", lang=lang) }} - {{ site_config.site_name }}{% endblock %}
{% block content %}
{{ hooks.home_top | safe }}
<section>...</section>
{{ hooks.home_middle | safe }}
{% for item in latest_contents %}<article>{{ item.title }}</article>{% endfor %}
{{ hooks.home_bottom | safe }}
{% endblock %}
3. category.html
根据 category.display_type 切换 list/gallery/page 模式,支持分页。
4. content.html
变量:post(文章对象)、body_html、hooks。
{% extends "base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<div class="flex flex-col md:flex-row gap-6">
<div class="flex-1">
<article><h1>{{ post.title }}</h1><div>{{ body_html|safe }}</div></article>
</div>
<div class="w-64">
{{ hooks.sidebar | safe }}
</div>
</div>
{% endblock %}
🔌 钩子系统
钩子系统允许插件在主题的任意位置注入内容,无需修改主题模板。主题开发者只需在模板中放置钩子占位符,插件即可动态填充内容。
- 主题与插件解耦,插件可独立更新
- 支持多语言(钩子内容中的
{{ key }}自动翻译) - 多个插件可向同一钩子追加内容,按顺序排列
- 钩子内容支持完整 HTML,灵活扩展
在主题模板中使用钩子
在任意位置插入钩子占位符,使用 {{ hooks.[name] | safe }} 语法:
<!-- 导航栏钩子 -->
<ul class="nav">
<li><a href="/">首页</a></li>
{{ hooks.nav | safe }}
<li><a href="/about">关于我们</a></li>
</ul>
<!-- 侧边栏钩子 -->
<aside class="sidebar">
{{ hooks.sidebar | safe }}
</aside>
<!-- 页脚钩子 -->
<footer>
{{ hooks.footer | safe }}
</footer>
| safe 过滤器,否则会被转义为纯文本。
钩子命名规范
建议使用语义化的钩子名称,便于插件开发者理解和使用:
| 钩子名 | 使用场景 |
|---|---|
nav | 导航栏菜单项 |
nav_end | 导航栏末尾 |
sidebar | 主侧边栏 |
sidebar_top | 侧边栏顶部 |
sidebar_bottom | 侧边栏底部 |
footer | 页脚区域 |
header | 头部(<head> 内或顶部) |
body_end | 页面底部(</body> 前) |
home_top | 首页顶部 |
home_bottom | 首页底部 |
content_after | 文章内容后 |
product_sidebar | 产品详情页侧边栏 |
- 在主题中预留足够的钩子位置,提升可扩展性
- 命名时考虑位置和用途,如
page_before_title、post_after_content - 同一页面可放置多个钩子,实现精细控制
- 钩子内容支持
{{ key }}多语言占位符,由插件语言包提供翻译
钩子内容的多语言支持
插件在钩子内容中可使用 {{ key }} 占位符,主程序会自动替换为对应语言的翻译:
<!-- 插件保存的钩子内容 -->
<li><a href="/plugins/wuyun/">{{ wuyun_title }}</a></li>
<!-- 渲染后(中文) -->
<li><a href="/plugins/wuyun/">五运六气</a></li>
<!-- 渲染后(英文) -->
<li><a href="/plugins/wuyun/">Five Yun and Six Qi</a></li>
翻译键(如 wuyun_title)由插件语言包(plugins/{name}/locales/*.json)提供。
调试钩子
如需查看当前页面所有钩子的内容,可在模板中临时添加:
<!-- 调试所有钩子 -->
<pre>{{ hooks | json_encode | safe }}</pre>
或在浏览器控制台检查网络请求,确认钩子数据是否正确加载。
🛒 产品模块模板
RustForge 提供完整的产品展示功能,包含产品列表、产品详情、尺码表、产品属性等。
1. products.html - 产品列表页
展示所有产品,支持分类筛选、关键词搜索、排序和分页。
可用变量:
products- 产品列表数组categories- 产品分类列表(含产品数量)current_page- 当前页码total_pages- 总页数total- 总产品数hooks.product_list_top- 列表顶部钩子hooks.product_list_bottom- 列表底部钩子
2. product.html - 产品详情页
展示产品完整信息,包括图片、变体选择、尺码表、产品属性等。
可用变量:
product- 产品对象(包含所有产品字段)variants- 变体列表(含颜色、尺码、价格、SKU等)product.images- 产品图片列表(含颜色代码)hooks.product_sidebar- 产品页侧边栏钩子
🌐 多语言支持
主题模板可以直接使用 t() 翻译函数,该函数从主程序语言包和已启用插件语言包中查找翻译。
{{ t(key="home", lang=lang) }}
{{ t(key="read_more", lang=lang) }}
产品模块相关翻译键:
| 翻译键 | 中文 | 英文 |
|---|---|---|
products | 产品 | Products |
color | 颜色 | Color |
size | 尺码 | Size |
buy_now | 立即购买 | Buy Now |
in_stock | 有货 | In Stock |
out_of_stock | 缺货 | Out of Stock |
size_chart | 尺码表 | Size Chart |
product_attributes | 产品属性 | Product Attributes |
product_highlights | 产品卖点 | Highlights |
product_summary | 产品简介 | Summary |
product_details | 产品详情 | Details |
price_low_to_high | 价格低到高 | Price Low to High |
price_high_to_low | 价格高到低 | Price High to Low |
unit_cm | 厘米 | cm |
unit_inch | 英寸 | inch |
导航栏语言切换示例:
<div>
{% for opt in lang_options %}
<a href="#" onclick="switchLang('{{ opt.code }}'); return false;">{{ opt.name }}</a>
{% endfor %}
</div>
<script>
function switchLang(lang) {
document.cookie = 'lang=' + lang + ';path=/;max-age=31536000';
location.reload();
}
</script>
语言包文件位于 locales/ 目录,系统自动加载主程序和已启用插件的翻译。
🛠️ 开发与定制主题
- 在
themes/下新建目录,创建theme.toml和templates/ - 至少包含
base.html、index.html、category.html、content.html - 产品模块需要
products.html和product.html - 建议在关键位置添加钩子(导航栏、侧边栏、页脚、首页区块等)
- 在后台主题管理页面激活新主题
注意事项
- 必须保留
{% block content %}和{% block title %} - 使用
|safe过滤器输出 HTML(如 product.description、钩子内容) - 日期格式化:
|date(format="%Y-%m-%d") - 翻译函数:
{{ t(key="xxx", lang=lang) }} - 钩子输出:
{{ hooks.nav | safe }} - 产品图片按颜色分组需要
color_code字段匹配 - 尺码表需要后端 API
/api/public/products/:id/size-table支持 - 产品属性需要后端 API
/api/public/products/:id/attribute-values支持
颜色代码映射
产品图片按颜色分组需要颜色代码映射文件 /config/color_codes.json:
{
"color_map": {
"BL": "Black",
"RD": "Red",
"BLUE": "Blue",
"PR": "Purple"
},
"color_name": {
"BL": "Black",
"RD": "Red",
"BLUE": "Blue",
"PR": "Purple"
}
}
变体颜色名称与图片颜色代码通过此映射关联,实现颜色分组展示。
- 预留钩子:在导航、侧边栏、页脚、内容前后等位置放置钩子
- 命名清晰:使用语义化名称,如
sidebar_contact、home_banner - 安全输出:始终使用
| safe过滤器输出钩子内容 - 多语言支持:钩子中的
{{ key }}会被自动翻译,无需额外处理