本文提供用户评论回复邮件通知的代码片段,说明其功能、使用方法、已发现的问题与推荐修复/改进措施,帮助你安全可靠地在 WordPress 站点中启用评论通知邮件。
作者已编写插件实现此功能,点击前往:https://yanqs.me/wp-comment-notify-plugin/

将以下代码粘贴入主题
functions.php即可启用
话不多说,我们先贴上代码。
代码
<?php
// 自定义评论回复通知邮件
function custom_comment_mail_notify($comment_id)
{
$admin_notify = '1'; // admin 要不要收回复通知 ( '1'=要 ; '0'=不要 )
$admin_email = get_bloginfo('admin_email');
$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
$comment = get_comment($comment_id);
$parent_id = $comment->comment_parent ? $comment->comment_parent : '';
$spam_confirmed = $comment->comment_approved;
global $wpdb;
$comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
if (($parent_id != '') && ($spam_confirmed != 'spam') && ($to != $admin_email)) {
$wp_email = 'no-reply@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
$to = trim(get_comment($parent_id)->comment_author_email);
$subject = '您在 [' . $blogname . ']' . ' 中的留言有了新回复!';
$message = '
<div style="background-color:white;border-left: 2px solid #555555;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;width:500px;margin:50px auto;color:#555555;font-family:"Source Sans Pro","Hiragino Sans GB","Microsoft Yahei",SimSun,Helvetica,Arial,Sans-serif,monospace;font-size:14px;">
<h2 style="border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;">
<span style="color: #409eff;font-weight: bold;">> </span>
您在 <a style="text-decoration:none; color:#409eff;font-weight:600;" href="' . home_url() . '">' . $blogname . '</a> 的留言有回复啦!
</h2>
<div style="font-size: 14px; color: #777; padding: 0 10px; margin-top: 18px;">
<p><b>' . trim(get_comment($parent_id)->comment_author) . '</b> 您曾在文章<b>《' . get_the_title($comment->comment_post_ID) . '》</b>上发表评论:</p>
<p style="background: #F5F5F5; padding: 10px 15px; margin: 18px 0;">' . nl2br(strip_tags(get_comment($parent_id)->comment_content)) . '</p>
<p>' . '<b>' . trim($comment->comment_author) . '</b>' . ' 给您的回复如下:</p>
<p style="background: #F5F5F5; padding: 10px 15px; margin: 18px 0;">' . nl2br(strip_tags($comment->comment_content)) . '</p>
<p>您可以点击 <a style="text-decoration:none; color:#409eff" href="' . htmlspecialchars(get_comment_link($parent_id)) . '">查看完整的回复內容</a>,也欢迎再次光临 <a style="text-decoration:none; color:#409eff"
href="' . home_url() . '">' . $blogname . '</a>。祝您生活愉快!</p>
<p style="padding-bottom: 15px;">(此邮件由系统自动发出,请勿直接回复!)</p>
</div>
</div>';
$from = "From: \"" . get_option('blogname') . "\" <$wp_email>";
$headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n";
wp_mail($to, $subject, $message, $headers);
}
//文章有新评论时通知管理员
if ($parent_id == '' && (trim($comment->comment_author_email) != trim($admin_email)) && ($spam_confirmed != 'spam') && ($comment->comment_approved != 0)) {
$wp_email = '';
$subject = '在「' . $blogname . '」的文章《' . get_the_title($comment->comment_post_ID) . '》一文有新的评论';
$message = '
<div style="background-color:white;border-left: 2px solid #555555;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;width:500px;margin:50px auto;color:#555555;font-family:"Source Sans Pro","Hiragino Sans GB","Microsoft Yahei",SimSun,Helvetica,Arial,Sans-serif,monospace;font-size:14px;">
<h2 style="border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;">
<span style="color: #409eff;font-weight: bold;">> </span>
<a style="text-decoration:none;color: #409eff;" href="' . home_url() . '">' . $blogname . '</a> 博客有新的评论啦!
</h2>
<div style="padding:0 12px 0 12px;margin-top:18px;">
<p><b>' . $comment->comment_author . '</b> 在文章<b>《' . get_the_title($comment->comment_post_ID) . '》</b>上发表评论:</p>
<p style="background-color: #f5f5f5;border: 0px solid #DDD;padding: 10px 15px;margin:18px 0;">' . $comment->comment_content . '</p>
<p>您可以点击 <a style="text-decoration:none; color:#409eff" href="' . htmlspecialchars(get_comment_link($parent_id)) . '">查看完整的回复內容</a>,也欢迎再次光临 <a style="text-decoration:none; color:#409eff" href="' . home_url() . '">' . $blogname . '</a>。祝您生活愉快!</p>
</div>
</div>';
$headers = "Content-Type: text/html; charset=" . get_option('blog_charset') . "\n";
wp_mail($admin_email, $subject, $message, $headers);
}
//评论需要审核时通知
if ($parent_id == '' && (trim($comment->comment_author_email) != trim($admin_email)) && ($spam_confirmed != 'spam') && ($spam_confirmed != 'trash') && ($comment->comment_approved == 0)) {
$wp_email = '';
$subject = '在「' . $blogname . '」的文章《' . get_the_title($comment->comment_post_ID) . '》中有新的评论需要审核';
$message = '
<div style="background-color:white;border-left: 2px solid #555555;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;width:500px;margin:50px auto;color:#555555;font-family:"Source Sans Pro","Hiragino Sans GB","Microsoft Yahei",SimSun,Helvetica,Arial,Sans-serif,monospace;font-size:14px;">
<h2 style="border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;">
<span style="color: #409eff;font-weight: bold;">> 「 </span>
<a style="text-decoration:none;color: #409eff;" href="' . home_url() . '">' . $blogname . '」</a> 中有一条评论等待您的审核
</h2>
<div style="padding:0 12px 0 12px;margin-top:18px;">
<p><b>' . $comment->comment_author . '</b> 在文章<b><a style="text-decoration:none;color: #409eff;" href="' . get_permalink($comment->comment_post_ID) . '">《' . get_the_title($comment->comment_post_ID) . '》</a></b>上发表评论:</p>
<p style="background-color: #f5f5f5;border: 0px solid #DDD;padding: 10px 15px;margin:18px 0;">' . $comment->comment_content . '</p>
<p><a style="text-decoration:none;color: #007017;" href="' . admin_url("comment.php?action=approve&c={$comment_id}#wpbody-content") . '">[批准评论]</a> | <a style="text-decoration:none;color: #b32d2e;" href="' . admin_url("comment.php?action=trash&c={$comment_id}#wpbody-content") . '">[移至回收站]</a>。您还可以:<a style="text-decoration:none; color:#b32d2e" href="' . admin_url("comment.php?action=delete&c={$comment_id}#wpbody-content") . '">永久删除评论</a> | <a style="text-decoration:none;color: #b32d2e;" href="' . admin_url("comment.php?action=spam&c={$comment_id}#wpbody-content") . '">标记为垃圾评论</a>
<p>当前有 ' . $comments_waiting . ' 条评论等待审核。请移步<a style="text-decoration:none;color: #409eff;" href="' . admin_url('edit-comments.php?comment_status=moderated#wpbody-content') . '">审核页面</a>来查看。</p>也欢迎再次光临 <a style="text-decoration:none; color:#409eff" href="' . home_url() . '">' . $blogname . '</a>。祝您生活愉快!</p>
</div>
</div>';
$headers = "Content-Type: text/html; charset=" . get_option('blog_charset') . "\n";
wp_mail($admin_email, $subject, $message, $headers);
}
}
add_action('comment_post', 'custom_comment_mail_notify');
概述
上述代码提供了一个函数 pk_comment_mail_notify($comment_id),并通过 add_action('comment_post', 'pk_comment_mail_notify') 将其挂载到 comment_post 钩子上。函数实现了三类通知:
- 当某条评论是对已有评论的回复时,向被回复的评论作者发送回复通知(邮件 HTML 模板)。
- 当某篇文章有新评论时,向管理员发送通知(仅当该评论不是来自管理员本人且未标记为垃圾且已通过审核)。
- 当某条评论需要人工审核(未通过自动审核)时,向管理员发送审核提醒邮件。
邮件内容使用 HTML 模版拼接,包含文章标题、原评论与回复内容,并提供跳转链接(如查看回复、审核评论等)。
如何使用
- 将上述代码放入你主题或插件的合适位置(例如主题的
functions.php或单独插件文件中)。 - 确保文件被加载(通过
require/include或在插件中激活)。 - 根据需要修改
From地址、样式或文案。
示例:把上述代码保存为 WordPress_Mail.php 放在主题目录并在 functions.php 中引入:
require get_template_directory() . '/WordPress_Mail.php';
已知问题与安全建议(重要)
下面列出阅读 WordPress_Mail.php 源码时应注意的问题,并给出修复建议:
- 条件中使用了未定义变量
$to
- 代码片段中有如下判断:
if (($parent_id != '') && ($spam_confirmed != 'spam') && ($to != $admin_email)) {
// ... 之后才设置 $to = trim(get_comment($parent_id)->comment_author_email);
}
-
问题:此处
$to在判断时尚未定义,可能导致未定义变量通知或逻辑错误(在某些 PHP 配置下会被视为空串),应改为直接比较父评论作者邮箱或先定义$to。 -
推荐修复(把
$to的定义提前并比较邮箱):
$parent_author_email = trim(get_comment($parent_id)->comment_author_email);
if (($parent_id != '') && ($spam_confirmed != 'spam') && ($parent_author_email != $admin_email)) {
$to = $parent_author_email;
// ...
}
- 头部换行与头注入风险
- 当前代码构造邮件头使用 “\n”(单 LF)或字符串拼接:
$headers = "$from\nContent-Type: text/html; charset=" . get_option('blog_charset') . "\n";
-
建议:使用
\r\n作为头部行结束符;更安全的做法是使用wp_mail()的 headers 参数传入数组或使用 WordPress 的过滤器wp_mail_from/wp_mail_from_name来设置发件人,避免直接拼接来自外部的值。 -
另外,任何直接来自用户输入的头部字段(如
From、Subject)都应清洗换行符以防止 header 注入攻击:
function safe_mail_header($value) {
return str_replace(array("\r", "\n"), '', $value);
}
$from_name = safe_mail_header(get_option('blogname'));
$wp_email = 'no-reply@' . preg_replace('#^www\\.#', '', strtolower($_SERVER['SERVER_NAME']));
$from = sprintf('From: "%s" <%s>', $from_name, $wp_email);
- HTML 内容需转义与严格控制用户输入
- 邮件中插入了评论内容(
$comment->comment_content)和作者名。即使要显示 HTML,也应使用wp_kses_post()或esc_html()/esc_attr()进行过滤,避免邮件中包含恶意脚本或反射式内容。示例:
$safe_parent_content = wp_kses_post(get_comment($parent_id)->comment_content);
$safe_reply_content = wp_kses_post($comment->comment_content);
- 使用 WordPress 推荐方式发送 HTML 邮件
- 若需发送 HTML,推荐通过
wp_mail()并在发送前临时添加过滤器设置内容类型:
add_filter('wp_mail_content_type', function() { return 'text/html'; });
wp_mail($to, $subject, $message, $headers_array);
remove_filter('wp_mail_content_type', '...');
或者将 headers 作为数组传入:$headers = array('From: ...', 'Content-Type: text/html; charset=UTF-8');
- 建议使用
wp_mail()的返回值与错误记录
wp_mail()返回true/false,建议在发送失败时记录日志(使用error_log()或 WP 的日志机制)以便排查。
推荐改进与增强
- 使用
wp_mail_from与wp_mail_from_name过滤器统一设置发件人,或在主题/插件初始化处设置而不是在函数内部硬编码。 - 对邮件头使用数组模式,避免行结束符差异。
- 对 HTML 邮件使用
wp_mail_content_type过滤器。 - 将样式模板抽出为可维护的部分(如使用
ob_start()+ 模板文件输出),便于修改与本地化。 - 更进一步,考虑使用 SMTP 插件(如 WP Mail SMTP 或使用 PHPMailer 自行配置 OAuth/TLS),以提升送达率。
建议修补(完整示例片段)
下面给出一个合并了上面建议的简化示例片段,你可以把它替换 WordPress_Mail.php 中对应的逻辑:
// 取得父评论作者邮箱并检查
$parent_author_email = $parent_id ? trim(get_comment($parent_id)->comment_author_email) : '';
if ($parent_id && $spam_confirmed !== 'spam' && $parent_author_email && $parent_author_email !== $admin_email) {
$to = $parent_author_email;
$from_name = str_replace(array("\r", "\n"), '', get_option('blogname'));
$wp_email = 'no-reply@' . preg_replace('#^www\\.#', '', strtolower($_SERVER['SERVER_NAME']));
$headers = array();
$headers[] = sprintf('From: %s <%s>', $from_name, $wp_email);
// 使用 wp_mail 时通过 filter 设置 content type 为 HTML
add_filter('wp_mail_content_type', function() { return 'text/html'; });
// 内容使用过滤以防注入或不当 HTML
$safe_parent_author = esc_html(trim(get_comment($parent_id)->comment_author));
$safe_parent_content = wp_kses_post(get_comment($parent_id)->comment_content);
$safe_reply_author = esc_html(trim($comment->comment_author));
$safe_reply_content = wp_kses_post($comment->comment_content);
$subject = sprintf('您在 [%s] 的留言有了新回复!', wp_specialchars_decode(get_option('blogname'), ENT_QUOTES));
// 这里可用模板文件输出 HTML 内容
$message = '
<p>原评论者: <strong>' . $safe_parent_author . '</strong></p>' .
'
<p>' . nl2br($safe_parent_content) . '</p>' .
'
<hr>' .
'
<p>回复者: <strong>' . $safe_reply_author . '</strong></p>' .
'
<p>' . nl2br($safe_reply_content) . '</p>';
if (! wp_mail($to, $subject, $message, $headers)) {
error_log('评论回复通知邮件发送失败, comment_id: ' . $comment_id);
}
remove_filter('wp_mail_content_type', '...');
}
注意:上面示例里的 remove_filter 应使用与 add_filter 相同的回调引用(若使用匿名函数需另行处理)。生产代码中建议使用具名函数来便于移除。
测试说明
- 在本地或开发环境测试邮件功能,推荐使用 MailHog / Mailtrap 捕获并查看邮件输出,而不是直接对真实用户发送。
- 检查
wp_mail()返回值并查看服务器邮件日志(如使用 sendmail/postfix 时的/var/log/mail.log)。


