代码高亮整套自研:10 浅 + 10 深配色、语言标签、评论区贴代码 (#11)
不再依赖第三方高亮插件,全部由主题自己实现。
主题配色(20 套)
- 浅色 10:github / vs / atom-one-light / idea / xcode /
stackoverflow-light / intellij-light / googlecode / magula / color-brewer
- 深色 10:github-dark / atom-one-dark / monokai / github-dark-dimmed /
a11y-dark / stackoverflow-dark / night-owl / srcery /
panda-syntax-dark / tomorrow-night-blue
- 深色卡片带 data-kind="dark",顶栏跟着换深色底
- 只加载当前选中的一套(20 套全加载会让后出现的规则压前面的,
切换配色容易"看起来没变")
代码语言标签(用户要求:防止复制错语言)
- 作者标了 language-xxx → 实线边框、正体
- 自动识别猜出来的 → 虚线边框、斜体
- 认不出来 → 显示 "—",仍保持虚线斜体(不冒充作者标注)
行号
- 默认关;行号槽在 <pre> 外面,复制天然不带行号
- 改掉原主题的 word-break:break-all(任意字符断行,代码像乱码)
- 归零 hljs 主题自带的 pre code.hljs{padding:1em},
否则代码被压低 1em、与行号槽错位 15.5px
复制
- 默认开;安全上下文判断 + execCommand 退路(HTTP 下 clipboard 是 undefined)
- 取 textContent 而非 innerHTML
- 默认 opacity:0、hover 显示、触屏覆盖回 1
(旧写法只在 @media(hover:none) 里写 1,等于空操作)
自动识别
- 做成选项,默认开
- 只对没标语言的块生效;站内实测长块准确率 22%,不能覆盖作者标注
评论区贴代码
- 评论工具条加"代码"按钮 + 29 种语言面板
- kses 放行 pre 并给 pre/code 放开 class
(WP 默认 pre 整条剥掉、code 属性全清,此前根本贴不了代码)
- 放行 pre 之后 wpautop/wptexturize/make_clickable 自动让路,
代码里的连续空行、引号、URL 都不会被改写
- comments.js 用占位符保护代码块,避免 walk() 的 /\n{3,}/ 压缩
其它
- 资源版本号改为读主题头,不再写死(写死会导致以后升级后
浏览器一直用旧缓存,改了 CSS/JS 完全不生效)
- 删除 footer.php 里旧的 Prism 兜底(两套高亮器同页会互相打架)
验收
- 用线上 284 个真实代码块跑产品代码:284/284 全部变卡片,内容丢字 0、双转义 0
- 47 个 text 标记全部映射到 plaintext(hljs 无 text 语言,不映射会静默不上色)
- 80 个裸 <pre>(无 code 子元素)全部覆盖
- 核心纯函数 65/65;核心反向 10/10 变红
- 浏览器端到端 32/32;行号几何逐行对齐偏差 0.00px,几何反向 4/4 变红
- 端到端反向 7/7 变红;语言标签反向 2/2 变红
- 全量 PHP 语法 95 文件 0 错误
发布:走 theme-update 通道(zip + readme + update.json),
未覆盖服务器主题目录;线上主题目录仍是 3.2.41,待后台升级。
This commit is contained in:
@@ -75,6 +75,36 @@ function yang_kses_allow_span($tags, $context)
|
||||
'style' => true,
|
||||
'class' => true,
|
||||
);
|
||||
|
||||
/* ── 3.2.42 评论贴代码 ────────────────────────────────────
|
||||
* 用真实 WP 7.1.3 实测的结论:不加这一段,访客在评论里**根本贴不了代码**。
|
||||
* · `pre` 不在 $allowedtags 里 → 整条内容连带代码一起被剥掉
|
||||
* · `code` 虽然在,但没有任何属性 → class="language-xxx" 被剥,
|
||||
* 语言标记保不住,代码块只能当纯文本
|
||||
* 所以必须同时做两件事:放行 pre;给 pre/code 放开 class。
|
||||
*
|
||||
* 🔴 放行 pre 之后有三件事会**自动变好**,不用另写代码,
|
||||
* 但必须知道原因,否则以后有人"顺手优化"掉 pre 就会全崩:
|
||||
* ① wpautop 不再套 <p> —— 缩进得救。
|
||||
* 没有 pre 时 <p> 的 white-space:normal 会把 4 个空格折叠成 1 个;
|
||||
* 有 pre 时 wpautop 会跳过那一整段。实测确认。
|
||||
* ② wptexturize 被挡住 —— 引号不再变弯。
|
||||
* 否则 ' → ’、-- → —、" → “”,代码直接跑不了。
|
||||
* ③ make_clickable 被挡住 —— 代码里的 URL 不会变成 <a href rel="nofollow">,
|
||||
* 否则复制出来全是 HTML。
|
||||
* ②③ 是最容易忽略的两条:它们**只在没有 pre 包裹时才破坏**。
|
||||
* 以上全部已在真实 WP 核心上逐条验证(11 条判据全通过)。
|
||||
*
|
||||
* 安全性:pre/code 都不接受任何 URL 类属性,class 只用于语言标记,
|
||||
* 本体不产生任何可执行内容。kses 仍会继续过滤 pre/code 内部的一切标签。
|
||||
*/
|
||||
$tags['pre'] = array(
|
||||
'class' => true,
|
||||
);
|
||||
$tags['code'] = array(
|
||||
'class' => true,
|
||||
);
|
||||
|
||||
return $tags;
|
||||
}
|
||||
add_filter('wp_kses_allowed_html', 'yang_kses_allow_span', 10, 2);
|
||||
@@ -165,6 +195,36 @@ function yang_comment_html($comment, $args = array(), $depth = 1, $is_ajax = fal
|
||||
comment_text($comment_id);
|
||||
$content = ob_get_clean();
|
||||
|
||||
/* 3.2.42 评论里的代码块也走和正文同一套渲染。
|
||||
🔴 走同一个函数 yang_hl_render_block(),不另写一份。
|
||||
理由:正文和评论的代码块如果各写一套,两边样式一定分叉,
|
||||
而这类分叉在页面上不容易一眼看出来(评论区的块通常更短)。
|
||||
渲染器负责的是"裸 pre → 卡片"的规范化,评论和正文的输入形态是一样的。
|
||||
🔴 为什么在 ob 取到之后再处理,而不是挂 comment_text 过滤器:
|
||||
挂过滤器会让 AJAX 返回和列表渲染各自经过一次,容易漏一侧;
|
||||
而 yang_comment_html() 是**列表与 AJAX 共用**的唯一出口
|
||||
(本文件开头就是为这个才重写的),在这里处理不会分叉。 */
|
||||
if (function_exists('yang_hl_render_block')
|
||||
&& function_exists('yang_hl_enabled') && yang_hl_enabled()
|
||||
&& strpos($content, '<pre') !== false) {
|
||||
$rendered = preg_replace_callback(
|
||||
'#<pre\b([^>]*)>(.*?)</pre>#is',
|
||||
function ($m) {
|
||||
$cls = '';
|
||||
if (preg_match('/class\s*=\s*"([^"]*)"/i', $m[1], $cm)
|
||||
|| preg_match("/class\s*=\s*'([^']*)'/i", $m[1], $cm)) {
|
||||
$cls = $cm[1];
|
||||
}
|
||||
return yang_hl_render_block($m[2], $cls);
|
||||
},
|
||||
$content
|
||||
);
|
||||
// preg_replace_callback 失败返回 null,绝不能把 null 当内容输出
|
||||
if ($rendered !== null) {
|
||||
$content = $rendered;
|
||||
}
|
||||
}
|
||||
|
||||
$avatar = '';
|
||||
if (get_option('show_avatars') && function_exists('get_avatar')) {
|
||||
$avatar = get_avatar($comment, 48, '', $author_name, array(
|
||||
|
||||
Reference in New Issue
Block a user