Files
wordpress-kratos-yang/README.md
T

500 lines
32 KiB
Markdown
Raw Normal View History

# Kratos Yang
2022-05-14 18:36:38 +08:00
一个给中文技术博客用的 WordPress 主题。上游是 [Kratos](https://github.com/seatonjiang/kratos),fork 出来之后按自己的写作习惯一路改到现在,改成了一个偏「写作与阅读」的形状:写的时候少折腾,读的时候少干扰,后台能看见的东西尽量不靠插件。
2022-05-14 17:53:21 +08:00
- 主题预览:<https://yangyq.net>
- 源码主仓库:<https://code.yangyq.net/laoyang/wordpress-kratos-yang>
- 协议:MIT。上游 Kratos 的版权归属见 `LICENSE`。
2022-05-14 18:38:57 +08:00
当前版本号看 `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>