3.2.18: 清明按节气换算、主题内 [TOC] 目录、重建评论区替代 wpDiscuz

三项功能:

1. 清明不再用固定 04-04
   清明是节气,日期在 4/4~4/6 之间浮动。硬编码 04-04 实测 1900-2100
   共 201 年里只有 76 年是对的(约 38%)。改为内嵌逐年表换算真实日期,
   超出 1900-2100 返回 null 明确放弃,不退化成近似值。
   兼容 3.2.17 及以前勾过的 '04-04' 键,升级后勾选不会被静默丢弃。

2. 主题内实现 [TOC]
   文章里写 [TOC],该位置输出本文目录,点击跳到对应标题。
   在 the_content 优先级 9 处理(早于 wpautop 10 / do_shortcode 11),
   保证"补 id"与"扫目录"用的是同一份文本,href 与 id 必然对得上。
   嵌套用深度归一化,h1→h3 跳级不会算错层级。
   scroll-margin-top 声明式让位,原生锚点/外部 #hash/后退全都生效。

3. 重建评论区
   旧实现的问题:列表渲染与 AJAX 渲染各写一份 HTML,已经分叉
   (AJAX 返回的新评论没有回复按钮);<li> 被 <div> 包着,嵌套回复错位。
   现在统一到 yang_comment_html() 单一渲染函数,列表与 AJAX 只差一个
   is-new 类。同时修掉三处真实缺陷:
     · 评论项用 flex 会把 <ol class="yang-children"> 当成第三个 flex 项,
       子评论跑到父评论右侧、正文被挤到 156px、页面横向溢出 75px —— 改 grid
     · 成功提示在 exitReplyMode() 之前设置,被其末尾的 setStatus('','')
       擦掉,用户提交成功却看不到反馈 —— 调整顺序
     · 窄屏媒体查询打不过深层选择器(媒体查询不增加特异性),
       嵌套头像反向变大 —— 补深层覆盖

   与 wpDiscuz 解耦:邮件模块不再无条件 return false(那等于永久关掉
   notify_postauthor 且不报错);插件在场时不加载主题评论资源,
   避免双份表单互抢。

验证:PHP 语法 73/73;_static_qingming 36、_test_toc 53、
_test_comments 62、_test_comments_falsify 17、
_toc_geometry 121、_toc_geometry_falsify 9、
_comments_geometry 98、_comments_geometry_falsify 23,全部 0 失败。
线上端到端 29/0(真实文章渲染目录 + 真实评论数据渲染)。
This commit is contained in:
2026-10-24 01:03:36 +08:00
parent 4beb09307c
commit cbe0f2dc59
14 changed files with 3577 additions and 192 deletions
+18 -101
View File
@@ -197,101 +197,21 @@ function pagelist($range = 5)
}
}
// 文章评论
function comment_scripts()
{
wp_enqueue_script('comment', ASSET_PATH . '/assets/js/comments.min.js', array(), THEME_VERSION);
wp_localize_script('comment', 'ajaxcomment', array(
'ajax_url' => admin_url('admin-ajax.php'),
'order' => get_option('comment_order')
));
}
add_action('wp_enqueue_scripts', 'comment_scripts');
function comment_err($a)
{
header('HTTP/1.0 500 Internal Server Error');
header('Content-Type: text/plain;charset=UTF-8');
echo $a;
exit;
}
function comment_callback()
{
$comment = wp_handle_comment_submission(wp_unslash($_POST));
if (is_wp_error($comment)) {
$data = $comment->get_error_data();
if (!empty($data)) {
comment_err($comment->get_error_message());
} else {
exit;
}
}
$user = wp_get_current_user();
do_action('set_comment_cookies', $comment, $user);
$GLOBALS['comment'] = $comment;
?>
<li class="comment cleanfix" id="comment-<?php echo esc_attr(comment_ID()); ?>">
<div class="avatar float-left d-inline-block mr-2">
<?php if (function_exists('get_avatar') && get_option('show_avatars')) {echo get_avatar($comment, 50);}?>
</div>
<div class="info clearfix">
<cite class="author_name"><?php echo get_comment_author_link();?></cite>
<div class="content pb-2">
<?php comment_text();?>
</div>
<div class="meta clearfix">
<div class="date d-inline-block float-left"><?php echo get_comment_date('Y年m月d日'); ?><?php if (current_user_can('edit_posts')) {echo '<span class="ml-2">';edit_comment_link(__('编辑', 'kratos'));echo '</span>';};?>
</div>
</div>
</div>
</li>
<?php die();
}
add_action('wp_ajax_nopriv_ajax_comment', 'comment_callback');
add_action('wp_ajax_ajax_comment', 'comment_callback');
function comment_post($incoming_comment)
{
$incoming_comment['comment_content'] = htmlspecialchars($incoming_comment['comment_content']);
$incoming_comment['comment_content'] = str_replace("'", '&apos;', $incoming_comment['comment_content']);
return ($incoming_comment);
}
add_filter('preprocess_comment', 'comment_post', '', 1);
function comment_display($comment_to_display)
{
$comment_to_display = str_replace('&apos;', "'", $comment_to_display);
return $comment_to_display;
}
add_filter('comment_text', 'comment_display', '', 1);
function comment_callbacks($comment, $args, $depth = 2)
{
$GLOBALS['comment'] = $comment;?>
<li class="comment cleanfix" id="comment-<?php echo esc_attr(comment_ID()); ?>">
<div class="avatar float-left d-inline-block mr-2">
<?php if (function_exists('get_avatar') && get_option('show_avatars')) {echo get_avatar($comment, 50);}?>
</div>
<div class="info clearfix">
<cite class="author_name"><?php echo get_comment_author_link();?></cite>
<div class="content pb-2">
<?php comment_text();?>
</div>
<div class="meta clearfix">
<div class="date d-inline-block float-left"><?php echo get_comment_date('Y年m月d日'); ?><?php if (current_user_can('edit_posts')) {echo '<span class="ml-2">';edit_comment_link(__('编辑', 'kratos'));echo '</span>';};?>
</div>
<div class="tool reply ml-2 d-inline-block float-right">
<?php
$defaults = array('add_below' => 'comment', 'respond_id' => 'respond', 'reply_text' => '<i class="kicon i-reply"></i><span class="ml-1">' . __('回复', 'kratos') . '</span>');
comment_reply_link(array_merge($defaults, array('depth' => $depth, 'max_depth' => $args['max_depth'])));
?>
</div>
</div>
</div>
<?php
}
/* ── 评论相关已迁到 inc/theme-comments.php(3.2.18)──────────────
*
* 原先这里有一段 201~294 行的评论实现(comment_scripts /
* comment_callback / comment_callbacks)和 380~385 行的
* recover_comment_fields。迁走的原因是:
*
* · 列表渲染与 AJAX 渲染**各写了一份 HTML**,已经分叉 ——
* AJAX 返回的新评论没有「回复」按钮,必须刷新页面才出现;
* · 提交逻辑用的是旧的 layer 弹窗 + 直接透传后端原始响应;
* · 缺少 nonce 校验、缺少防重复提交。
*
* 新实现统一到 yang_comment_html() 一个渲染函数,两边都调它,
* 从结构上消除分叉可能。函数名 comment_callbacks / comment_scripts
* 也都在新文件里以兼容形式保留,所以 comments.php 不必改调用点。
* ------------------------------------------------------------ */
// 文章评论表情
function custom_smilies_src($img_src, $img, $siteurl)
@@ -377,12 +297,9 @@ function comment_add_at($comment_text, $comment = '') {
}
add_filter('comment_text' , 'comment_add_at', 20, 2);
function recover_comment_fields($comment_fields){
$comment = array_shift($comment_fields);
$comment_fields = array_merge($comment_fields ,array('comment' => $comment));
return $comment_fields;
}
add_filter('comment_form_fields','recover_comment_fields');
/* recover_comment_fields() 已由 inc/theme-comments.php 里的
yang_comment_form_fields() 接替(同样的字段顺序,但不再用
array_shift 硬拿第一个 —— 那样在插件往字段数组前面插东西时会拿错)。 */
$new_meta_boxes =
array(