本文约 4,665 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:反垃圾不是装个插件就完事
每个社区站长都会经历那个早上:打开后台,300 条待审评论,全是英文博彩链接。装了 Akismet 之后好一些,但很快又出现新的问题——机器绕过 Akismet 发中文软广、老用户之间吵架需要人工介入、有人举报内容但你没有一个受理入口。反垃圾真正的结构应该是三层:机器过滤(挡掉 95%)、规则过滤(挡掉剩下大部分)、人工兜底(处理争议)。只有第一层的社区,要么被淹,要么误杀正常用户。
原理分析:三层过滤的分工
| 层级 | 手段 | 拦截率 | 误杀风险 |
|---|---|---|---|
| 机器层 | Akismet、reCAPTCHA、蜜罐字段 | 高 | 低 |
| 规则层 | 黑名单关键词、链接数限制、频率限制 | 中 | 中 |
| 人工层 | 待审队列、举报入口、版主处理 | 低 | 无 |
WordPress 内置了两套关键词机制,存放在 options 表里:moderation_keys(命中后进入待审)与 blacklist_keys(命中后直接判垃圾)。这两套由 wp_check_comment_data() 触发,是规则层的基础。核心钩子是 pre_comment_approved——它决定一条内容的初始状态,返回 0(待审)、1(通过)、spam(垃圾)。规则层的自定义逻辑全部挂在这里。
保姆级实操
步骤 1:配置内置的审核规则。 进入”设置 → 讨论”,勾选”评论必须经人工批准”(对新站点强烈建议开启),并填写”评论审核关键词”与”评论黑名单”。
步骤 2:接入 Akismet。 装插件后在设置页填入 API Key。Akismet 会把判定结果写进评论的 akismet_result meta,后续可以据此统计拦截量。
步骤 3:加蜜罐字段。 机器表单会填满所有字段,人类看不见隐藏字段,所以隐藏字段被填即判定为机器。这是成本最低、误杀最少的一招。
// 在评论表单里插入一个人类看不见的字段
add_filter( 'comment_form_defaults', 'mimangfei_add_honeypot' );
function mimangfei_add_honeypot( $defaults ) {
$defaults['fields']['hp'] = '<p style="display:none"><input type="text" name="mmf_hp" value="" autocomplete="off" tabindex="-1"></p>';
return $defaults;
}
// 隐藏字段被填写即为机器
add_filter( 'pre_comment_approved', 'mimangfei_check_honeypot' );
function mimangfei_check_honeypot( $approved ) {
if ( ! empty( $_POST['mmf_hp'] ) ) {
return 'spam';
}
return $approved;
}
步骤 4:写敏感词与链接数规则。 敏感词命中进待审,链接超过 2 条也进待审,正常用户几乎不受影响。
add_filter( 'pre_comment_approved', 'mimangfei_content_rules', 10, 2 );
function mimangfei_content_rules( $approved, $commentdata ) {
if ( 'spam' === $approved ) {
return $approved;
}
$content = isset( $commentdata['comment_content'] ) ? $commentdata['comment_content'] : '';
// 规则一:链接数量限制
$links = preg_match_all( '/https?:\/\//i', $content, $m );
if ( $links > 2 ) {
return 0; // 进入待审
}
// 规则二:敏感词命中
$words = (array) get_option( 'mmf_moderation_words', array() );
foreach ( $words as $word ) {
if ( $word && false !== mb_strpos( $content, $word ) ) {
return 0;
}
}
// 规则三:新用户前 3 条内容一律待审
$user = wp_get_current_user();
if ( $user->exists() ) {
$count = get_comments( array(
'user_id' => $user->ID,
'status' => 'approve',
'count' => true,
) );
if ( $count < 3 ) {
return 0;
}
}
return $approved;
}
步骤 5:做频率限制。 同一 IP 在 60 秒内提交超过 3 次即拦截。用 transient 存储,不额外建表。
add_filter( 'pre_comment_approved', 'mimangfei_rate_limit' );
function mimangfei_rate_limit( $approved ) {
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
$key = 'mmf_rate_' . md5( $ip );
$hit = (int) get_transient( $key );
if ( $hit >= 3 ) {
return 'spam';
}
set_transient( $key, $hit + 1, MINUTE_IN_SECONDS );
return $approved;
}
步骤 6:加举报入口。 给每条内容一个”举报”按钮,写入独立表或用 comment meta 记录,后台统一处理。
add_action( 'wp_ajax_mmf_report', 'mimangfei_handle_report' );
add_action( 'wp_ajax_nopriv_mmf_report', 'mimangfei_handle_report' );
function mimangfei_handle_report() {
check_ajax_referer( 'mmf_report', 'nonce' );
$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
$reason = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : '';
if ( ! $post_id ) {
wp_send_json_error( '参数错误' );
}
$reports = (array) get_post_meta( $post_id, '_mmf_reports', true );
$reports[] = array(
'user' => get_current_user_id(),
'ip' => $_SERVER['REMOTE_ADDR'],
'time' => current_time( 'mysql' ),
'reason'=> $reason,
);
update_post_meta( $post_id, '_mmf_reports', $reports );
// 举报达 3 次自动转为待审
if ( count( $reports ) >= 3 ) {
wp_update_post( array( 'ID' => $post_id, 'post_status' => 'pending' ) );
wp_mail( get_option( 'admin_email' ), '内容被多次举报', '请处理:' . get_permalink( $post_id ) );
}
wp_send_json_success( '已收到举报' );
}
步骤 7:给版主配好工具。 在后台装”批量处理”类视图,并配置待审通知邮件,避免待审队列积压超过 24 小时。
常见踩坑
- 只装 Akismet 不加规则。 Akismet 对中文软广识别率偏低,需要本土规则补位。
- 误杀正常用户。 敏感词里包含了常见词的 substring,应做全词匹配或维护白名单。
- 待审队列积压。 没有通知机制,管理员三天没登录,评论区等于关闭。
- 案例: 某社区把”评论黑名单”配置得过宽,包含了单字”票”,结果正常讨论”机票”的用户评论被直接判垃圾且不通知,两周后才被发现,期间流失了大量老用户。教训:敏感词优先用”进待审”而不是”直接判垃圾”。
- 蜜罐字段被浏览器自动填充。 要加
autocomplete="off"与负tabindex。 - 举报接口没做 nonce 校验。 可被脚本刷举报,导致正常内容被自动下架。
- 频率限制用了 IP 但站点在 CDN 后。 必须取
HTTP_X_FORWARDED_FOR或使用 CDN 提供的真实 IP 头。
总结
三层过滤的配置顺序是:先开 Akismet 与蜜罐(机器层),再加链接数、敏感词、新用户审核(规则层),最后补举报入口与版主通知(人工层)。判断标准:待审队列不超过 24 小时、正常用户几乎不被拦截、垃圾内容不在前台出现超过 10 分钟。社区互动载体怎么选见WordPress 论坛插件对比;会员内容的权限保护见会员权限与内容保护。
