Files
wordpress-kratos-yang/README.md
T
laoyang ba1245191c README.md 整体重写:讲功能与用法,删掉更新机制与一堆过期说法 #37
用户要求「readme 需要全部重写,主要介绍功能用法,不要写更新机制」。
注意对象是**仓库的 README.md**,不是线上后台详情页那份 readme.html —
先前 #36 我理解错了对象,那是另一份文档。

删掉的更新机制内容:主题自动更新 / update.json 格式 / 发布新版本的顺序 /
自动升级会覆盖主题目录 / 换域名退役旧域名。

更要紧的是原文里有好几处**已经和代码不符**,重写时逐条对着代码核过:

- 「移动端侧边栏只在首页,文章页为减少数据传输仍没有」——
  这条其实**一直是对的**,我一度把它当成过期说法,是因为只 grep 了
  PHP 里有没有 dynamic_sidebar(),没看它外面那个 div 的 class。
  实际 single.php:121 是 `d-none d-lg-block`(小屏 CSS 隐藏),
  index.php:40 是 `d-lg-block`(小屏可见);且文章页侧栏另受
  「文章配置 → 页面布局」g_article_widgets 控制,选单栏时整段不输出。
  真相比"过期"复杂,按实况写清两层。
- 「文章聚合 widget 将最新文章优先显示」——已反转,现在是热点文章
  (widget_posts 内部换成 yang_hot_posts())。
- 「这些代码库都和源库保持一致和同步」——实测不成立:gitlab 镜像
  style.css 还是 3.2.0(源库 4.2.0)。改成"手动同步、不保证最新"。
- 阿里云 Code 镜像:该平台已下线,死链,删除。
- 旧 README 的七条「主要修改」里只有三条半还成立,且这种
  「相对上游做了啥」的写法本身不可持续,整段不要。

新增的主体是后台 16 个分组逐项对照代码写:真实键名、真实默认值
(std)、以及几处方向容易记反的开关(g_gutenberg 默认关=勾上才启用
区块编辑器;toc_float 默认关;a_lightbox_enable/a_highlight_enable/
stat_track_enable/toc_inline 默认开)。

两处刻意纠正的误解:
- 「Gravatar 加速」不是开/关替换,而是换哪个镜像——主题默认就把
  Gravatar 域名换成 cn.gravatar.com,勾选后换成 gravatar.loli.net。
- 自动头像是 PHP **服务端**生成(自实现 PRNG 与 DiceBear 逐字节一致),
  不是浏览器本地生成。

pages/ 那四个文件说清楚是 get_template_part()/require 引入的片段,
不是能在编辑器里选的页面模板(它们没有 Template Name 头)。

**版本号不写死数字**:#35 刚立了「版本号只留一份真源」的规矩,
README 再抄一份 4.2.0 等于自打脸,改成指向 style.css。
判据里专门有一条判这个,注入 `4.2.0` 会红。

只提交仓库、不重新发版:纯文档改动不该逼所有站点强制升级。

判据三层(都是对着代码写的,不是照着旧文案改字眼):
- _readme37_check.py  45/0,且同一套跑旧 README 命中 15 条(有区分力)
- _readme37_falsify.py 13/13
- _readme37_meta.py   10/10

判据自身在写反证时被改坏过三次,都是「判词出现过」冒充「判结构」:
E 组(删参数表格一行仍绿,因为示例行自带那些词)、
I 组(改错一处套数仍绿,因为另一处还对)、
K 组(### 降级成 #### 仍绿,因为"不跳级"抓不到差 1 的降级)。
三条全部改成判一致性/表格行。
2026-10-28 20:54:09 +08:00

500 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kratos Yang
一个给中文技术博客用的 WordPress 主题。上游是 [Kratos](https://github.com/seatonjiang/kratos),fork 出来之后按自己的写作习惯一路改到现在,改成了一个偏「写作与阅读」的形状:写的时候少折腾,读的时候少干扰,后台能看见的东西尽量不靠插件。
- 主题预览:<https://yangyq.net>
- 源码主仓库:<https://code.yangyq.net/laoyang/wordpress-kratos-yang>
- 协议:MIT。上游 Kratos 的版权归属见 `LICENSE`。
当前版本号看 `style.css` 头部的 `Version:` 字段——**那是版本号唯一的地方**,JS 和控制台输出的版本都由它派生。
## 环境要求
| | |
| --- | --- |
| PHP | 7.0 以上(`style.css` 的 `Requires PHP: 7.0`) |
| WordPress | 开发机与线上实测均在 7.1.x;主题只用到 `add_theme_support` / `register_sidebar` / `wp_get_theme` 这些很成熟的 API,但**低版本没有实测过** |
| 数据库 | 跟随 WordPress 本身的要求 |
`style.css` 没有声明 `Tested up to`,所以上面 WordPress 那一行请当作「已知可用的环境」,不是「验证过的最低版本」。
主题**不依赖任何插件**。代码高亮、图片灯箱、自动目录、评论表情、SMTP 发信、访问统计面板都是主题自带——装了同类插件反而会打架,原因见文末「已知冲突」。
## 后台设置:16 个分组
设置页左侧是分组标签,右侧只显示当前那一组。想找某项设置先看左边。
### 一、全站配置
| 项 | 键 | 默认 | 说明 |
| --- | --- | --- | --- |
| 图片 Logo | `g_logo` | 主题自带 | 留空用默认图 |
| Favicon 图片 | `g_icon` | 主题自带 | 浏览器标签页小图标 |
| 背景颜色 | `g_background` | `#f5f5f5` | 内容区背景,输出在 `k-main` 的 `style` 上 |
| Chrome 导航栏颜色 | `g_chrome` | — | 只影响移动端 Chrome 的地址栏配色 |
| 404 页面图片 | — | 主题自带 | 走错地址时的插画 |
| 前台管理员导航 | `g_adminbar` | **开** | 关掉后管理员在前台看不到顶部黑色工具条 |
| CSS 动画库 | `g_animate` | **关** | 开:加载 `animate.min.css`,卡片进场有动效;关:少一个请求 |
| Gravatar 加速 | `g_gravatar` | **关** | 见下方说明 |
| 禁止生成缩略图 | `g_removeimgsize` | **关** | 开:停止生成 thumbnail / medium / large / medium_large 四档。只影响**之后**上传的图,已有图片不受影响 |
| Gutenberg 编辑器 | `g_gutenberg` | **关** | 默认就关——勾选才会**启用**区块编辑器。关闭时主题会连前端的 block-library CSS 一起卸掉 |
关于 **Gravatar 加速**,这里有个容易被选项名误导的细节:
主题**默认就把所有 Gravatar 域名替换成 `cn.gravatar.com`**(不管开关)。勾选「加速」后换的是 `gravatar.loli.net`。也就是说这个选项不是「开/关替换」,而是「换哪个镜像」。两种情况下顺带都把 `http://` 升级成 `https://`。
> 为什么这很关键:`cn.gravatar.com` 在部分网络环境下同样不通。如果你发现头像仍然是破图,先确认这个开关的状态,再确认你的网络能不能通到所选镜像。**彻底不依赖 Gravatar 的办法是开「二、自动头像」**(见下)。
### 二、自动头像
没上传过头像的访客,不该是一个灰色神秘人。
| 项 | 键 | 默认 |
| --- | --- | --- |
| 启用自动头像 | `a_auto_enable` | **关** |
| 注册用户保留原头像 | `a_auto_keep_member` | **开** |
| 头像风格 | `a_auto_style` | 18 套可选 |
开启后,主题按评论者**邮箱地址**生成一张 SVG 头像,以 `data:image/svg+xml;base64,…` 内联输出。**服务端生成、不落盘、不请求任何外部服务**(单次渲染实测 0.09~0.15 ms,比一次磁盘 stat 还便宜,所以没必要缓存到文件)。
- 算法与图形素材来自 DiceBear 9.x。主题把各风格的图形模板「编译」成了纯 PHP 数组(`inc/avatar-styles/*.php`,共 18 个文件),运行时不执行任何 JS。
- 为了和 DiceBear 官方预览页**逐字节一致**,主题自己实现了 PRNG:DiceBear 9.x 用 xorshift + 自定义 hashSeed,全程在 JS 的 32 位有符号整数域里运算,而 PHP 整数是 64 位,必须逐步截断到 int32。不这么做,同一邮箱在两边会得到两张不同的脸。
- 18 套风格全部可自由商用且不要求署名(CC0,或作者自定义的「个人与商业可用」条款)。后台点风格名能看到实时预览。
- 尺寸按实际显示需求生成,上限 256px(再大模板会被撑得没必要地大)。
**一个必须知道的取舍。** WordPress 的 `get_avatar()` 从不去查 Gravatar 上到底有没有这张图,它只负责拼 URL;返回真人图还是默认图,是 Gravatar 服务端在加载时才决定的。这意味着**服务端无法在离线状态下区分「这个邮箱有 Gravatar」和「没有」**——任何声称能精确判断的写法都要发一次外网请求,而 `gravatar.com` 在国内基本全超时。
所以主题的判据退了一步:`src` 指向 Gravatar 家族、**且**该邮箱不属于本站注册用户 ⇒ 替换成生成图;本站用户、媒体库图片、外链头像、已经是 `data:` 的(说明别的插件给过了)一律放行。
代价:如果你开了「Gravatar 加速」并且匿名访客确实有 Gravatar 头像,这里仍会盖掉他的图。相比「多数访客是一张破图」,「偶尔盖掉一个匿名访客的真实头像」伤害更小。
### 三、顶部导航
| 项 | 键 | 默认 |
| --- | --- | --- |
| 顶部样式 | `top_select` | 图片导航 |
| 图片导航背景 | `top_img` | 主题自带 |
| 颜色导航背景 | `top_color` | — |
| 副标题 | `top_title` | — |
| 标题描述 | `top_describe` | — |
图片导航背景、颜色导航背景分别是上面两种样式用的;选了另一种时该项不生效。
### 四、首页配置
| 项 | 键 | 默认 | 说明 |
| --- | --- | --- | --- |
| 特色图片 | `g_thumbnail` | **开** | 首页文章列表每篇标题上方显示一张配图 |
| 默认特色图 | `g_postthumbnail` | 主题自带 | 文章**既没有正文图片、也没设特色图**时顶上 |
| 无内容图片 | `g_nothing` | 主题自带 | 搜不到结果、或分类下还没有文章时的插画 |
### 五、文章配置
| 项 | 键 | 默认 | 说明 |
| --- | --- | --- | --- |
| 页面布局 | `g_article_widgets` | 双栏 | **文章详情页要不要侧边栏**,单栏/双栏两张图直接点选。只影响文章页,首页不受它管 |
| 文章打赏 | `g_donate` | **关** | 开启后文章末尾出打赏按钮,点开是收款码 |
| 支付宝收款码 | `g_donate_alipay` | 主题自带 | |
| 微信收款码 | `g_donate_wechat` | 主题自带 | |
侧栏的实际可见性还多一层:文章页的侧栏容器 class 是 `col-lg-4 sidebar d-none d-lg-block`,**小屏(<992px)本来就隐藏**;选「单栏」时主题干脆不输出这段 HTML,连 DOM 都没有。首页的侧栏是 `col-lg-4 sidebar d-lg-block`,所以移动端首页仍然显示侧栏。
### 六、自动目录
长文必备。**正文里那份和浮层那份是两个独立开关,不是二选一**,可以同时开——两份目录指向同一批锚点,点哪份都跳同一处。
正文里那份:
| 项 | 键 | 默认 |
| --- | --- | --- |
| 在正文中显示 | `toc_inline` | **开** |
| 正文中的对齐 | `toc_inline_align` | — |
| 添加方式 | `toc_mode` | — |
| 自动插入位置 | `toc_anchor` | — |
| 正文目录的默认状态 | `toc_inline_default` | — |
浮层那份:
| 项 | 键 | 默认 |
| --- | --- | --- |
| 浮动显示 | `toc_float` | **关** |
| 浮动方向 | `toc_float_side` | — |
| 浮层目录的默认状态 | `toc_float_default` | — |
两份共用:目录标题 `toc_title`、显示序号 `toc_numbering`(默认关)。
「添加方式」控制自动模式(正文一个字都不用写,按 `toc_anchor` 插)与手动模式(按你写的 `[TOC]` 位置放)。只要正文里有 `[TOC]`,就只按你写的位置渲染正文那一份,不再重复插;但浮层那份独立判断——你写了 `[TOC]` 并不等于说「不要浮动目录」。
展开态写在 class(`is-open`)上而不是靠 JS 加,所以**禁用 JS 也能看到目录的默认状态**,JS 只负责之后的切换。
### 七、站长信息
个人头像 `a_gravatar`、个人昵称 `a_nickname`、个人简介 `a_about`。
这三项同时喂给两个地方:**「个人简介」挂件**,以及**文章页底部的作者栏**(`pages/page-toolbar.php`)。所以改这里,文章页的作者信息会跟着变。
### 八、页脚配置
| 项 | 键 | 说明 |
| --- | --- | --- |
| 版权信息 | `s_copyright` | 留空则自动用「COPYRIGHT © 当前年份 站点名称 版权所有」 |
| 是否显示国旗 | `g_flag` | 默认关 |
| 国旗图片 | `g_flag_url` | |
| 工信部备案信息 | `s_icp` | |
| 公安网备案信息 | `s_gov` | |
| 公安网备案链接 | `s_gov_link` | 公安备案没有可推导的统一格式,需单独填 |
### 九、哀悼模式
全站变灰,用于公祭日、地震纪念日等。
| 项 | 键 | 默认 |
| --- | --- | --- |
| 手动常开 | `g_rip` | **关** |
| 按纪念日自动哀悼 | `g_rip_auto` | **关** |
| 附加日期 | `g_rip_extra` | — |
| 说明页路径 | `g_rip_page_slug` | `memory` |
自动模式内置一批日期,按当天判断。日期分两类可信度,代码里也分开标注:
- **法定纪念日**(全国人大常委会决定设立、每年国家举行纪念活动):09-03 中国人民抗日战争胜利纪念日、09-30 烈士纪念日、12-13 南京大屠杀死难者国家公祭日。每个日期在源码里都写了设立依据的会议与文件出处。
- **民间广泛采用**(非法定,但主流网站普遍变灰):05-12 汶川地震纪念、09-18 九一八事变纪念。
「说明页」是变灰时页面顶部那个入口点进去的页面,解释「今天为什么是灰的」。它由主题按 slug 直接 `include` 模板,**绕开 WordPress 模板层级**,因此不受全站灰度滤镜影响——这一页必须是彩色的。
### 十、收录与统计
**SEO**:关键词 `seo_keywords`、站点描述 `seo_description`、分享图片 `seo_shareimg`(搜索引擎或社交工具分享首页时抓的卡片图,留空自动用主题自带默认图)。
**robots.txt**:这一组底部直接显示主题生成的 robots.txt 内容(Disallow `wp-admin` / `wp-includes` / `wp-content/plugins` / `wp-content/themes`)。
**统计埋点**:
| 项 | 键 | 默认 |
| --- | --- | --- |
| 统计代码 | `seo_statistical` | — |
| 启用统计埋点 | `stat_track_enable` | **开** |
「统计代码」是你粘第三方埋点 `<script>` 段的地方(百度统计、GA 等)。
**访问统计面板**——把百度统计的数字直接画在后台设置页,不用跳去他家网站看:
| 项 | 键 | 存储位置 |
| --- | --- | --- |
| API Key | `stat_api_key` | **凭据文件,不进 options 表** |
| Secret Key | `stat_api_secret` | **凭据文件** |
| refresh_token(高级) | `stat_refresh` | **凭据文件** |
| 站点 ID | `stat_site_id` | options 表 |
| 授权码 | `stat_auth_code` | **不落库**(一次性,换完 token 即弃) |
| 面板显示哪些指标 | `stat_metrics` | options 表 |
凭据单独存(复用写作引擎那套 `of_sanitize_password` 拦截),options 表里只留空串——所以一次「导出主题配置」不会把密钥带出去。副作用是表单永远回显空框,因此**「空值 = 不修改」而不是「清空」**;否则你每次保存别的设置都会把凭据抹掉。
面板的三个设计约束都是踩出来的:
1. **后台绝不能被 API 拖死**。百度统计的接口是同步 HTTP,对方超时默认要等 30 秒以上——设置页会因为一个"附加面板"卡住,你会以为主题坏了。所以连接超时压到 5 秒 + `blocking => false`,任何失败路径都返回数组(含 error 字段),渲染层只负责显示、不负责判断成败。整条链路没有一个 `wp_die()` 或异常外抛。
2. **站点 ID** 就是网站列表里点进站点后,地址栏 `siteId=` 后面那串数字。整条地址粘进去也行,会自动抠出数字。
3. 前台埋点仍走上面那个「统计代码」文本框,面板只负责取数与展示。
### 十一、邮件通知
| 项 | 键 | 默认 |
| --- | --- | --- |
| SMTP 服务 | `m_smtp` | **关** |
| 邮件服务器 | `m_host` | |
| 服务器端口 | `m_port` | |
| 授权方式 | `m_sec` | |
| 邮箱帐号 | `m_username` | |
| 邮箱密码 | `m_passwd` | 填密码或授权码均可 |
| (测试发送按钮) | `m_sendmail` | |
| 有人回复时发邮件通知 | `m_comment_notify` | **关** |
| 评论通过审核时通知评论者 | `m_comment_approved_notify` | **关** |
| 保留 WordPress 自带的作者通知 | `m_keep_core_notify` | **关** |
开启 SMTP 后 WordPress 的所有发信(找回密码、评论通知等)都走这里。填完点「邮箱密码」下面那个测试按钮直接发一封验证。
**最后那个开关值得单独说。** 装过 wpDiscuz 之类评论插件的人大概都遇过「一条评论收到好几封邮件」——插件的通知和主题/ WordPress 的通知完全重复。所以:
- 主题早期确实自己发过「回复通知」和「审核通过通知」,与 wpDiscuz 的通知完全重复,现已全部从 `theme-smtp.php` 移除;发信通道的接管逻辑统一在 `inc/theme-mail.php`。
- 上面三个开关**原先只有代码在读取、后台根本没有界面**,现在补齐了。想让别的插件发信,就把对应的关掉。
- `theme-mail.php` 接管 SMTP 的钩子优先级是 9999,并且会先判「配置不完整就不接管」「清掉别的插件残留配置」——避免两套 SMTP 配置互相覆盖。
- `m_keep_core_notify` 关掉时,WordPress 自己那套「作者收到新评论」的邮件也停掉。
### 十二、CDN 加速
把页面里指向本站的静态资源地址,前缀换成你的 CDN 地址。思路参考 CDN Enabler 插件,但只保留三件事:CDN 地址、白名单、黑名单(黑名单优先)。
勾选「启用 CDN 加速」`cdn_enable`(默认关)并填 `cdn_url` 才生效。
**改写发生在最终 HTML 的输出缓冲层,不是改 enqueue。** 原因很实际:主题自己 enqueue 的资源只有十来个,可以精确改;但文章正文里的图片、插件输出的样式、Gutenberg 区块的图片都绕过 enqueue、直接写死在 HTML 里。只在最终 HTML 上做,才能一次覆盖全部,主题自身资源也顺带覆盖,不必维护两套逻辑。
**硬编码的安全底线,不受白名单影响、不能放开**——站点被 CDN 改坏最常见的原因是「把页面地址也改了」:导航链接变成 CDN 域名 → 用户点一下就离开本站 → 全站 404。所以下面这些一律不改写:
- 以 `/` 结尾的地址(页面、栏目页)
- `.php` / `.html` / `.htm` 等页面或动态后缀
- `wp-admin` / `wp-login` / `wp-json` / `wp-cron` 等后台与接口路径
- 非本站域名(外链、别人家的 CDN)
- `data:` / `mailto:` / `tel:` / `javascript:` 等非 http(s) 协议
后台这一组里把「白名单写法」「这些地址永远不走 CDN」「后台与接口里不改写」三段说明直接列了出来,不用翻文档。
### 十三、图片灯箱
正文图片点一下在当前页放大,不跳走;多张图可左右切换,键盘方向键也能翻。
| 项 | 键 | 默认 |
| --- | --- | --- |
| 启用图片灯箱 | `a_lightbox_enable` | **开** |
| 遮罩配色 | `a_lightbox_theme` | |
| 遮罩不透明度 | `a_lightbox_opacity` | |
关掉后图片恢复成普通链接行为。
### 十四、代码高亮
**不依赖任何高亮插件**,主题自带一套(highlight.js 自托管)。Ender / Prism / Enlighter 那类可以卸掉——装多了反而打架,早期版本同时开两个,出现过复制按钮变两个、行号叠成重影。
| 项 | 键 | 默认 |
| --- | --- | --- |
| 启用代码高亮 | `a_highlight_enable` | **开** |
| 代码配色 | `a_highlight_theme` | |
| 显示行号 | `a_highlight_line_numbers` | **关** |
| 显示复制按钮 | `a_highlight_copy_button` | **开** |
| 自动识别代码语言 | `a_highlight_autodetect` | **开** |
- **20 套配色**:10 浅 + 10 深(GitHub、VS、Atom One、IntelliJ、Monokai、Night Owl、Dracula 系、Srcery、Panda 等)。选完在后台当场就能看到效果。
- **只加载你选中的那一套 CSS**。20 套全加在一起实测 19.3 KB(gzip 后 8.8 KB),不算大,但九成用不上的样式没必要拖在首屏。
- 语言标签显示在代码块左上角;代码围栏没写语言时去猜,猜不准标「可能」。
- 复制出去的代码**永远不含行号**——带行号粘出去没法直接跑。
- **深色配色会连着把代码卡片底色也变深**。这条要单独做,否则深色代码贴在白卡片上,看着像没加载完。
### 十五、写作增强
发布文章时自动生成摘要 / 分类 / 标签 / 英文别名。**四个引擎互不依赖,每个都能单独开关、单独失败**:
| 项 | 键 | 默认 | 依赖 |
| --- | --- | --- | --- |
| 自动生成摘要 | `w_on_excerpt` | **关** | 纯本地 |
| 自动选择分类 | `w_on_category` | **关** | 纯本地 |
| 自动生成标签 | `w_on_tag` | **关** | 本地优先,可选外部 |
| 每篇最多新增几个标签 | `w_tag_new_limit` | | |
| 自动生成英文别名 | `w_on_slug` | **关** | **必须外部翻译** |
| 翻译服务商 | `w_provider` | | |
| 接口超时(秒) | `w_timeout` | | |
标签为什么能本地做:站里已有的几百个标签本身就是最好的领域词典,不需要外部服务。
别名为什么**必须**外部服务:线上实测过三条路,只有第三条可用。
- `intl` 拼音:`信息焦虑综合症` → `xin-xi-jiao-lu-zong-he-zheng`。能用,但不是翻译,且长到没法看。
- 拿 966 组「中文标题 → 英文 slug」训练词对齐:5 个测试标题里 3 个**译出 0 个词**(数据摊到 8521 个中文片段上太稀疏)⇒ 不可用。
- 翻译 API:`信息焦虑综合症` → `Information Anxiety Syndrome` ⇒ 可用。
服务器没有 scws / jieba 任何中文分词扩展,「本地发现新词」这条路本身走不通——这是环境事实,不是偷懒。
翻译服务商可选:
| 服务商 | 要不要密钥 |
| --- | --- |
| MyMemory | **不要**,直接可用(每日有免费字符限额,超限会返回错误,届时可换百度) |
| 百度翻译 | 要 APPID + 密钥(免费版每月 5 万字符) |
| 有道翻译 | 要应用 ID + 应用密钥 |
**选完谁才显示谁的输入框**,不会三家密钥全摆着(靠 `yang-prov` / `yang-prov-<key>` 两个 class 做分组,声明处就在选项定义里)。每家怎么拿账号,后台对应位置写了分步说明。
**三条红线,改这块代码前先读:**
1. **绝不覆盖已有值**。用户原话:「别名可能意味着 url,url 变化了会造成大量的 404 错误」。所以 slug 只在为空时写,其它三项同理。
2. **绝不处理旧文章**。只在「第一次变成 publish」时触发;已在 publish 状态下再次保存 ⇒ 直接返回,一个字都不动。
3. **外部服务失败必须静默降级**。发布是主流程,不能让一个翻译接口超时把「发布」这个动作卡住或报红。
### 十六、自定义代码
| 项 | 键 |
| --- | --- |
| 自定义 CSS | `g_custom_css` |
| 自定义 JS | `g_custom_js` |
两段内容存在数据库的选项里,**升级、重装、改主题目录名都不受影响**。它们分别在主题样式表和主题脚本之后加载,优先级最高。
- 不需要写 `<style>` / `<script>` 标签,直接写 CSS / JS 内容。
- 内容不会被当作 HTML 处理,`>`、`<`、`~`、反斜杠转义(如 `content: "\f101"`)都原样保留。
- 想清空,把框里内容删掉保存即可。
## 短代码
### `[TOC]`
正文任意位置写一行 `[TOC]`,那里就长出目录。可带参数(都可省略):
```
[TOC title="本文目录" levels="1,2,3" numbering="1" toggle="0" open="0"]
```
| 参数 | 含义 |
| --- | --- |
| `title` | 这份目录的标题 |
| `levels` | 收哪些层级,认 `"1,2,3"` 写法;只收 h2/h3 就写 `"2,3"` |
| `numbering` | `1` = 条目前加 `1` / `1.1` 这样的序号,默认 `0` |
| `toggle` | 是否显示展开/收起按钮 |
| `open` | 默认是否展开 |
**手写参数优先于后台设置**,没写的项才回落到后台。
### `[Archives]`
年 / 月归档文章列表。在文章或页面正文任意位置写一行:
```
[Archives]
```
- 默认显示**今年**,按月份归类(只列有文章的月份)
- 每篇后面带**浏览数 / 评论数 / 点赞数**
- 列表四角各有「上一年 / 下一年」按钮
- 切年**纯 JS 重建 DOM,不刷新页面**
可调参数(都可省略):
```
[Archives year="2025" month="1" nav="1"]
```
| 参数 | 含义 |
| --- | --- |
| `year` | 首次显示哪一年,默认今年;也可用 `?arc_year=2025` 覆盖 |
| `month` | `1` 显示月份分组标题,`0` 只平铺列表。默认 `1` |
| `nav` | `1` 显示四角年份导航,`0` 不显示。默认 `1` |
同一页放两个 `[Archives]` 也只算一次数据。
为什么不用 WordPress 自带的 `wp_get_archives()`:三个原因,每个都足以否掉它——① 它拿不到计数,要显示浏览数/评论数/点赞数只能每篇再查一次,71 篇就是 71 次查询外加 2×71 次 meta 查询;② 输出格式固定(`<li><a>…</a></li>` 或下拉框),塞不进三项计数;③ 它按「按月 / 按年」二选一输出整条时间线,没有「给我某一年」的能力。主题改成**每次一条 SQL** 拿全部计数。
短代码标签区分大小写,`[archives]` 和 `[Archives]` 都认。
## 侧栏挂件
主题自己实现了 7 个,在「外观 → 小工具」里拖用:
| 挂件 | 说明 |
| --- | --- |
| 个人简介 | 读「七、站长信息」的头像 / 昵称 / 简介,可设背景图 |
| 最近评论 | 主题自建,替代 Comments Widget Plus 一类插件 |
| 文章聚合 | 热点文章(按热度,**不是**按时间) |
| 标签聚合 | 标签云,可设列数 |
| 文章分类 | 接管并美化了 WP 自带的那個(原生的没被主题接管、也没美化) |
| 图片广告 | 一张图 + 一个链接 |
| 搜索框 | 站内搜索输入框 |
三条使用须知:
- **标题都能在后台改**,不用动代码(早期「标签聚合」的标题是硬编码的,后台连输入框都没有)。
- **样式只依赖挂件自己的 class**(如 `.w-cats`、`.w-comments`),不写成 `.k-main .sidebar .w-cats`。因为「外观 → 小工具」的预览界面里**没有** `.k-main .sidebar` 那层祖先,依赖祖先的规则在后台预览会全部失效——你会以为样式没加载,其实只在前台生效。
- 「文章聚合 · 热点」曾经长期只显示 1 条,原因是候选池被设成了「最近 30 天发布的文章」——那个时间窗才是根因,现在改成按热度取。
## 主题里的复用片段
`pages/` 下的四个文件是**被其它模板引入的片段**(局部视图),不是可以在编辑器里选择的页面模板——它们不会出现在「模板」下拉里。
| 文件 | 被谁引入 | 渲染什么 |
| --- | --- | --- |
| `page-content.php` | `index.php` 经 `get_template_part()` | 首页列表里每一篇的卡片 |
| `page-toolbar.php` | `single.php` | 文章页底部的作者栏 + 分享 + 打赏 |
| `page-smilies.php` | `comments.php` | 评论框上方的表情选择条 |
| `page-mourning.php` | `inc/theme-mourning-page.php` 直接 `include` | 哀悼说明页(见「九、哀悼模式」) |
要新增一个真正的独立页面,走 WordPress 正常的新建页面流程即可,不需要碰这里。
## 评论区增强
评论区不需要装插件就有这些:
- **表情条**:`page-smilies.php` 输出的表情图标条,点一下往评论框插入 `:smile:` 这类代码,显示时换成图。主题把表情图片路径指向了自己的 `assets/img/smilies/`,不依赖 WordPress 安装目录里的那套。
- **富文本工具条**:加粗、斜体、文字颜色三个按钮。这里有个容易忽略的实现点——`<strong>` / `<em>` 本来就在 WordPress 评论的 kses 白名单里,但 `<span style="color:…">` **不在**,访客提交时会被 `wp_filter_kses` 整个剥掉,颜色功能就白做了。所以主题把 `span`(带 `style` / `class`)追加进了白名单。安全性由三层兜着:kses 对 `style` 内容还会再过一遍 `safecss_filter_attr()`(一份固定白名单,`expression()` / `url()` / `behavior` 一律剥掉);工具条前端只生成 `color` 一个声明;有 `unfiltered_html` 权限的管理员本来就不走 kses。
- **评论区也能贴代码**,和正文用同一套高亮。语言下拉里只列真正支持的,不会让你选了得到一个白板代码块。
- **回复的嵌套缩进保留,但每一层的引导线按层配色**(第 1 层浅蓝、第 2 层深蓝、第 3 层用点赞色,再往下从一个色板按层循环)。配色是**确定性**的:同一层永远同一个颜色、相邻层必定不同色,刷新页面不变——用真随机会让同一层的线各页各色,层级信号反而乱了。颜色都取饱和偏深的中明度,因为引导线在白底上,淡黄之类根本看不见。嵌套深度沿用 WordPress 的「评论层级」设置(`thread_comments_depth`,默认 5)。
- **评论关闭时整块彻底消失**,不会留一个空框加一句「评论已关闭」。
- 装了 wpDiscuz 之类第三方评论系统时,主题这块会**让位**,不会两边各画一个框。
## 多语言
语言包在 `languages/`:`kratos.pot` 是模板,另有 `en_US` 与 `zh_TW`。仓库带 `crowdin.yml`,想补别的语言可以直接改 `.po`,也可以通过翻译平台提交。
主题自己的文本域是 `kratos`。
## 已知冲突与注意事项
**1. 装了会改评论容器类名的插件,评论样式会失效。**
有些评论插件会把评论容器的 `class="comments"` 换成 `class="comments-area"`,主题的样式选择器就选不中了。主题**没有**内置这条兼容规则(那属于插件冲突,不改主题本身)。处理办法:在「主题设置 → 自定义代码 → 自定义 CSS」里补上:
```css
.k-main .details .comments-area {
margin-top: 16px;
padding: 1.6px 16px 16px;
border-radius: 2px;
background-color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
```
**2. 装多个代码高亮插件会打架。** 表现为复制按钮变两个、行号叠成重影。主题自带一整套,把插件卸掉。
**3. 后台「可用挂件」列表被主题收窄过。**
主题在 `widgets_init` 里用 `unregister_widget()` 注销了 9 个 WordPress 原生挂件:`WP_Widget_Pages`、`WP_Widget_Meta`、`WP_Widget_Recent_Posts`、`WP_Widget_Recent_Comments`、`WP_Widget_RSS`、`WP_Widget_Search`、`WP_Widget_Tag_Cloud`、`WP_Nav_Menu_Widget`、`WP_Widget_Categories`——前八个用主题自己的实现替代,`WP_Widget_Categories` 是被主题的 `widget_categories` 接管。
两个实现要点:
- **注销是按类名,不是按 `id_base`。** `WP_Widget_Factory::register()` 按类名存,所以只 `register` 自己的类不够——核心的 `WP_Widget_Categories` 还留在工厂里,后台列表会同时出现「分类」和「文章分类」两项,用户分不清该拖哪个。注销核心的之后列表里只剩一个。
- **注销不影响存量实例。** `_register_widgets()` 是按 `id_base` 读 option 的,主题的接管类沿用了同样的 `id_base`,所以旧实例照样被认领。
- 执行顺序也确认过:主题挂在 `widgets_init` 优先级 10,工厂自己的 `_register_widgets` 挂在优先级 100,所以「先注销 + 再注册」一定在真正注册实例之前完成。
如果你另有插件注册了同名 `id_base` 的挂件,以最后一次注册为准。
**4. 两个「文章聚合」会撞出重复 id。** 侧栏里同时挂两个同类挂件时,曾经产生过同一页面里重复的 DOM id(HTML 非法)。现在按实例区分。
**5. 小屏的标签页图标只有一份 DOM。** 早期实现是 PHP 渲染两份(带图标的 + 不带图标的)用 class 切换显隐,导致 `nav-tab` 等四个 id 在同一页面各出现两次。现在 DOM 只有一份,显隐交给媒体查询。
## 改代码前必读:源文件与压缩产物
**这两件事都会让人以为"改了没生效":**
1. **CSS**:`assets/css/kratos.css` 是源文件,前台加载的是 `assets/css/kratos.min.css`。历史上当过这样一次事故:把单行压缩版手工展开成可读格式时**漏掉了一整段**(`.k-main .details .article .content` 下的 `pre` / `code` / `kbd` / `pre code` / `pre ol` / `pre li` 六条规则),而未压缩的 `kratos.css` 里它们是齐全的,于是源与产物对不上——表现是行内 `code` 与 `kbd` 完全没有样式(代码块因为当时装着 Prism 才没露馅)。**别手工维护压缩产物**,改完用压缩器重新生成:
```bash
npx clean-css-cli@5.6.3 -o assets/css/kratos.min.css assets/css/kratos.css
```
2. **JS**:同理,前台执行的是 `assets/js/kratos.min.js`,`assets/js/kratos.js` 只是源文件。只改源文件等于没改。
## 仓库镜像
主仓库是 <https://code.yangyq.net/laoyang/wordpress-kratos-yang>(自建 Gitea,唯一权威来源)。下列平台是**手动同步的镜像,不保证最新**:
| 平台 | 地址 |
| --- | --- |
| GitHub | <https://github.com/dryangyq/wordpress-kratos-yang> |
| Gitee | <https://gitee.com/dryangyq/wordpress-kratos-yang> |
| GitLab | <https://gitlab.com/dryangyq/wordpress-kratos-yang> |
要拿最新版请直接克隆主仓库。GitHub 因网络原因同步经常失败;GitLab 上实测出现过落后一百多个小版本的情况。这不是承诺,是提醒。
## 这个主题不做什么
知道边界能省下试错的时间:
- **不做多套皮肤切换。** 只有一个形状,可调的只有背景色和顶部样式两类颜色项。
- **不做页面切换动画。** 跨文档 View Transition 要求站点每个页面都主动 opt-in,收益(一点点过渡顺滑)远低于代价——侧栏和内容区做整体动画极易出现元素跳动,并且首屏渲染会被拖慢。
- **不内置评论系统。** 自带的是对原生评论的样式与增强;换 Disqus / wpDiscuz 时主题会让位。
- **不做拖拽建站 / 页面构建器。** 正文就是一篇文章,排版靠主题的稳定规则。默认甚至**关掉了 Gutenberg**,要用区块编辑器得去「全站配置」里勾选。
- **不把用户数据写进主题目录。** 自定义代码进数据库、图片进媒体库或对象存储,主题目录保持「可以被整体替换」的状态——这一点很重要,因为 WordPress 升级主题的做法是删掉整个目录再解压新包,任何直接改在主题目录里的东西都会丢。
## 遇到问题
- 先翻「这个主题不做什么」,确认你想要的不是它有意不做的。
- 功能没生效:先确认后台对应分组的开关。有几个开关的方向容易记反——`g_gutenberg` 默认关(勾上才启用区块编辑器)、`toc_float` 默认关、`a_highlight_line_numbers` 默认关;而 `a_lightbox_enable` / `a_highlight_enable` / `stat_track_enable` / `toc_inline` 是默认**开**的。
- 改了 CSS 或 JS 没变化:先回看上面那节「源文件与压缩产物」。
- 页面报错、白屏:把 PHP 错误日志的相关行贴出来,比描述现象有用得多。
- Issue 提到主仓库:<https://code.yangyq.net/laoyang/wordpress-kratos-yang/issues>