From db2e9c4230aac67d5a99565d9cd4dd24c238a829 Mon Sep 17 00:00:00 2001 From: laoyang Date: Mon, 26 Oct 2026 14:04:12 +0800 Subject: [PATCH] =?UTF-8?q?3.2.47:=20=E4=BF=AE=20[Archives]=20=E9=A6=96?= =?UTF-8?q?=E5=AD=97=E6=AF=8D=E5=A4=A7=E5=86=99=E4=B8=8D=E7=94=9F=E6=95=88?= =?UTF-8?q?=EF=BC=88WP=20=E7=9F=AD=E4=BB=A3=E7=A0=81=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=8C=BA=E5=88=86=E5=A4=A7=E5=B0=8F=E5=86=99=EF=BC=89#17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户线上实测:页面 /blogtime 写 [Archives] 原样输出

[Archives]

, 看起来像"短代码没装/被 markdown 插件转义",实际是标签名大小写对不上。 根因(内核证据,wp-includes/shortcodes.php): · get_shortcode_regex() 用 implode('|', array_map('preg_quote',$tagnames)) 拼正则,不做任何大小写归一化 · do_shortcode() 的 preg_match_all('/'.get_shortcode_regex().'/') 没有 i 修饰符 · do_shortcode_tag() 用 $m[2] 精确查 $shortcode_tags ⇒ add_shortcode('archives') 只匹配全小写,[Archives] 完全匹配不上。 线上实测(真实 WP 环境跑 do_shortcode): [archives] 长度=209239 解析=是 [Archives] 长度=10 解析=否(原样返回) [ARCHIVES] 长度=10 解析=否(原样返回) 3.2.46 里我写的注释"WP 短代码标签大小写不敏感、内部统一 strtolower" 是错的,这一版一并改正。 改动: · inc/theme-archives.php - 同时注册 archives / Archives / ARCHIVES 三种写法 (不为任意混合大小写膨胀正则,[aRcHiVeS] 刻意不支持,已加断言锁住) - 修短代码签名:$atts, $content, $tag —— 补上中间的 $content WP 通过 call_user_func($fn, $attr, $content, $tag) 传三个参数, 漏掉 $content 会让 $tag 落到第 2 个形参上,实际收到空串, shortcode_atts_{$tag} 退化成无主的 shortcode_atts_ - shortcode_atts 第 3 参数改为实际命中的 $tag(原来写死 'archives') · style.css 版本号 3.2.46 -> 3.2.47 测试也一并修(这才是本轮最值得记的): · _archives_unit.php 的 add_shortcode 桩原来写了 strtolower($tag), 比真实 WP 宽容 ⇒ 产品坏着、94 条断言全绿。 现在照抄内核不归一化,并新增真实的 do_shortcode 解析实现。 · ⑪ 组从"查注册表有没有 archives 这个键"改成"拿真实写法解析一遍" · 新增断言:三种写法都渲染出 .yang-archives、 混合大小写原样返回(刻意不支持)、未注册标签原样保留、 shortcode_atts 收到的 tag 恰好是实际命中的那个 · _archives_unit_falsify.py 新增 R5~R8 四条注入: R5 只注册小写(3.2.46 的错误形态)→ 红 10 条 R6 大写注册指向不存在的回调 → 红 4 条 R7 shortcode_atts 的 tag 写死小写 → 红 2 条 R8 签名去掉中间的 $content → 红 3 条 验证: 2j 评论关闭零输出 通过 54 / 0 失败 2k 评论关闭反向验证 真红 13 / 0 无效 2l 归档单测 通过 109 / 0 失败(原 94,新增 15 条) 2m 归档端到端 通过 109 / 0 失败 2n 归档端到端反向 真红 21 / 0 无效 2o 归档源码级反向 真红 10 / 0 无效(原 6,新增 4 条) lint 96 个 PHP 文件全过 线上验证(真实 WordPress,不是模拟): 补注册前:只 ["archives"],[Archives] 原样返回 补注册后:["archives","Archives","ARCHIVES"],三种写法长度全是 209239 发布:已推 3.2.47 到 /theme-update/,update.json 已落 3.2.47; 服务器 wp-content/themes/kratos_yang/ 仍为 3.2.46(未覆盖, 等用户在后台点升级)。 --- inc/theme-archives.php | 58 ++++++++++++++++++++++++++++++++++-------- style.css | 2 +- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/inc/theme-archives.php b/inc/theme-archives.php index bb787dc..af2f5a3 100644 --- a/inc/theme-archives.php +++ b/inc/theme-archives.php @@ -285,16 +285,22 @@ function yang_archives_data() /** * 短代码参数 * - * @param array $atts + * @param array $atts + * @param string $tag 实际命中的标签名(`archives` 或 `Archives`) * @return array */ -function yang_archives_atts($atts) +function yang_archives_atts($atts, $tag = 'archives') { + /* 🔴 第 3 个参数必须是**实际命中的那个 tag**,不能写死 'archives'。 + * 它决定 `shortcode_atts_{$tag}` 过滤器往外传的名字。 + * 我们同时注册了 `archives` 与 `Archives` 两种写法, + * 写死小写的话,用 `[Archives]` 的站点上 `shortcode_atts_Archives` + * 这个钩子永远收不到 —— 属于"功能能用但扩展点悄悄失效"的隐性 bug。 */ $a = shortcode_atts(array( 'year' => '', 'month' => '1', 'nav' => '1', - ), $atts, 'archives'); + ), $atts, $tag); return array( 'year' => $a['year'] === '' ? '' : (int) $a['year'], @@ -567,12 +573,24 @@ function yang_archives_render_nav_btn($target, $dir, $year) /** * 短代码主体 * - * @param array $atts + * 🔴 签名必须是 `($atts, $content, $tag)` 三个参数 —— 这是 WordPress + * `do_shortcode_tag()` 的调用约定: + * call_user_func( $shortcode_tags[$tag], $attr, $content, $tag ) + * 中间的 `$content` 是**闭合式短代码**(`[x]...[/x]`)的中间内容, + * 自闭合短代码传空串。本短代码用不到它,但**位置不能省**: + * 省掉之后 `$tag` 会落到第 2 个参数上,实际收到的 tag 变成空串, + * `shortcode_atts_{$tag}` 就只剩 `shortcode_atts_` 这个无主钩子。 + * (3.2.47 开发中实测踩到:直接调函数传 ('Archives') 是对的, + * 过 do_shortcode 才变成空 —— 差别就在中间这个 $content。) + * + * @param array $atts + * @param string $content 闭合式短代码的中间内容(本短代码不用) + * @param string $tag 实际命中的标签名(archives / Archives / ARCHIVES) * @return string */ -function yang_archives_shortcode($atts) +function yang_archives_shortcode($atts, $content = '', $tag = 'archives') { - $opt = yang_archives_atts($atts); + $opt = yang_archives_atts($atts, $tag); $data = yang_archives_data(); if (empty($data['order'])) { @@ -691,7 +709,27 @@ function yang_archives_shortcode($atts) return $out; } -/* WP 的 shortcode 标签是**大小写不敏感**的(它内部统一 strtolower), - * 所以注册小写 `archives` 就能同时匹配 [Archives] / [ARCHIVES] / [archives]。 - * 这里按 WP 惯例注册小写。 */ -add_shortcode('archives', 'yang_archives_shortcode'); \ No newline at end of file +/* 🔴🔴 WP 的 shortcode 标签**区分大小写** —— 这一点 3.2.46 写错过,实测过。 + * + * 内核证据(wp-includes/shortcodes.php): + * ① `get_shortcode_regex()` 直接 `implode('|', array_map('preg_quote', $tagnames))`, + * 拿注册名拼正则,**没有做任何大小写归一化**; + * ② `do_shortcode()` 里 `preg_match_all('/' . get_shortcode_regex() . '/', ...)` + * —— 修饰符只有默认,**没有 `i`**; + * ③ `do_shortcode_tag()` 拿到 `$tag = $m[2]` 后直接 `$shortcode_tags[$tag]` 精确查表。 + * + * ⇒ `add_shortcode('archives', ...)` **只匹配全小写 `[archives]`**。 + * 用户按文档写 `[Archives]`,正则压根不认,WordPress 就把原文原样吐出来 + * —— 页面显示 `

[Archives]

`,看起来极像"短代码没装/被转义", + * 实际是**标签名大小写对不上**。 + * + * ⇒ 只能把要支持的写法**逐个注册**。这里注册三种常见形态: + * 全小写(WP 惯例)、首字母大写(文档与用户习惯)、全大写。 + * 注册同一个回调是安全的:`$shortcode_tags` 里就是几条 key 指向同一个函数, + * 任何时刻只会命中其中一条(正则里几个分支互斥),不会渲染两次。 + * + * ⚠️ 不追求覆盖任意混合大小写(`[aRcHiVeS]`):那需要每隔位置都注册一条, + * 正则会膨胀到不可维护。三种形态已经覆盖真实使用中的全部习惯写法。 */ +add_shortcode('archives', 'yang_archives_shortcode'); +add_shortcode('Archives', 'yang_archives_shortcode'); +add_shortcode('ARCHIVES', 'yang_archives_shortcode'); \ No newline at end of file diff --git a/style.css b/style.css index 613e992..7d5c78a 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.46 +Version: 3.2.47 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好