2026年10月17日

2026年10月17日

WordPressのコメントスパムを防ぐ完全ガイド【Akismet・honeypot・reCAPTCHA】

はじめに

WordPressのコメント欄は公開されているため、スパムBotの格好の標的になります。毎日大量のスパムコメントが届き、モデレーションが大変になることがあります。複数の防御策を組み合わせることでスパムを効果的に排除できます。

症状・原因

  • 毎日大量のスパムコメントが届き、承認待ちが数百件以上になっている
  • スパムコメントに外部サイトへのリンクや広告が含まれている
  • 自動化されたBotによるコメント投稿が大量に来ている
  • wp_commentmetaテーブルが大きくなりDBが重くなっている

解決手順

ステップ1:WordPress標準のコメント設定を最適化する

// functions.php: コメント設定の最適化
add_action('init', function(): void {
    // 登録ユーザーのみコメント可能
    update_option('comment_registration', 1);

    // コメント承認が必要
    update_option('comment_moderation', 1);

    // 既に承認済みユーザーはスキップ
    update_option('comment_whitelist', 1);

    // スパムに自動フラグを立てる条件
    update_option('comment_max_links', 2);  // リンク2個以上でスパム

    // 古い投稿へのコメントを閉じる(30日後)
    update_option('close_comments_for_old_posts', 1);
    update_option('close_comments_days_old', 30);
});

// コメント機能が不要なページタイプでは無効化
add_action('wp_loaded', function(): void {
    // ページではコメントを無効化
    add_filter('comments_open', function(bool $open, int $post_id): bool {
        $post = get_post($post_id);
        if ($post && $post->post_type === 'page') {
            return false;
        }
        return $open;
    }, 10, 2);
});

ステップ2:Honeypotフィールドを実装する

// Honeypotフィールド(Botトラップ)
// Botは見えないフィールドに入力する傾向がある
class Comment_Honeypot {

    public function __construct() {
        add_action('comment_form_after_fields', [$this, 'add_honeypot_field']);
        add_filter('preprocess_comment',        [$this, 'validate_honeypot']);
    }

    // 非表示フィールドを追加(CSSで隠す)
    public function add_honeypot_field(): void {
        echo '<p id="comment-hp-field" style="display:none !important; visibility:hidden; position:absolute; left:-9999px;" aria-hidden="true">';
        echo '<label for="comment_hp">コメントを入力しないでください(スパム対策)</label>';
        echo '<input type="text" id="comment_hp" name="comment_hp" value="" autocomplete="off" tabindex="-1">';
        echo '</p>';
    }

    // Honeypotフィールドが入力されていたらスパムと判定
    public function validate_honeypot(array $commentdata): array {
        $honeypot = sanitize_text_field($_POST['comment_hp'] ?? '');

        if (!empty($honeypot)) {
            // Botによる入力を検出
            wp_die(
                'スパムが検出されました。',
                'スパム',
                ['response' => 403, 'back_link' => true]
            );
        }

        return $commentdata;
    }
}

new Comment_Honeypot();

ステップ3:コメント投稿時間でBotを検出する

// コメント投稿が速すぎる場合はBotと判定
class Comment_Time_Check {

    public function __construct() {
        add_action('comment_form_top', [$this, 'set_timestamp']);
        add_filter('preprocess_comment', [$this, 'check_elapsed_time']);
    }

    public function set_timestamp(): void {
        $token = wp_create_nonce('comment_timestamp_' . session_id());
        echo '<input type="hidden" name="comment_timestamp" value="' . esc_attr(time()) . '">';
        echo '<input type="hidden" name="comment_timestamp_nonce" value="' . esc_attr($token) . '">';
    }

    public function check_elapsed_time(array $commentdata): array {
        $timestamp = (int) ($_POST['comment_timestamp'] ?? 0);
        $elapsed   = time() - $timestamp;

        // 3秒未満はBotと判定(人間には最低3秒必要)
        if ($timestamp && $elapsed < 3) {
            wp_die('コメントの送信が速すぎます。もう一度お試しください。', 403);
        }

        // 24時間以上古いフォームはリジェクト(CSRF対策)
        if ($timestamp && $elapsed > 86400) {
            wp_die('フォームの有効期限が切れています。ページを更新してください。', 403);
        }

        return $commentdata;
    }
}

new Comment_Time_Check();

ステップ4:コメントを一括管理・削除する

# WP-CLIでスパムコメントを管理
# スパムコメントの件数確認
wp comment list --status=spam --format=count

# スパムコメントを一括削除
wp comment delete $(wp comment list --status=spam --format=ids) --force

# 承認待ちコメントの確認
wp comment list --status=hold --format=count

# 特定のメールアドレスからのコメントをすべてスパムに
wp comment list --author_email=spam@example.com --format=ids | \
  xargs -I{} wp comment spam {}

# 古いスパムを定期削除(WP-Cron)
// 1週間以上古いスパムを自動削除
add_action('init', function(): void {
    if (!wp_next_scheduled('weekly_spam_cleanup')) {
        wp_schedule_event(time(), 'weekly', 'weekly_spam_cleanup');
    }
});

add_action('weekly_spam_cleanup', function(): void {
    $spams = get_comments([
        'status'     => 'spam',
        'date_query' => [['before' => '1 week ago']],
        'number'     => 500,
    ]);

    foreach ($spams as $spam) {
        wp_delete_comment($spam->comment_ID, true); // true = 完全削除
    }

    error_log('[Comment] Cleaned ' . count($spams) . ' spam comments');
});

ステップ5:コメントの通知とモデレーションを最適化する

// コメント通知メールをカスタマイズ
add_filter('comment_notification_recipients', function(array $emails, int $comment_id): array {
    $comment = get_comment($comment_id);

    // スパム判定コメントは通知しない
    if ($comment && $comment->comment_approved === 'spam') {
        return [];
    }

    return $emails;
}, 10, 2);

// コメント承認をAjaxで処理するショートカット
add_action('wp_ajax_quick_approve_comment', function(): void {
    check_ajax_referer('comment_action');

    if (!current_user_can('moderate_comments')) {
        wp_send_json_error('権限がありません');
    }

    $comment_id = (int) ($_POST['comment_id'] ?? 0);
    wp_set_comment_status($comment_id, 'approve');
    wp_send_json_success('承認しました');
});

注意事項

  • Akismetプラグイン: 商業サイトではAkismetの有料プランが必要です(無料プランは個人・非商業サイトのみ)
  • コメント完全無効化: スパムが深刻な場合はコメント機能自体を無効化するほうが効果的な場合があります(remove_post_support('post', 'comments'))
  • reCAPTCHAのアクセシビリティ: reCAPTCHAはスクリーンリーダーユーザーへの影響があります。代替手段(Honeypot等)との組み合わせを検討してください

まとめ

コメントスパム対策の組み合わせは「WordPress標準設定の最適化・Honeypot・投稿時間チェック・Akismet・定期的なスパム削除」です。これらを重ねることでスパムの99%以上をブロックできます。関連記事:WordPressのWAF設定方法

お気軽にご相談ください

お見積りへ お問い合わせへ
▲