2026年5月20日

2026年5月20日

WordPressのコメントスパムを完全に防ぐ方法

はじめに

WordPressのコメントスパムはSEOに悪影響を与え、管理者の負担を増やし、サイトの信頼性を損ないます。Akismet・honeypot・レート制限を組み合わせることでスパムをほぼ完全に防止できます。

症状・原因

  • 毎日大量のスパムコメントが届き、承認待ちが数百件になっている
  • カジノ・薬・アダルト等のスパムリンクを含むコメントが自動投稿されている
  • ボットがWordPressのコメントAPIを直接叩いてスパムを送信している
  • Akismetを設定しているのにスパムが通過してしまっている

解決手順

ステップ1:現在のスパム状況を確認する

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

# 直近のスパムコメントを確認
wp comment list --status=spam --fields=comment_author,comment_author_email,comment_author_url,comment_date --format=table | head -20

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

# データベースから直接削除(大量の場合)
wp eval "
global \$wpdb;
\$count = \$wpdb->query(\"DELETE FROM {\$wpdb->comments} WHERE comment_approved = 'spam'\");
echo \"Deleted spam comments: \" . \$count . PHP_EOL;
"

ステップ2:Akismet を正しく設定する

# Akismet をインストール・有効化
wp plugin install akismet --activate

# Akismet APIキーを設定(WordPress.com アカウントで取得)
wp option update akismet_strictness 1  # 厳格モード

# Akismet の設定をWP-CLIで確認
wp option get akismet_strictness
// functions.php: Akismet の設定を最適化

// ① 自動的にスパムを削除(承認待ちに入れない)
add_filter('akismet_spam_count', '__return_true');

// ② Akismet チェック後の処理をカスタマイズ
add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    // Akismet が spam と判定した場合
    if ($approved === 'spam') {
        // オプション: 即座に削除(デフォルトはスパムフォルダに保存)
        // return 'trash';  // ゴミ箱へ
    }
    return $approved;
}, 10, 2);

// ③ APIキーなしでもスパムをある程度防ぐ
add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    // URLを多数含むコメントを自動的にスパム扱い
    $url_count = substr_count($comment_data['comment_content'], 'http');
    if ($url_count > 2) {
        return 'spam';
    }
    return $approved;
}, 5, 2);

ステップ3:honeypot フィールドでボットをトラップする

// functions.php: honeypot(ハニーポット)でボットを検出

// ① honeypot フィールドをコメントフォームに追加
add_filter('comment_form_defaults', function(array $defaults): array {
    $defaults['fields']['hp_website'] =
        '<p class="comment-form-hp" style="display:none!important">'
        . '<label for="hp_website">Website (leave blank)</label>'
        . '<input type="text" name="hp_website" id="hp_website" value="" tabindex="-1" autocomplete="off">'
        . '</p>';
    return $defaults;
});

// ② honeypot フィールドが入力されていたらスパム扱い
add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    // ボットは非表示フィールドにも値を入れる
    if (!empty($_POST['hp_website'])) {
        return 'spam';
    }
    return $approved;
}, 1, 2);

// ③ タイムスタンプ検証(人間は最低数秒かかる)
add_action('comment_form', function(): void {
    echo '<input type="hidden" name="comment_timestamp" value="' . time() . '">';
});

add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    $timestamp = (int) ($_POST['comment_timestamp'] ?? 0);
    $elapsed = time() - $timestamp;

    // 3秒未満での送信はボット
    if ($timestamp > 0 && $elapsed < 3) {
        return 'spam';
    }
    // 1時間以上経過したフォームも拒否
    if ($timestamp > 0 && $elapsed > 3600) {
        return 'spam';
    }
    return $approved;
}, 2, 2);

ステップ4:コメント投稿のレート制限と検証を強化する

// functions.php: コメント投稿を厳格に制御

// ① 同一IPからの連続投稿を制限
add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    $ip = $comment_data['comment_author_IP'];
    $transient_key = 'comment_rate_' . md5($ip);
    $count = (int) get_transient($transient_key);

    if ($count >= 3) {  // 30分間に3件まで
        return 'spam';
    }

    set_transient($transient_key, $count + 1, 30 * MINUTE_IN_SECONDS);
    return $approved;
}, 10, 2);

// ② 禁止キーワードを含むコメントをブロック
add_filter('pre_comment_approved', function(mixed $approved, array $comment_data): mixed {
    $blocked_keywords = ['casino', 'viagra', 'buy cheap', 'click here', 'free money'];
    $content = strtolower($comment_data['comment_content']);

    foreach ($blocked_keywords as $keyword) {
        if (str_contains($content, $keyword)) {
            return 'spam';
        }
    }
    return $approved;
}, 10, 2);

// ③ ログインユーザーのみコメントを許可
// → 設定 → ディスカッション → 「コメントの投稿者の登録とログインを必須にする」
add_action('init', function(): void {
    if (!is_user_logged_in()) {
        add_filter('comments_open', '__return_false');
    }
});

ステップ5:コメントを完全に無効化する(必要な場合)

// functions.php: コメント機能を完全に無効化

// ① 新規コメントを完全にブロック
add_filter('comments_open', '__return_false');
add_filter('pings_open', '__return_false');

// ② 既存のコメント数を0として扱う
add_filter('get_comments_number', '__return_zero');

// ③ 管理画面のコメントメニューを非表示
add_action('admin_menu', function(): void {
    remove_menu_page('edit-comments.php');
});

// ④ ダッシュボードのコメントウィジェットを削除
add_action('wp_dashboard_setup', function(): void {
    remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');
});

// ⑤ wp-admin/comment*.php へのアクセスをリダイレクト
add_action('admin_init', function(): void {
    global $pagenow;
    if ($pagenow === 'edit-comments.php' || $pagenow === 'comment.php') {
        wp_redirect(admin_url());
        exit;
    }
});

注意事項

  • Akismetは商用サイトでは有料プランが必要です。無料の代替として「Antispam Bee」プラグインも有効です
  • honeypotフィールドはCSS非表示のため、スクリーンリーダーでは見えてしまいます。aria-hidden="true"tabindex="-1"を設定して支援技術から隠すことを推奨します
  • コメントを完全無効化した後も、既存のコメントはデータベースに残ります。完全に削除する場合はwp comment delete $(wp comment list --format=ids) --forceで全件削除してください

まとめ

コメントスパム対策は①wp comment list --status=spamで状況確認、②Akismetを設定してakismet_strictness=1で厳格モードに、③honeypotフィールド(非表示input)とタイムスタンプ検証でボットをトラップ、④IPベースのレート制限(30分3件まで)と禁止キーワードフィルター、⑤コメント不要ならcomments_open/__return_falseで完全無効化します。

お気軽にご相談ください

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