Skip to content

MacCMS 模板二次开发实战 +「Skill 策略」 ​

想给自建的 MacCMS 站点换个样子——改配色、加一块推荐榜、把列表改成瀑布流、顺手适配一下手机——其实都是在动「模板」。本文结合 MacCMS V10(magicblack/maccms10)真实源码,讲清模板到底长什么样、那些 {maccms:...} 标签怎么来的、改完怎么生效;再给出一套把这些经验沉淀成「Skill 策略」的方法,让 AI 助手按规矩帮你改模板。

读之前先了解整体架构

本文只聚焦「模板二开」。MacCMS 的整体架构(ThinkPHP 5.0.24、三入口、请求生命周期、API 两套)在源码结构分析里讲过,本文不重复,涉及底层时直接引用那篇。

结论来自实际读源码

下面所有路径、标签名、配置项都来自实际阅读 d:\maccms10 源码(只读,未改动任何源码文件)。不同发行版的目录可能略有增减,以你本地源码为准。

一、模板目录长什么样 ​

MacCMS 的前台模板都放在源码根目录的 template/ 下。源码自带一套名为 default 的模板集:

template/
└── default/                 # 一套完整模板集(可以有多套,如 template/1、template/2)
    ├── info.ini             # 模板信息文件
    ├── config.defaults.json.example  # 模板主题配置示例
    ├── asset/               # 该模板自带的静态资源
    │   ├── css/  js/  img/  fonts/  language/ ...
    ├── images/              # 模板图片
    └── html/                # 模板文件主目录(真正要改的在这里)
        ├── index/           # 首页
        ├── vod/             # 视频模块(详情/播放/分类/搜索…)
        ├── art/             # 文章模块
        ├── user/            # 用户中心
        ├── public/          # 全站公共片段(头、尾、引入文件、分页…)
        ├── module/ widget/  # 可复用的页面区块
        ├── topic/ actor/ role/ manga/ website/ plot/ ...  # 其它内容模块
        ├── comment/ gbook/  # 评论、留言本
        ├── map/ rss/        # sitemap、RSS
        └── ads/             # 广告位片段

规律很清晰:一套模板 = 一个 template/模板名/ 目录,里面 html/ 按「业务模块」分子目录,asset/(或 css/js/images)放这套模板自己的样式脚本。想做一套全新皮肤,常见做法是复制 default 为 template/mytheme,在副本里改,不动原版。

html/ 下几个最常打交道的目录:

目录放什么
index/首页 index.html
vod/视频相关页:detail.html(详情)、play.html(播放)、type.html(分类)、show.html(筛选)、search.html(搜索)等
art/文章相关页,结构与 vod 对应
user/用户中心各页(登录、注册、收藏、充值…)
public/全站公共片段:include.html(引入 js/css)、head.html(头部)、foot.html(尾部)、paging.html(分页)等
module/、widget/可被各页 include 的可复用区块(如首页榜单、标签墙)
ads/广告位片段

自带标签速查表就在源码里

源码 说明文档/标签说明.txt 是一份完整的模板文件清单 + 标签字段表(视频/文章/演员/专题等每个模块能用哪些字段、列表标签支持哪些筛选参数)。改模板时把它当字典查最省事——但标签的实际行为以源码为准(见下一节)。

二、模板标签引擎:{maccms:…} 是怎么来的 ​

MacCMS 的模板不是纯 HTML,而是在 ThinkPHP5 原生模板引擎之上扩展了一套自有标签。两层关系要分清:

底层:ThinkPHP5 的 Think 模板引擎 ​

application/config.php 的 template 配置段里写死了引擎类型和标记:

php
'template' => [
    'type'         => 'Think',   // 用 TP5 自带的 Think 模板引擎
    'view_path'    => './template/',
    'view_suffix'  => 'html',
    'tpl_begin'    => '{',        // 普通标签 {$var}
    'tpl_end'      => '}',
    'taglib_begin' => '{',        // 标签库标签 {maccms:xxx}
    'taglib_end'   => '}',
    'taglib_pre_load' => 'app\common\taglib\Maccms',  // 预加载 MacCMS 标签库
],

所以模板里能直接用 TP5 原生语法:

  • 输出变量:{$maccms.site_name}、{$obj.vod_name}
  • 引入片段:{include file="public/head"}
  • 条件判断:{if condition="$obj.vod_jumpurl neq ''"}...{/if}
  • 循环:{volist name="list" id="vo"}...{/volist}
  • 调用函数:{:mac_url_vod_detail($obj)}、{:mac_url_img($vo.vod_pic)}

上层:MacCMS 自己的标签库 TagLib ​

关键在那行 taglib_pre_load——它把 app\common\taglib\Maccms 预加载进了模板引擎。这个类(源码 application/common/taglib/Maccms.php)继承自 TP5 的 think\template\TagLib,用 $tags 数组声明了所有自定义标签和它们支持的属性:

php
class Maccms extends Taglib {
    protected $tags = [
        'type'  => ['attr' => 'order,by,start,num,id,ids,...'],
        'vod'   => ['attr' => 'order,by,start,num,type,class,tag,area,year,level,...'],
        'art'   => ['attr' => '...'],
        'actor' => ['attr' => '...'],
        'topic' => ['attr' => '...'],
        'link'  => ['attr' => '...'],
        'foreach' => ['attr' => 'name,id,key'],
        // 还有 area / lang / year / class / version / comment / gbook / manga / website ...
    ];
    // 每个标签对应一个 tagXxx() 方法,把 {maccms:vod ...} 编译成底层 PHP + volist 循环
    public function tagVod($tag, $content) { ... }
}

工作原理:模板里写 {maccms:vod num="6" order="desc" by="hits_month"}...{/maccms:vod},引擎在编译阶段调用 tagVod(),它内部把标签翻译成「查数据 + {volist} 循环」的底层代码。所以**{maccms:xxx} 本质是 TP5 TagLib 的语法糖**,循环体里再用 {$vo.字段名} 取每条记录的字段。

一个真实的首页热门推荐片段(取自 template/default/html/index/index.html):

html
<ul class="img-list">
    {maccms:vod num="6" level="1,2,3,4,5,6,7,8,9" order="desc" by="hits_month"}
        {notempty name="vo"}{include file="widget/vod_box"}{else}{include file="public/notempty"}{/notempty}
    {/maccms:vod}
</ul>

这段的意思:取月点击量最高的 6 条视频,循环里把每条交给 widget/vod_box 片段渲染;没有数据就渲染占位片段。

列表标签的常用筛选属性

{maccms:vod} / {maccms:art} 这类列表标签支持一大把筛选属性:num(条数)、order(asc/desc)、by(time/hits/hits_month/level/rnd…)、type(分类)、class(扩展分类)、area/lang/year(地区/语言/年代)、level(推荐值)、ids(指定 id)、not(排除 id)、paging="yes"(翻页)等。完整清单看源码 说明文档/标签说明.txt。

三、静态资源:asset 与 static_new 怎么分工 ​

模板里引用静态资源,统一用全局变量拼路径,而不是写死域名:

  • {$maccms.path}:网站根目录(带末尾斜杠),指向站点根。
  • {$maccms.path_tpl}:当前模板目录,等价于 template/当前模板名。

实际源码里两类资源并存:

html
<!-- 模板自带资源:跟着这套皮肤走 -->
<link rel="stylesheet" href="{$maccms.path}template/default/asset/css/index.css?v=xxx">
<img src="{$maccms.path_tpl}/images/la/home-icon10.png">

<!-- 全站共享资源:所有模板通用,如播放器库 -->
<script src="{$maccms.path}static_new/player/dplayer/flv.min.js"></script>

分工大致是:

位置作用
template/模板名/asset(或 css/js/images)这套模板专属的样式、脚本、图片,换皮肤就跟着换
static / static_new全站共享的基础资源(播放器 DPlayer、layui、字体、公共 js 等),不随模板切换

加版本号防缓存

源码里大量 ?v=202604169 这样的版本参数,就是改完 css/js 后强制浏览器重新拉取。你自己改样式后,顺手把版本号加一,省得读者看到旧样式。

四、后台怎么配置与编辑模板 ​

选用哪套模板 ​

当前用哪套模板、html 目录叫什么,存在 MacCMS 配置里(源码 application/extra/maccms.php 的 site 段):

php
'site' => [
    'template_dir'     => 'default',  // PC 端用的模板集目录名
    'html_dir'         => 'html',     // 模板文件子目录名
    'mob_status'       => '0',        // 是否启用独立手机模板
    'mob_template_dir' => 'default',  // 手机端模板集
    'mob_html_dir'     => 'html',
    'ads_dir'          => 'ads',      // 广告位目录
    // ...
],

这些值由后台「网站参数配置」里的模板选项写入,不建议手改配置文件。切换模板,本质就是把 template_dir 指到另一个 template/xxx 目录。mob_status=1 时手机端会走 mob_template_dir 那套独立模板。

在线编辑模板文件 ​

后台自带一个模板文件管理器(源码 application/admin/controller/Template.php):它读的就是「当前模板」目录(config('maccms.site') 里的 template_dir + html_dir),能在浏览器里直接浏览、编辑 html/ 下的模板文件和 ads/ 广告位。

这个入口只允许改模板目录

Template::index() 对路径做了限制:请求的 path 必须以 .@template 开头,并且会剔除 /、\ 等字符、限制层级,防止越权读写模板目录以外的文件。也就是说后台模板编辑器设计上只让你碰 template/ 下的东西,这是好事——别想着用它去改框架文件。

五、实操:改一个页面 ​

目标:把首页「热门推荐」默认取 6 条改成 10 条,并换个排序。

  1. 定位文件。首页在 template/default/html/index/index.html(default 换成你实际在用的 template_dir)。

  2. 找到标签。搜到那段 {maccms:vod num="6" ... by="hits_month"}。

  3. 改属性。把 num="6" 改成 num="10",想按最新更新排就把 by="hits_month" 换成 by="time":

    html
    {maccms:vod num="10" level="1,2,3,4,5,6,7,8,9" order="desc" by="time"}
        {notempty name="vo"}{include file="widget/vod_box"}{else}{include file="public/notempty"}{/notempty}
    {/maccms:vod}
  4. 清缓存看效果。MacCMS 会缓存编译后的模板和页面。改完如果前台没变化,去后台清一次缓存,或删掉 runtime/ 下的缓存文件(runtime 目录可写,见源码结构分析),再刷新前台。

两条红线

  • 别动 thinkphp/ 核心:模板二开只该碰 template/ 和它的 asset。改框架文件会在升级时被覆盖,还可能破坏安全补丁(见安全加固)。
  • 别破坏标签语法:{maccms:vod} 必须成对闭合 {/maccms:vod},{if}/{volist}/{include} 同理。少一个闭合标签,整页编译报错白屏。

常见「改一个页面」的落点:

  • 换配色/字体 → 改 template/模板名/asset/css/*.css,加版本号。
  • 加一块推荐榜 → 在目标页复制一段 {maccms:vod ...}{/maccms:vod},改 by/type/num。
  • 改列表卡片样式 → 多半在 widget/vod_box.html 这类可复用片段里。
  • 适配移动端 → 要么在现有模板写响应式 css,要么开 mob_status 用独立手机模板。

六、Skill 策略:把模板二开交给 AI 来做 ​

上面这些改动有个共同点:重复、套路化、边界清晰。换配色、加版块、改卡片、适配移动端——每次的步骤几乎一样。这正适合沉淀成一套「Skill 策略」,让 AI 助手照着执行。

这里说的「Skill」是方法论

本节的「Skill 策略」指的是你写给 AI 的一套结构化指令/检查清单/提示词模板,不是某个具体软件的插件。核心思想:把「怎么改 MacCMS 模板」这件事从你脑子里的经验,变成一份可复用、可交给 AI 执行的文档。

什么是「Skill 策略」 ​

一句话:把一类重复的模板改造任务,抽象成结构化的指令集 + 检查清单。好处是——

  • 你不用每次从头交代背景,AI 一上来就知道 MacCMS 的目录和标签。
  • 改动有固定步骤和验证环节,不容易漏(比如忘了清缓存)。
  • 把「不能碰什么」写死,AI 不会手滑去改框架核心。

一套合格的模板二开 Skill 策略应包含的要素 ​

要素内容
目标描述这次要达成什么效果(换色/加版块/改列表/移动端适配),尽量给出可验收的标准
模板定位方法当前模板在 template/{template_dir}/html/{模块}/;公共片段在 public/、module/、widget/
标签知识{maccms:vod/art/...} 列表标签 + {$obj.字段};筛选属性查 说明文档/标签说明.txt
改动步骤定位文件 → 改标签/样式 → 加版本号
验证方法清 runtime 缓存(或后台清缓存)→ 前台刷新核对效果
不可触碰边界不改 thinkphp/ 核心、不改 vendor/;标签必须成对闭合;不写死域名用 {$maccms.path}

可直接套用的策略模板 ​

策略模板 A:通用「改一个前台页面」清单

text
# Skill:MacCMS 模板改一个页面

## 背景(固定)
- 站点:MacCMS V10(ThinkPHP5),模板引擎 Think + 自定义 TagLib。
- 当前模板目录:template/{template_dir}/html/,{template_dir} 默认 default。
- 资源路径用 {$maccms.path}(站点根)、{$maccms.path_tpl}(当前模板目录)。

## 输入(每次填)
- 页面:<首页 / 视频详情 / 分类页 / ...>
- 想要的改动:<一句话目标>

## 执行步骤
1. 按模块定位 html 文件(首页=index/index.html,视频详情=vod/detail.html…)。
2. 只改该文件内的标签/HTML/样式;复用区块优先改 widget/ 或 module/ 下的片段。
3. 用到数据列表时,用 {maccms:vod ...}{/maccms:vod} 并保证闭合;字段用 {$vo.字段名}。
4. 改 css/js 后在引用处把 ?v= 版本号 +1。

## 验证
- 清 runtime 缓存(或后台清缓存)→ 打开对应前台页面核对。
- 页面不白屏、标签全部成对闭合、无 PHP 报错。

## 禁止
- 不修改 thinkphp/、vendor/ 任何文件。
- 不写死协议/域名;不在模板里放密钥。
- 不破坏 {maccms:...}/{if}/{volist}/{include} 的成对语法。

策略模板 B:「加一块推荐版块」最小提示词

text
在 template/{template_dir}/html/index/index.html 的 <目标位置> 新增一块「<版块名>」:
- 用 {maccms:vod num="10" type="<分类id或all>" order="desc" by="<time|hits_month|level>"} 取数据;
- 循环体复用现有卡片片段(如 {include file="widget/vod_box"}),没有则按同页其它卡片的 class 结构写;
- 标签必须 {/maccms:vod} 闭合;
- 新增/改动 css 放到 template/{template_dir}/asset/css/ 并在引用处加版本号;
- 完成后提示我清缓存并给出需要核对的前台 URL。
不要改 thinkphp/ 和 vendor/,不要写死域名。

安全与可维护(策略里务必写死) ​

把 AI 当成一个会照做的新手,边界必须显式写进策略:

  • 输出转义防 XSS:模板里凡是回显用户可控内容(评论、留言、搜索词),用转义输出,别直接 {$var|raw} 原样打印。
  • 不在模板写死密钥:接口 key、第三方令牌放配置,不要硬编码进 html。
  • 改动走版本管理:改模板前先 git 托管这套 template/模板名/,每次改动留提交记录,出问题能回滚。
  • 先备份再大改:换皮肤复制 default 为新目录改副本,别在原版上直接动刀。

相关文档 ​