diff --git a/functions.php b/functions.php index 7b0f50e..6c11ae5 100644 --- a/functions.php +++ b/functions.php @@ -95,6 +95,11 @@ require get_template_directory() . '/inc/theme-mail-template.php'; // 邮件治理:统一接管发信通道、去重、关掉重复通知 require get_template_directory() . '/inc/theme-mail.php'; +// 核心评论通知正文接管:挂 comment_notification_text / comment_moderation_text +// 两个过滤器。不接管的话,核心那封纯文本会被 Content-Type: text/html 硬渲染, +// 收件人看到的是一堆没有样式的裸地址(3.2.18 卸载 wpDiscuz 后才暴露)。 +require get_template_directory() . '/inc/theme-mail-core.php'; + // SMTP 配置(连通性相关,实际接管在 theme-mail.php) require get_template_directory() . '/inc/theme-smtp.php'; diff --git a/inc/theme-mail-core.php b/inc/theme-mail-core.php new file mode 100644 index 0000000..df0ae00 --- /dev/null +++ b/inc/theme-mail-core.php @@ -0,0 +1,248 @@ + + * @license MIT License + */ + +if (!defined('ABSPATH')) { + exit; +} + +/** + * 取评论对应的文章标题 + * + * 文章被删掉时 get_the_title() 返回空串,邮件里就会出现《》, + * 比直接说「文章已删除」更难懂。 + */ +function yang_mail_core_post_title($post_id) +{ + $post = get_post($post_id); + if (!$post) { + return __('(文章已删除)', 'kratos'); + } + $t = get_the_title($post); + return $t !== '' ? $t : __('(无标题)', 'kratos'); +} + +/** + * 后台评论操作链接 + * + * 核心给的 approve / spam / trash 是三个裸 URL,这里做成模板里的一行 + * 文字链接。为什么不做成三个并排按钮:邮件里并排三个按钮在手机上 + * 必然换行、高度不齐,看起来像渲染出错;而且这些是后台管理动作, + * 不该和主按钮抢视觉权重。 + * + * @param int $comment_id + * @param bool $with_approve 已发布的评论不需要「通过」 + * @return array + */ +function yang_mail_core_action_links($comment_id, $with_approve = false) +{ + $id = (int) $comment_id; + $links = array(); + + if ($with_approve) { + $links[] = array( + 'text' => __('通过审核', 'kratos'), + 'url' => admin_url("comment.php?action=approve&c={$id}#wpbody-content"), + ); + } + + if (EMPTY_TRASH_DAYS) { + $links[] = array( + 'text' => __('移至回收站', 'kratos'), + 'url' => admin_url("comment.php?action=trash&c={$id}#wpbody-content"), + ); + } else { + $links[] = array( + 'text' => __('永久删除', 'kratos'), + 'url' => admin_url("comment.php?action=delete&c={$id}#wpbody-content"), + ); + } + + $links[] = array( + 'text' => __('标记为垃圾', 'kratos'), + 'url' => admin_url("comment.php?action=spam&c={$id}#wpbody-content"), + ); + + return $links; +} + +/** + * 把评论通知(有新评论 → 文章作者)渲染成主题模板 + * + * @param string $text 核心生成的纯文本(仅在参数非法时原样返回) + * @param string|int $comment_id + * @return string + */ +function yang_mail_core_render_comment_notify($text, $comment_id) +{ + if (!yang_mail_smtp_ready()) { + return $text; + } + + $comment = get_comment($comment_id); + if (!($comment instanceof WP_Comment)) { + return $text; + } + + // 引用 / Pingback 不是评论,字段结构不同,不套模板 + if ($comment->comment_type === 'trackback' || $comment->comment_type === 'pingback') { + return $text; + } + + $title = yang_mail_core_post_title($comment->comment_post_ID); + $author = $comment->comment_author !== '' ? $comment->comment_author : __('匿名访客', 'kratos'); + + $rows = array( + array('label' => __('文章', 'kratos'), 'value' => $title), + array('label' => __('评论者', 'kratos'), 'value' => $author, 'strong' => true), + ); + + if ($comment->comment_author_email !== '') { + $rows[] = array('label' => __('邮箱', 'kratos'), 'value' => $comment->comment_author_email); + } + if ($comment->comment_author_url !== '') { + $rows[] = array('label' => __('网址', 'kratos'), 'value' => $comment->comment_author_url); + } + if ($comment->comment_author_IP !== '') { + $rows[] = array('label' => __('IP 地址', 'kratos'), 'value' => $comment->comment_author_IP); + } + $rows[] = array('label' => __('时间', 'kratos'), 'value' => mysql2date('Y-m-d H:i', $comment->comment_date)); + + return yang_mail_render(array( + 'title' => sprintf(__('%s · 新评论', 'kratos'), get_bloginfo('name')), + 'preheader' => sprintf(__('%s 在《%s》下发表了评论。', 'kratos'), $author, $title), + 'badge' => __('新评论', 'kratos'), + 'heading' => __('文章有新评论', 'kratos'), + 'intro' => sprintf(__('《%s》收到了一条新评论。', 'kratos'), $title), + 'quotes' => array( + array( + 'label' => sprintf(__('%s 说', 'kratos'), $author), + 'content' => yang_mail_text($comment->comment_content, 1200), + 'meta' => mysql2date('Y-m-d H:i', $comment->comment_date), + ), + ), + 'rows' => $rows, + 'cta_text' => __('查看评论', 'kratos'), + 'cta_url' => get_comment_link($comment), + 'links' => yang_mail_core_action_links($comment->comment_ID, false), + 'note' => __('你收到这封邮件,是因为你是这篇文章的作者。', 'kratos'), + )); +} +add_filter('comment_notification_text', 'yang_mail_core_render_comment_notify', 20, 2); + +/** + * 把审核通知(有待审评论 → 管理员)渲染成主题模板 + * + * 内容与上面高度重合,差别只有:徽标是「待审核」、主按钮去审核面板、 + * 操作行多一个「通过审核」。合并成一个函数要靠一堆 if 分叉, + * 不如分开写清楚。 + * + * @param string $text + * @param string|int $comment_id + * @return string + */ +function yang_mail_core_render_moderation($text, $comment_id) +{ + if (!yang_mail_smtp_ready()) { + return $text; + } + + $comment = get_comment($comment_id); + if (!($comment instanceof WP_Comment)) { + return $text; + } + + if ($comment->comment_type === 'trackback' || $comment->comment_type === 'pingback') { + return $text; + } + + $title = yang_mail_core_post_title($comment->comment_post_ID); + $author = $comment->comment_author !== '' ? $comment->comment_author : __('匿名访客', 'kratos'); + + $rows = array( + array('label' => __('文章', 'kratos'), 'value' => $title), + array('label' => __('评论者', 'kratos'), 'value' => $author, 'strong' => true), + ); + + if ($comment->comment_author_email !== '') { + $rows[] = array('label' => __('邮箱', 'kratos'), 'value' => $comment->comment_author_email); + } + if ($comment->comment_author_url !== '') { + $rows[] = array('label' => __('网址', 'kratos'), 'value' => $comment->comment_author_url); + } + if ($comment->comment_author_IP !== '') { + $rows[] = array('label' => __('IP 地址', 'kratos'), 'value' => $comment->comment_author_IP); + } + $rows[] = array('label' => __('时间', 'kratos'), 'value' => mysql2date('Y-m-d H:i', $comment->comment_date)); + + return yang_mail_render(array( + 'title' => sprintf(__('%s · 待审核评论', 'kratos'), get_bloginfo('name')), + 'preheader' => sprintf(__('%s 在《%s》下的评论等待审核。', 'kratos'), $author, $title), + 'badge' => __('待审核', 'kratos'), + 'heading' => __('有一条评论等待审核', 'kratos'), + 'intro' => sprintf(__('《%s》收到了新评论,需要你确认后才公开显示。', 'kratos'), $title), + 'quotes' => array( + array( + 'label' => sprintf(__('%s 说', 'kratos'), $author), + 'content' => yang_mail_text($comment->comment_content, 1200), + 'meta' => mysql2date('Y-m-d H:i', $comment->comment_date), + ), + ), + 'rows' => $rows, + 'cta_text' => __('去后台审核', 'kratos'), + 'cta_url' => admin_url('edit-comments.php?comment_status=moderated#wpbody-content'), + 'links' => yang_mail_core_action_links($comment->comment_ID, true), + 'note' => __('这是评论审核提醒,处理完即可忽略。', 'kratos'), + )); +} +add_filter('comment_moderation_text', 'yang_mail_core_render_moderation', 20, 2); \ No newline at end of file diff --git a/inc/theme-mail-template.php b/inc/theme-mail-template.php index 9fdd7f7..2bb68f4 100644 --- a/inc/theme-mail-template.php +++ b/inc/theme-mail-template.php @@ -750,6 +750,9 @@ function yang_mail_button($text, $url, $bg = null, $fg = null) * @type string $cta_url 按钮链接 * @type string $note 底部提示(纯文本) * @type string $badge 顶部小标签,如「新评论」 + * @type array $links 次要操作链接,每项 array('text'=>, 'url'=>)。 + * 用于后台管理动作(通过/回收站/垃圾),渲染成一行文字链接, + * 不做成并排按钮:手机宽度下三个按钮必然换行、高度不齐。 * } * @return string 完整 HTML */ @@ -767,6 +770,7 @@ function yang_mail_render($args) 'cta_url' => '', 'note' => '', 'badge' => '', + 'links' => array(), // 次要操作链接 array('text'=>, 'url'=>),渲染成一行文字链接 )); /* 统一成 $quoteList: @@ -973,6 +977,30 @@ function yang_mail_render($args) + + +