* @license MIT License */ if (!defined('ABSPATH')) { exit; } /** * 内置纪念日清单 * * 返回 array( 键 => array(月份, 日, 名称, 说明, 分类, 是否默认勾选) ) * * 键名用 `m-d` 形式(补零),与 current_time('m') / current_time('d') 直接可比。 */ function yang_mourning_presets() { return array( // ── A 类:法定纪念日 ── '09-03' => array( 'name' => __('中国人民抗日战争胜利纪念日', 'kratos'), 'note' => __('1945 年 9 月 2 日日本签署投降书,9 月 3 日定为胜利纪念日', 'kratos'), 'group' => 'legal', 'default' => 0, ), '09-30' => array( 'name' => __('烈士纪念日', 'kratos'), 'note' => __('向人民英雄敬献花篮仪式在天安门广场举行', 'kratos'), 'group' => 'legal', 'default' => 0, ), '12-13' => array( 'name' => __('南京大屠杀死难者国家公祭日', 'kratos'), 'note' => __('1937 年 12 月 13 日南京沦陷,30 万同胞遇难', 'kratos'), 'group' => 'legal', 'default' => 0, ), // ── B 类:民间惯例,默认不勾 ── '05-12' => array( 'name' => __('汶川地震纪念日', 'kratos'), 'note' => __('2008 年 5 月 12 日 14 时 28 分,汶川发生 8.0 级地震', 'kratos'), 'group' => 'custom', 'default' => 0, ), '09-18' => array( 'name' => __('九一八事变纪念日', 'kratos'), 'note' => __('1931 年 9 月 18 日,日本关东军发动九一八事变', 'kratos'), 'group' => 'custom', 'default' => 0, ), '07-07' => array( 'name' => __('七七事变纪念日', 'kratos'), 'note' => __('1937 年 7 月 7 日,卢沟桥事变,全民族抗战爆发', 'kratos'), 'group' => 'custom', 'default' => 0, ), '12-12' => array( 'name' => __('西安事变纪念日', 'kratos'), 'note' => __('1936 年 12 月 12 日,张学良、杨虎城发动兵谏', 'kratos'), 'group' => 'custom', 'default' => 0, ), '08-15' => array( 'name' => __('日本宣布无条件投降纪念日', 'kratos'), 'note' => __('1945 年 8 月 15 日,日本天皇宣布接受波茨坦公告', 'kratos'), 'group' => 'custom', 'default' => 0, ), '04-04' => array( 'name' => __('清明节', 'kratos'), 'note' => __('节气日期每年浮动,这里固定为 4 月 4 日,仅作近似', 'kratos'), 'group' => 'custom', 'default' => 0, ), ); } /** * 读取用户勾选的纪念日 * * 老站点升级上来时这个选项还不存在,此时返回 presets 里 default=1 的那些。 * 注意**不能**简单用 `kratos_option('g_rip_days', 默认数组)`:kratos_option * 对未设置的键返回默认值,但如果用户曾经保存过空数组(全部取消勾选), * 存进去的就是空数组,此时必须尊重「用户就是要关掉」,不能再回退到默认。 * 所以这里用「option 数组里有没有这个键」来判断,而不是判断值是否为空。 */ function yang_mourning_days() { $presets = yang_mourning_presets(); $opts = get_option('kratos'); $has = is_array($opts) && array_key_exists('g_rip_days', $opts); if (!$has) { // 从未保存过:用内置默认 $out = array(); foreach ($presets as $md => $info) { if (!empty($info['default'])) { $out[] = $md; } } return $out; } $saved = $opts['g_rip_days']; if (!is_array($saved)) { return array(); } // 只保留在 presets 里存在、且值为真的日期(防止脏数据) $out = array(); foreach ($saved as $md => $v) { if ($v && isset($presets[$md])) { $out[] = $md; } } return $out; } /** * 今天是否应当哀悼 */ function yang_is_mourning_today() { // 旧的手动开关:开了就一直黑白(保持向后兼容,不能让升级把黑白站点变回彩色) if (kratos_option('g_rip', false)) { return true; } if (!kratos_option('g_rip_auto', false)) { return false; } // 走站点时区,不是服务器时区 $md = current_time('m') . '-' . current_time('d'); $days = yang_mourning_days(); // 自定义附加日期(用户自己填的,如特定年份的哀悼日) if (kratos_option('g_rip_extra', '')) { $extra = kratos_option('g_rip_extra', ''); foreach (preg_split('/[\s,,、;;]+/u', (string) $extra) as $one) { $one = trim($one); if ($one === '') { continue; } // 支持 MM-DD 与 YYYY-MM-DD 两种写法 if (preg_match('/^\d{2}-\d{2}$/', $one)) { $days[] = $one; } elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $one, $m)) { // 带年份的只在当年生效,不是周年循环 if ((int) $m[1] === (int) current_time('Y')) { $days[] = $m[2] . '-' . $m[3]; } } } } return in_array($md, $days, true); } /** * 输出黑白样式 * * 几个细节: * 1. `html { filter: grayscale(1) }` 会给整页建一个合成层,fixed 定位的元素 * 在某些旧版 Chrome 上会错位。所以额外加 `background-attachment: fixed` * 的补丁样式不写;这里改用给 body 和 .k-header 分别处理更稳。 * —— 实际上实测最稳的是给 html 加 filter 并用 transform: translateZ(0) * 在 body 上兜住,避免 iOS Safari 的渲染错位。这里保留 html 方案, * 因为它在用户当前主题结构下工作正常(老功能的写法),只是补一条 * iOS 的兼容声明。 * 2. 不能只挂 is_home():详情页也应该黑白。老代码限定首页,那是 bug。 * 3. 只在真正哀悼的日子输出,避免给所有页面增加一条无用样式。 */ function yang_mourning_style() { if (is_admin() || !yang_is_mourning_today()) { return; } echo '\n"; } add_action('wp_head', 'yang_mourning_style', 1); /** * 后台显示今天的哀悼状态,便于确认配置是否生效 */ function yang_mourning_status_text() { if (kratos_option('g_rip', false)) { return __('当前为手动常开模式:站点一直黑白,与日期无关。', 'kratos'); } if (!kratos_option('g_rip_auto', false)) { return __('自动哀悼未开启。', 'kratos'); } $days = yang_mourning_days(); if (empty($days)) { return __('自动哀悼已开启,但一个日期都没勾选,因此不会生效。', 'kratos'); } sort($days); $today = current_time('m') . '-' . current_time('d'); $is = in_array($today, $days, true); return sprintf( /* translators: 1: 今天的月日, 2: 是否处于哀悼, 3: 勾选的日期列表 */ __('今天是 %1$s,%2$s。已启用:%3$s', 'kratos'), $today, $is ? __('正在哀悼,站点已黑白', 'kratos') : __('不在哀悼日', 'kratos'), implode('、', $days) ); } /** * 哀悼期间在页面**最顶部正中**显示一条提示,链接到说明页 * * ── 为什么必须放在最顶部 ────────────────────────────────────── * 用户的原话是「别人都不知道咋回事,为啥变黑白」。只把入口藏在页脚, * 绝大多数人根本不会看到 —— 他们看到一片灰就关掉了。 * 所以提示条必须出现在**首屏第一眼就看到**的位置:整页最上方、水平居中。 * * ── 只在哀悼日出现 ──────────────────────────────────────────── * 平时打开站点的人不应该看到任何"哀悼说明"的入口 —— 他既没看到黑白, * 也不知道在对什么致哀,那个入口本身就是困惑源。所以页脚的常驻链接 * 已经移除,说明页的入口就只在这条提示里。 * * ── 为什么不做成弹窗 ────────────────────────────────────────── * 弹窗会挡住内容,纪念日当天每个访客每次访问都被弹一次,是骚扰。 * 一条可以关闭的细横条才是合适的强度,且关闭状态记在 sessionStorage * (用 session 而不是 localStorage:当天关闭后,第二天不应该还记着)。 * * ── 定位方式:占文档流第一行 + 同步下移导航栏 ───────────────── * 目标是「整页最上方、水平居中」。实现时连撞两次,都靠真实几何测出来: * * 第一版:`position:relative`,排进文档流。左右 padding 是 * `9px 46px 9px 18px`(左 18、右 46,为了给关闭按钮让位), * 内容整体偏左(实测文字中心 602、视口中心 640,偏 38px)—— * "最中间"根本没做到。同时它从 y=0 开始、高 40px,而导航栏 * `.k-nav` 是 `absolute; top:0`、z-index 1030,提示条 z-index 9990 * ⇒ **压在站点标题上方**(与 `.navbar-brand` 实测重叠 32px),把 Logo 遮住。 * * 第二版:改成 `position:fixed; top:0; left:0; right:0`,并给 body 加 * `padding-top`。居中问题解决了(中心精确等于视口中心),但**重叠仍在 31px**。 * 原因很隐蔽:`.k-nav` 是 `position:absolute`,它的包含块是初始包含块 * (视口),**body 的 padding 推不动它**。 * * 现在的做法(两件事配合): * 1. 提示条本身 `position:relative` 占文档流第一行、横跨整宽, * 内容交给内层 `.ymb-inner` 居中,左右 padding 等宽, * 关闭按钮 absolute 不占内部流 ⇒ 几何中心 = 视口中心。 * 它占位后,`.k-header` 会被自然推下去,正文不受影响。 * 2. 唯独 `.k-nav` 是 absolute,必须单独补一条 * `body.has-yang-mourning-bar .k-nav{top:var(--ymb-h)}` 把它挪到提示条下方。 * 没有提示条时该变量不存在、偏移为 0,行为与改动前完全一致。 * * 不用 fixed 的理由:fixed 会一直悬浮,滚动看文章时顶部永远压一条深色带, * 内容从它下面穿过去;而且它不占位,必须靠 padding 补偿,补偿量还算不准 * (窄屏换行后高度会变)。占文档流第一行没有这些问题。 */ 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'); ?>