主题开发模型
主题用于替换 ClayBBS 的展示层。论坛控制器通过 theme_view('web/...') 查找视图:当前主题存在同路径文件时优先使用主题文件,找不到时回退默认视图。
原则:主题主要负责展示,不建议在主题中写复杂业务逻辑,也不要改变表单字段语义。付费主题授权无效时,论坛会自动回退默认主题。
主题命名规范
- slug:使用稳定英文标识,例如
clay_light。 - 视图路径:必须和默认视图相同路径,才能完成覆盖。
- 资源路径:建议统一放在主题
assets/下,不要污染主系统assets/。 - 版本:主题升级应保持同一 slug,并递增版本号。
主题目录结构
clay_light/ ├── market.json ├── theme.json ├── views/ │ ├── web/home/index.php │ ├── web/thread/show.php │ └── web/layouts/main.php ├── assets/ │ ├── css/theme.css │ └── js/theme.js └── README.md
theme.json:论坛端主题识别文件。views/:按默认视图路径覆盖页面。assets/:主题自己的 CSS、JS、图片资源。
theme.json / market.json
{
"type": "theme",
"slug": "clay_light",
"name": "Clay Light",
"version": "1.0.0",
"api_version": "1.0.0",
"min_core_version": "1.0.0",
"description": "一个主题开发示例",
"author": "你的名字"
}主题 slug 同样要求稳定。用户安装后,升级包应沿用同一个 slug。
api_version 声明主题依赖的 Extension API 版本,论坛切换主题时会检查兼容性。
market.json 用于提交官方市场;theme.json 用于论坛本地识别。
ThemeApi 方法速查
主题可通过 App\Extension\ThemeApi 获取当前主题、视图路径、资源 URL 和安全转义。
| 方法 | 说明 |
|---|---|
version() | 返回 ThemeApi 版本号 |
active() | 返回当前启用主题 slug;授权失效会返回 default |
view(path) | 按当前主题解析视图路径 |
assetUrl(path, slug) | 生成主题资源 URL;默认主题时返回站点根相对路径 |
cssTag(path, slug) | 生成主题 CSS link 标签 |
e(value) | HTML 转义 |
use App\Extension\ThemeApi as ClayTheme;
<link rel="stylesheet" href="<?= ClayTheme::e(ClayTheme::assetUrl('assets/css/theme.css')) ?>">
<img src="<?= ClayTheme::e(ClayTheme::assetUrl('assets/images/logo.svg')) ?>" alt="">视图覆盖规则
默认视图:
app/views/web/home/index.php
主题覆盖:
themes/clay_light/views/web/home/index.php
只覆盖你需要改动的页面即可,不需要复制全部默认视图。这样更容易跟随官方升级。
- 主题只覆盖通过
theme_view()渲染的前台视图;后台管理视图不属于主题覆盖范围。 - 控制器已大量使用
theme_view('web/...'),因此主题目录里的路径必须从views/web/开始保持一致。 - 布局文件也可以覆盖,例如
themes/clay_light/views/web/layouts/main.php,但必须保留必要的 CSRF、Hook、静态资源和底部脚本输出。
资源组织
assets/ ├── css/theme.css ├── js/theme.js └── images/logo.svg
- CSS/JS 文件命名要清晰,不要覆盖全局变量太多。
- 默认布局会通过
theme_assets()自动输出当前主题的assets/css/theme.css;如果覆盖布局,请保留等价的主题资源加载逻辑。 - 主题内引用资源建议使用
ThemeApi::assetUrl(),不要写死域名。 - 图片尽量压缩,避免主题包体积过大。
- 如果引入第三方库,要说明来源和许可协议。
样式与交互规范
- 移动端优先,避免大块固定宽度布局。
- 兼容暗色模式,优先使用系统 CSS 变量。
- 按钮、表单、列表保持简洁,不要过度装饰。
- 不要移除必要的 CSRF 字段、隐藏字段和提交按钮 name/value。
- 图片、头像、帖子卡片需要考虑长内容和空状态。
兼容与表单规则
- 不要删除表单中的
csrf_field()。 - 不要修改后端依赖的
name字段,例如标题、内容、板块 ID。 - 保留登录态、未登录态、空状态、错误提示。
- 列表页要测试长标题、无头像、无图片、多图、暗色模式。
- 主题只覆盖展示层,不应直接写数据库。
授权与付费主题
付费主题同样使用市场授权注入。主题包声明 license.required=true 后,论坛在安装、启用和渲染时会校验授权;授权无效时自动回退默认主题。
{
"type": "theme",
"slug": "premium_dark",
"name": "Premium Dark",
"version": "1.0.0",
"license": {
"required": true,
"protected_features": ["theme_activate", "theme_render"]
}
}- 官方站只会向已购买并绑定域名的站点注入有效授权。
- 论坛端启用付费主题前会校验授权。
- 授权失效或域名不匹配时,不会继续渲染该主题。
主题打包发布
- 复制示例主题工程并修改 slug/name/version/api_version。
- 按需覆盖页面视图,不要一次性复制全部默认视图。
- 补充主题 CSS/JS,并确认覆盖布局时仍加载主题资源、CSRF、Hook 和必要脚本。
- 测试登录/未登录、移动端、暗色模式、空状态、长内容、主题切换和授权失效回退。
- 确认没有运行数据、日志、上传文件、缓存、私钥、数据库配置、
license.json、market-license.json。 - 压缩主题根目录;市场安装器支持
market.json在 zip 根目录或slug/market.json,但解压后主题根目录必须包含theme.json。 - 提交官方审核。
公益开发者只能发布免费主题;普通开发者可以发布免费或付费主题。付费主题授权文件由官方站按购买和绑定域名动态注入,开发者不要把授权文件打进分发包。
主题示例工程
Clay Light 示例主题
成为开发者后下载包含 market.json、theme.json、api_version 声明、assets/css/theme.css、views/example-snippet.php 和 README。