From 269364bed4cc306204c1aa807b41144cf2576c52 Mon Sep 17 00:00:00 2001 From: laoyang Date: Fri, 23 Oct 2026 14:43:47 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=203.2.6=20->=203.2.?= =?UTF-8?q?7=EF=BC=88=E7=BA=AA=E5=BF=B5=E6=97=A5=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=8D=E5=8B=BE=20+=20=E5=BD=A9=E8=89=B2?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=E9=A1=B5=20+=20=E9=82=AE=E4=BB=B6=E5=BD=A9?= =?UTF-8?q?=E8=89=B2=20+=20=E5=8F=8C=E5=BC=95=E7=94=A8=E5=9D=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 哀悼默认值全部改为不勾选 - 九个纪念日的 default 全改成 0。之前法定那三个是 1,导致全新安装的站点 一到日子就自己变黑白,而站主根本没同意过这件事。 - 后台多选组件的 std 全为 0,打开设置页一个都不勾。 - 「从未保存过」与「保存过但全不勾」两条路径都返回空数组, 不能因为结果为空就回退到默认 —— 那等于用户取消勾选无效。 新增彩色说明页(inc/theme-mourning-page.php + pages/page-mourning.php) - 站点变黑白后必须有个地方解释清楚,否则访客只看到一片灰、以为站点坏了。 - 三处入口:顶部提示条(wp_body_open,首屏可见)、页脚常驻链接、 [yang_mourning] 短代码。 - 页面内容由真实配置驱动,不是写死的文案:没勾的日期不会出现, 今天在列表里带「今天」标记,一个都没勾时明说「不会生效」。 - 页面必须保持彩色,否则解释「为什么是灰的」的页面自己也是灰的。 取消灰度做了两层:filter:none 与 grayscale(0%) 都写,且带 !important; 优先级放在 wp_head 的 2,晚于灰度样式的 1。 - 路由走 parse_request 优先级 5 而非 template_redirect: 避免先走一遍 404 判定与 404 模板。带子目录安装时先剥掉前缀再比对。 - 不抢占用户自己建的页面:如果站里已有同名 slug 的页面就放手。 否则用户会觉得「我建的页面坏了」,且没有任何提示。 邮件不受影响,且回复邮件同时给出双方内容 - 邮件是独立 HTML,不走 wp_head,结构上就不可能被灰度,已断言验证。 - theme-mail-template 的单个 quote 改成 quotes 列表,一个模板同时渲染 「被回复的那条」与「新的回复」,最后一块用主色高亮(回复是重点), 前面的用弱化色。只有一块时退化为主色,与旧行为一致。 - 通过 wpdiscuz_email_content 重建整封邮件,不需要改插件。 审核通过通知用 wpdiscuz_comment_approved_email_content 走同一模板, 但它只给 post_id、不给评论对象,能放的内容受此限制。 两个必须记下来的坑 - wpDiscuz 在过滤器之后还会做一次 html_entity_decode 再发信。 esc_html 的输出会被那一步还原成真标签,评论里的 ` 会变回可执行标签, + * 未闭合的 `
` 会吃掉整封邮件的布局。 + * + * 这**在本地用桩环境测不出来** —— 桩环境没有插件那一步解码, + * 断言只会看到"已转义"而全绿。只有读插件源码才发现。 + * + * 解法:把 `&` 全部预编码成 `&`。这样插件解码一次之后, + * 恰好还原成我们想要的转义状态(decode("&lt;") === "<")。 + * 只处理 `&` 就够,因为其它实体的风险都源于 `&` 被还原。 + */ +function yang_mail_escape_for_wpdiscuz($html) +{ + return str_replace('&', '&', $html); +} + +/** + * 把 wpDiscuz 的通知邮件接管成主题模板 + * + * ── 为什么要接管 ────────────────────────────────────────────── + * wpDiscuz 自己的模板只印「新评论内容」,收件人看到一句陌生人说的话, + * 完全想不起自己在哪篇文章下说过什么。要理解上下文,必须**同时给出 + * 被回复的那条评论**。 + * + * 它的过滤器 `wpdiscuz_email_content` 能拿到 `$comment`(新评论对象) + * 和 `$emailData`(订阅记录),足以重建整封邮件,所以不需要改插件。 + * + * ── 两个模板还是一个模板 ────────────────────────────────────── + * 用一个。评论通知和「审核通过」通知的差别只有标题、徽标、引言和 + * 上面那两段引用,正文骨架完全一样。做成两套模板会立刻分叉, + * 以后改一次配色要改两处。 + * + * @param string $message 插件生成的 HTML(丢弃) + * @param WP_Comment $comment 新评论 + * @param array $email_data 订阅记录 + * @return string + */ +function yang_mail_render_comment_notify($message, $comment, $email_data = array()) +{ + if (!yang_mail_smtp_ready() || !($comment instanceof WP_Comment)) { + return $message; + } + + $site = get_bloginfo('name'); + $post_id = (int) $comment->comment_post_ID; + $post = get_post($post_id); + $title = $post ? get_the_title($post) : __('(文章已删除)', 'kratos'); + $link = get_comment_link($comment->comment_ID); + $author = $comment->comment_author ? $comment->comment_author : __('匿名访客', 'kratos'); + + // 新评论这一段(一定是最后一块,模板会把它高亮成主色) + $quotes = array(); + + // 被回复的原评论:有父评论才取,取不到就不放,宁缺毋滥 + $parent_id = (int) $comment->comment_parent; + if ($parent_id > 0) { + $parent = get_comment($parent_id); + if ($parent) { + $p_author = $parent->comment_author ? $parent->comment_author : __('匿名访客', 'kratos'); + $quotes[] = array( + 'label' => sprintf(__('你之前说的(%s)', 'kratos'), $p_author), + 'content' => yang_mail_text($parent->comment_content, 1200), + 'meta' => mysql2date('Y-m-d H:i', $parent->comment_date), + ); + } + } + + $quotes[] = array( + 'label' => sprintf(__('%s 回复说', 'kratos'), $author), + 'content' => yang_mail_text($comment->comment_content, 1200), + 'meta' => mysql2date('Y-m-d H:i', $comment->comment_date), + ); + + // 引言随场景变化:有父评论是「有人回复你」,没有是「有新评论」 + $intro = $parent_id > 0 + ? sprintf(__('你在《%s》下的评论收到了一条回复。', 'kratos'), $title) + : sprintf(__('《%s》下有新的评论。', 'kratos'), $title); + + $rows = array( + array('label' => __('文章', 'kratos'), 'value' => $title), + array('label' => __('评论者', 'kratos'), 'value' => $author, 'strong' => true), + array('label' => __('时间', 'kratos'), 'value' => mysql2date('Y-m-d H:i', $comment->comment_date)), + ); + + $body = yang_mail_render(array( + 'title' => sprintf(__('%s · 新回复', 'kratos'), $site), + 'preheader' => sprintf(__('%s 在《%s》下回复了评论。', 'kratos'), $author, $title), + 'badge' => $parent_id > 0 ? __('新回复', 'kratos') : __('新评论', 'kratos'), + 'heading' => $parent_id > 0 ? __('有人回复了你的评论', 'kratos') : __('文章有新评论', 'kratos'), + 'intro' => $intro, + 'quotes' => $quotes, + 'rows' => $rows, + 'cta_text' => __('查看完整讨论', 'kratos'), + 'cta_url' => $link, + 'note' => __('你收到这封邮件,是因为你订阅了这篇文章的评论,或你的评论被回复了。', 'kratos'), + )); + + return yang_mail_escape_for_wpdiscuz($body); +} +add_filter('wpdiscuz_email_content', 'yang_mail_render_comment_notify', 20, 3); + +/** + * 审核通过通知也套同一套模板 + * + * 这个过滤器的参数是 ($message, $post_id, $email),拿不到评论对象, + * 所以只能给「你的评论已通过审核」这种通用内容 —— 这是插件接口的限制, + * 不是这里偷懒。 + */ +function yang_mail_render_approved_notify($message, $post_id, $email) +{ + if (!yang_mail_smtp_ready()) { + return $message; + } + + $title = get_the_title($post_id); + + return yang_mail_escape_for_wpdiscuz(yang_mail_render(array( + 'title' => sprintf(__('%s · 评论已通过审核', 'kratos'), get_bloginfo('name')), + 'preheader' => sprintf(__('你在《%s》下的评论已通过审核并公开显示。', 'kratos'), $title), + 'badge' => __('已通过', 'kratos'), + 'heading' => __('你的评论已通过审核', 'kratos'), + 'intro' => sprintf(__('你在《%s》下提交的评论已经审核通过,现在其他读者可以看到它了。', 'kratos'), $title), + 'rows' => array( + array('label' => __('文章', 'kratos'), 'value' => $title), + ), + 'cta_text' => __('去看看', 'kratos'), + 'cta_url' => get_permalink($post_id), + 'note' => __('这是评论审核结果通知,无需回复。', 'kratos'), + ))); +} +add_filter('wpdiscuz_comment_approved_email_content', 'yang_mail_render_approved_notify', 20, 3); diff --git a/inc/theme-mourning-page.php b/inc/theme-mourning-page.php new file mode 100644 index 0000000..9c94b7e --- /dev/null +++ b/inc/theme-mourning-page.php @@ -0,0 +1,414 @@ + + * @license MIT License + */ + +if (!defined('ABSPATH')) { + exit; +} + +/** + * 说明页用的配色 + * + * 哀悼页是**彩色**的,但主色调仍然克制(不用大红大绿), + * 因为它讲的是一件严肃的事。用「暖金 + 深墨」的组合: + * 金色呼应纪念的国家仪式感,深墨保证长文可读。 + */ +function yang_mourning_page_palette() +{ + return array( + 'gold' => '#b8860b', // 暗金,装饰色(SVG 描边、分隔线、纯装饰的描边) + /* 金的"可读版本"。 + * #b8860b 在白底上只有 3.06:1,低于 WCAG AA 对正文的 4.5:1 —— + * 装饰线条用它没问题,但当**文字颜色**就偏虚,尤其 12–15px 小字。 + * #946600 是同色相里仍属金色、且刚好过线(4.75:1)的最亮一档, + * 再亮一档 #9c7000 只有 4.18:1 不达标,再暗就往棕色走了。 + * 所以装饰归装饰、文字归文字,两个变量分开,不要混用。 */ + 'gold_text' => '#946600', + 'gold_soft' => '#fdf6e3', // 金的浅底 + 'ink' => '#1f2933', // 正文墨色 + 'ink_soft' => '#52606d', // 次要文字 + 'paper' => '#ffffff', + 'canvas' => '#f7f8fa', + 'line' => '#e4e7eb', + 'red' => '#a4243b', // 公祭日用的暗红 + ); +} + +/** + * 渲染哀悼说明的正文(短代码与模板共用) + * + * @return string HTML + */ +function yang_mourning_page_content() +{ + $p = yang_mourning_page_palette(); + $days = yang_mourning_days(); + $presets = yang_mourning_presets(); + + // 今天是否在哀悼 + $is_today = yang_is_mourning_today(); + $today = current_time('m') . '-' . current_time('d'); + + ob_start(); + ?> + +
+ + +
+
+ +

+

+ + 本站今日以黑白呈现,以寄哀思。这不是故障,是刻意的。 + + 在特定的日子里,本站会转为黑白显示,以示纪念。 + +

+
+ + + 当前状态:正在哀悼(全站黑白) + + 当前状态:正常显示 · 今天是 + +
+
+
+ + +
+

为什么会变成黑白

+
+

在一些具有特殊意义的日子里,本站会把整站色调转为黑白,暂停一切彩色装饰。这是一种无声的致意 —— 和降半旗、鸣笛、默哀是同一类表达。

+

它不改变内容,也不影响你阅读任何文章。只是把颜色暂时收起来。

+
+
+ + +
+

哪几天会自动变黑白

+ + + + +
法定纪念日
+
+ $info): ?> +
+
+
+
+
+
+
今天
+
+ +
+ + + +
本站另外启用的纪念日
+
+ $info): ?> +
+
+
+
+
+
+
今天
+
+ +
+ + + +
站主另行标注的日期
+
+ ' . esc_html($one) . ''; + } + ?> +
+ + + +
+

本站目前没有启用任何纪念日。

+

如果哪天你看到这里变成黑白,那说明站主刚刚启用了它。

+
+ +
+ + +
+

几个可能想问的问题

+
+
+ 是我浏览器坏了吗? +
不是。可以在别的设备上打开对比一下,同样是黑白。整站色调由一段样式统一控制,会在纪念日当天自动生效,次日自动恢复。
+
+
+ 会影响阅读吗? +
内容、链接、图片都不变,只是颜色被去掉。文字对比度反而更高一些。唯一的变化是图片失去色彩。
+
+
+ 什么时候恢复彩色? +
当天 24 点过后自动恢复。本站按站点时区判断日期,不是按你所在时区,所以不同地区看到的切换时刻可能略有差别。
+
+
+ 打印出来也是灰的吗? +
不是。打印时已专门取消灰度,纸上呈现正常颜色。
+
+
+ 这个页面为什么是彩色的? +
说明性质的内容需要读得清楚。把说明页也做成灰的,反而增加了理解成本 —— 这与「让人明白发生了什么」的目的是相反的。
+
+
+
+ + +
+
+

铭记,是为了更好地前行。

+ +
+ +
+ query_vars = array(); + status_header(200); + $GLOBALS['wp_query'] = new WP_Query(array('page_id' => 0)); + $GLOBALS['wp_query']->is_404 = false; + + include get_template_directory() . '/pages/page-mourning.php'; + exit; +} +add_action('parse_request', 'yang_mourning_page_route', 5); + +/** + * 注册短代码,便于在任意文章里嵌入说明 + */ +function yang_mourning_shortcode($atts = array()) +{ + return yang_mourning_page_content(); +} +add_shortcode('yang_mourning', 'yang_mourning_shortcode'); \ No newline at end of file diff --git a/inc/theme-mourning.php b/inc/theme-mourning.php index 5d4c582..ab87b0c 100644 --- a/inc/theme-mourning.php +++ b/inc/theme-mourning.php @@ -65,19 +65,19 @@ function yang_mourning_presets() 'name' => __('中国人民抗日战争胜利纪念日', 'kratos'), 'note' => __('1945 年 9 月 2 日日本签署投降书,9 月 3 日定为胜利纪念日', 'kratos'), 'group' => 'legal', - 'default' => 1, + 'default' => 0, ), '09-30' => array( 'name' => __('烈士纪念日', 'kratos'), 'note' => __('向人民英雄敬献花篮仪式在天安门广场举行', 'kratos'), 'group' => 'legal', - 'default' => 1, + 'default' => 0, ), '12-13' => array( 'name' => __('南京大屠杀死难者国家公祭日', 'kratos'), 'note' => __('1937 年 12 月 13 日南京沦陷,30 万同胞遇难', 'kratos'), 'group' => 'legal', - 'default' => 1, + 'default' => 0, ), // ── B 类:民间惯例,默认不勾 ── @@ -256,4 +256,123 @@ function yang_mourning_status_text() $is ? __('正在哀悼,站点已黑白', 'kratos') : __('不在哀悼日', 'kratos'), implode('、', $days) ); -} \ No newline at end of file +} +/** + * 哀悼期间在页面顶部显示一条提示,链接到说明页 + * + * ── 为什么必须放在顶部 ──────────────────────────────────────── + * 用户的原话是「别人都不知道咋回事,为啥变黑白」。只把入口藏在页脚, + * 绝大多数人根本不会看到 —— 他们看到一片灰就关掉了。 + * 所以提示条要出现在**首屏就能看到**的位置。 + * + * ── 为什么不做成弹窗 ────────────────────────────────────────── + * 弹窗会挡住内容,纪念日当天每个访客每次访问都被弹一次,是骚扰。 + * 一条可以关闭的细横条才是合适的强度,且关闭状态记在 sessionStorage + * (用 session 而不是 localStorage:当天关闭后,第二天不应该还记着)。 + */ +function yang_mourning_notice_bar() +{ + // 只在真正哀悼时显示,且不在说明页自身显示(那页自己会说明) + if (is_admin() || !yang_is_mourning_today()) { + return; + } + if (yang_mourning_page_is_current()) { + return; + } + + $url = yang_mourning_page_url(); + $name = yang_mourning_today_name(); + $text = $name !== '' + ? sprintf(__('今天是%s,本站以黑白致哀。', 'kratos'), $name) + : __('今天是纪念日,本站以黑白致哀。', 'kratos'); + ?> +
+ + + + +
+ + + + + + __('纪念日清单', 'kratos'), - 'desc' => __('勾选需要自动黑白的日期。前三个是法定纪念日(默认已勾),后面几个是民间通行做法,按自己意愿决定。日期按站点时区判断,只比对月和日,每年循环。', 'kratos'), + 'desc' => __('勾选需要自动黑白的日期。默认一个都不勾,请按自己的意愿挑选。前三个是法定纪念日,后面几个是民间通行做法。日期按站点时区判断,只比对月和日,每年循环。', 'kratos'), 'id' => 'g_rip_days', 'std' => $rip_default, 'type' => 'multicheck', @@ -282,6 +282,20 @@ $options[] = array( 'type' => 'text', ); + $options[] = array( + 'name' => __('说明页路径', 'kratos'), + 'desc' => sprintf( + /* 注意:desc 会过 wp_kses($allowedtags),那是 WordPress 的默认白名单, + 只放行 a/abbr/b/br/em/i/strong 等,**不放行 ** —— + 写 会被静默剥掉,页面上只剩裸文字。所以这里用 强调。 */ + __('变黑白时,页面顶部会出现一条提示,点进去是一个说明页面(彩色),讲清楚为什么变黑白、哪几天会变。
这里可以改那个页面的路径。留空默认 memory,即 %s
注意:不要和已有文章或页面的路径重名。', 'kratos'), + esc_url(home_url('/memory/')) + ), + 'id' => 'g_rip_page_slug', + 'std' => 'memory', + 'type' => 'text', + ); + $options[] = array( 'desc' => yang_mourning_status_text(), 'type' => 'info', diff --git a/pages/page-mourning.php b/pages/page-mourning.php new file mode 100644 index 0000000..c069f0a --- /dev/null +++ b/pages/page-mourning.php @@ -0,0 +1,62 @@ + + * @license MIT License + */ + +if (!defined('ABSPATH')) { + exit; +} + +/** + * 把灰度反转掉 + * + * 为什么写两遍: + * - `html{filter:none}` 取消外面的灰度; + * - 但某些浏览器在 filter 从有到无的瞬间会留下合成层缓存,导致首屏仍是灰的, + * 所以补一条 `filter:grayscale(0%)` 显式声明,比 none 更稳。 + * + * 权限用 `!important`:主题的灰度样式在 wp_head 优先级 1 输出, + * 本段在优先级 2,同优先级下后写的赢,加 !important 是防其它插件插入的覆盖。 + */ +function yang_mourning_page_ungrayscale() +{ + echo '\n"; +} +add_action('wp_head', 'yang_mourning_page_ungrayscale', 2); + +/** + * 输出本页样式 + */ +function yang_mourning_page_print_css() +{ + echo '\n"; +} +add_action('wp_head', 'yang_mourning_page_print_css', 3); + +get_header(); +?> +
+
+
+
+ +
+
+
+
+ \ No newline at end of file diff --git a/style.css b/style.css index b455879..d2f0845 100644 --- a/style.css +++ b/style.css @@ -1,7 +1,7 @@ /* Theme Name: Kratos_Yang Text Domain: kratos_Yang -Version: 3.2.6 +Version: 3.2.7 Requires PHP: 7.0 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好