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 的降级)。
三条全部改成判一致性/表格行。
This commit is contained in:
2026-10-28 20:54:09 +08:00
parent c058ecc827
commit ba1245191c
+465 -94
View File
@@ -1,128 +1,499 @@
该项目是原kratos的一个分支。
本项目仓库地址:
https://code.yangyq.net/laoyang/wordpress-kratos-yang
因为我需要一些定制的功能,就fork出来一个新的分支,自己用。如果你对原有的主题开发也有不满意的地方,欢迎使用我的这个版本。当然,版权仍然是属于原主题。
主题预览:<a href="https://yangyq.net" target="_blank">老杨说话的地方</a>。
# Kratos Yang
该仓库已同步到多个git托管平台,包括<a href="https://github.com/dryangyq/wordpress-kratos-yang.git" target="_blank">Github</a>、<a href="https://gitee.com/dryangyq/wordpress-kratos-yang.git" target="_blank">Gitee</a>、
<a href="https://gitlab.com/dryangyq/wordpress-kratos-yang.git" target="_blank">Gitlab</a>和<a href="https://code.aliyun.com/dryangyq/wordpress-kratos-yang.git" target="_blank">阿里云Code</a>。这些代码库都和<a href="https://code.yangyq.net/laoyang/wordpress-kratos-yang.git" target="_blank">源库</a>保持一致和同步,在任何平台上关注都可以。
一个给中文技术博客用的 WordPress 主题。上游是 [Kratos](https://github.com/seatonjiang/kratos),fork 出来之后按自己的写作习惯一路改到现在,改成了一个偏「写作与阅读」的形状:写的时候少折腾,读的时候少干扰,后台能看见的东西尽量不靠插件。
**Github因为网络原因,同步会出现失败情况,无法保证最新。**
- 主题预览:<https://yangyq.net>
- 源码主仓库:<https://code.yangyq.net/laoyang/wordpress-kratos-yang>
- 协议:MIT。上游 Kratos 的版权归属见 `LICENSE`。
主要修改的地方主要包括:
1. 为移动端增加了侧边栏显示。之前的版本,在移动端无法看到最近评论,这个版本加入了这个功能。当然只是在首页,在文章页面,为了减少数据传输,仍然没有侧边栏。
2. 文章聚合widget,将最新文章优先显示。原来的版本,是显示最热门文章,但是不知道什么原因,热点文章总是没几个,而且我认为,大部分人上来,应该时主要为了看最新文章的吧。
3. 删除了配置页面中的关于主题,精简、精简、精简。
4. 删除了资源托管选项,删除了媒体托管选项。
5. 文章配置中,删除了文章版权信息,删除了网易云音乐。
6. 删除了社交相关配置选项。
7. 增加了在页脚显示国旗的选项。
当前版本号看 `style.css` 头部的 `Version:` 字段——**那是版本号唯一的地方**,JS 和控制台输出的版本都由它派生。
# 修复Bug
1. 如果使用了插件,会改变comment的div名称,class="comments" 变成了comments-area,因此,评论的样式不好用了。
## 环境要求
此时,在主题的额外CSS中添加:
| | |
| --- | --- |
| 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;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.k-main .details .post-2 .comments-area {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
```
就可以了。该问题属于和插件的冲突问题,因此,在额外CSS中添加,不修改主题本身。
**2. 装多个代码高亮插件会打架。** 表现为复制按钮变两个、行号叠成重影。主题自带一整套,把插件卸掉。
# 代码块样式
**3. 后台「可用挂件」列表被主题收窄过。**
主题的 `assets/css/kratos.css` 里有一组 `.k-main .details .article .content` 下的
`pre` / `code` / `kbd` / `pre code` / `pre ol` / `pre li` 规则,负责代码块与行内代码的底色和间距。
主题在 `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` 接管。
**这六条曾经在压缩产物里整组丢失过**:某次改动把单行压缩版 `kratos.min.css` 手工展开成可读格式,
展开时漏掉了这一整段,而原始未压缩的 `kratos.css` 里它们是齐全的,导致源与产物对不上。
表现是行内 `code` 与 `kbd` 没有样式(代码块因为插件 Prism 主题的覆盖才没露馅)。
两个实现要点:
改完 CSS 后请用压缩器重新生成产物,不要手工维护 `kratos.min.css`:
- **注销是按类名,不是按 `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` 只是源文件。只改源文件等于没改。
更新走的是一份静态 JSON + 一个 zip 包,由 `inc/update-checker/`(Plugin Update Checker 4.9)消费。
## 仓库镜像
- 元数据地址:`https://yangyq.net/theme-update/update.json`
(定义在 `inc/theme-core.php`,可用 `wp-config.php` 里的 `YANG_THEME_UPDATE_URL` 覆盖)
- 发布目录:站点根下的 `theme-update/`,内容只有三样:
主仓库是 <https://code.yangyq.net/laoyang/wordpress-kratos-yang>(自建 Gitea,唯一权威来源)。下列平台是**手动同步的镜像,不保证最新**:
```
theme-update/update.json # 版本元数据
theme-update/kratos_yang.zip # 主题包,解压后是 kratos_yang/ 目录
theme-update/readme.html # 「详情」页,可省
```
| 平台 | 地址 |
| --- | --- |
| GitHub | <https://github.com/dryangyq/wordpress-kratos-yang> |
| Gitee | <https://gitee.com/dryangyq/wordpress-kratos-yang> |
| GitLab | <https://gitlab.com/dryangyq/wordpress-kratos-yang> |
`update.json` 格式(`version` 与 `details_url` 必填):
要拿最新版请直接克隆主仓库。GitHub 因网络原因同步经常失败;GitLab 上实测出现过落后一百多个小版本的情况。这不是承诺,是提醒。
```json
{
"version": "3.3.0",
"details_url": "https://yangyq.net/theme-update/readme.html",
"download_url": "https://yangyq.net/theme-update/kratos_yang.zip"
}
```
## 这个主题不做什么
## 发布新版本的顺序
知道边界能省下试错的时间:
**先改 `style.css` 里的 `Version`,再打包**,否则 WordPress 认为没有新版本,不会提示升级。
- **不做多套皮肤切换。** 只有一个形状,可调的只有背景色和顶部样式两类颜色项。
- **不做页面切换动画。** 跨文档 View Transition 要求站点每个页面都主动 opt-in,收益(一点点过渡顺滑)远低于代价——侧栏和内容区做整体动画极易出现元素跳动,并且首屏渲染会被拖慢。
- **不内置评论系统。** 自带的是对原生评论的样式与增强;换 Disqus / wpDiscuz 时主题会让位。
- **不做拖拽建站 / 页面构建器。** 正文就是一篇文章,排版靠主题的稳定规则。默认甚至**关掉了 Gutenberg**,要用区块编辑器得去「全站配置」里勾选。
- **不把用户数据写进主题目录。** 自定义代码进数据库、图片进媒体库或对象存储,主题目录保持「可以被整体替换」的状态——这一点很重要,因为 WordPress 升级主题的做法是删掉整个目录再解压新包,任何直接改在主题目录里的东西都会丢。
1. 改 `style.css` 的 `Version`(例如 3.2.2 → 3.3.0)
2. 打包:`zip -r kratos_yang.zip kratos_yang -x "*.DS_Store" "*/.git/*"`
3. 传 `kratos_yang.zip` 到 `theme-update/`
4. **最后**才改 `update.json` 里的 `version`
## 遇到问题
第 4 步放最后,是因为 WordPress 见到新版本号就会立刻允许升级;
若此时 zip 还是旧的,等于发了个指向旧包的更新,装完版本号没变(或者直接坏掉)。
## ⚠️ 自动升级会覆盖主题目录
WordPress 升级主题的做法是**删掉整个 `kratos_yang/` 再解压新包**
(`wp-admin/includes/class-theme-upgrader.php` 里 `clear_destination => true`,
随后 `delete_old_theme()` 递归删除)。所以任何直接改在服务器主题目录里的东西都会丢,
包括手工打的补丁(例如曾经直接在 `footer.php` 里加的 Prism 脚本)。
**自定义样式不再放主题目录。** 早期版本有一个 `custom/` 目录(`custom.css` /
`custom.js` / `custom.php`),是给用户随手加样式的入口,但它位于主题目录内,
每次升级都会被清空 —— 而且 `custom.php` 会被 `require`,等于允许在主题里执行任意
PHP 代码。该模块已在 3.2.2 移除,改为后台选项:
> 后台 → 主题选项 → **自定义代码** → 自定义 CSS / 自定义 JS
这两段内容存在数据库的 `kratos` 选项里,**升级、重装、改主题目录名都不受影响**。
它们分别在主题样式表和主题脚本之后加载,优先级最高。
几个要点:
- 不需要写 `<style>` / `<script>` 标签,直接写 CSS / JS 内容
- 内容不会被当作 HTML 处理,`>`、`<`、`~`、反斜杠转义(如 `content: "\f101"`)都原样保留
- 想彻底清空,把框里内容删掉保存即可(空值会覆盖内置默认值)
- 点“恢复默认”会把「自定义 CSS」还原成主题自带的默认样式
## 换域名 / 退役旧域名
以前更新元数据放在独立子域名上,现在收进主站,省掉一个站点、一套证书和一份备案。
切换时注意:
1. 先把 `theme-update/` 部署到主站并确认 `update.json` 能直接访问(返回 JSON,不是 404 或首页)
2. 再发布带新地址的主题版本
3. **旧版本的主题仍会去老地址拉更新**,所以旧域名的 `update.json` 要在确认所有站点都升级完之后才能下线
- 先翻「这个主题不做什么」,确认你想要的不是它有意不做的。
- 功能没生效:先确认后台对应分组的开关。有几个开关的方向容易记反——`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>