2026年5月21日
2026年5月21日
WordPressのスパムコメント・スパムユーザーをデータベースから一括削除する方法
この記事で扱うこと
スパムコメントは削除しない限り wp_comments と wp_commentmeta に残り続けます。数万件たまると、コメント一覧の表示やバックアップが重くなります。ここでは、スパムコメントとスパム登録ユーザーを安全に一括削除する方法を、手軽な順に説明します。
作業の前に、データベースのバックアップを取ってください。
wp db export before-spam-cleanup.sql
テーブル名の接頭辞は wp_ として書いています。違う場合は wp db prefix で確認し、SQL の中のテーブル名を読み替えてください。
まず件数とサイズを確認する
# 状態ごとのコメント数(承認済み・承認待ち・スパム・ゴミ箱など)
wp comment count
# スパムだけの件数
wp comment list --status=spam --format=count
# テーブルごとのサイズ
wp db size --tables
wp_comments の comment_approved 列は、承認済みが 1、承認待ちが 0、スパムが spam、ゴミ箱が trash です。
wp db query "SELECT comment_approved, COUNT(*) AS cnt FROM wp_comments GROUP BY comment_approved ORDER BY cnt DESC;"
方法1: 管理画面から削除する
件数が数千件程度までなら、管理画面で足ります。
- 「コメント」→「スパム」を開きます。
- 一覧の上にある「スパムをすべて削除」を押すと、スパムに分類されたコメントがゴミ箱を経由せずにすべて削除されます。
- 「ゴミ箱」のタブでも同様に「ゴミ箱を空にする」で削除できます。
件数が非常に多いと処理が時間切れになることがあります。その場合は次の WP-CLI を使います。
方法2: WP-CLIで一括削除する
wp comment delete --force は WordPress の wp_delete_comment() を通して削除するため、コメントに付いた wp_commentmeta の行も一緒に消え、投稿のコメント数も更新されます。
# スパムを1,000件ずつ、無くなるまで削除
while true; do
ids=$(wp comment list --status=spam --format=ids --number=1000)
[ -z "$ids" ] && break
wp comment delete $ids --force
done
# ゴミ箱のコメントも同じように削除
while true; do
ids=$(wp comment list --status=trash --format=ids --number=1000)
[ -z "$ids" ] && break
wp comment delete $ids --force
done
一度に全件の ID を渡すと、件数によってはコマンドラインの長さ制限を超えるため、1,000件ずつに分けています。
古いスパムだけを消す
誤判定のコメントを確認する猶予を残したい場合は、一定期間より古いものだけを消します。wp comment list には日付で絞る引数が無いため、wp eval で get_comments() の date_query を使います。
wp eval '
$comments = get_comments( array(
"status" => "spam",
"date_query" => array( array( "before" => "30 days ago" ) ),
"number" => 1000,
"fields" => "ids",
) );
foreach ( $comments as $id ) {
wp_delete_comment( $id, true );
}
echo count( $comments ) . " deleted\n";
'
1回で最大1,000件です。0件になるまで繰り返します。
承認待ちのコメントについて
承認待ち(--status=hold)には正規のコメントも含まれます。一括削除する前に、wp comment list --status=hold --fields=comment_ID,comment_author,comment_date --number=50 で中身を確認してください。
方法3: SQLで直接削除する
数十万件あり WP-CLI でも時間がかかる場合は、SQL で直接消せます。ただし WordPress の処理(フックや投稿のコメント数の更新)を通らないため、上の方法で済むならそちらを使ってください。スパムとゴミ箱のコメントはもともと投稿のコメント数に数えられていないため、これらを消すだけなら数の食い違いは起きません。
-- スパムを削除
DELETE FROM wp_comments WHERE comment_approved = 'spam';
-- ゴミ箱を削除
DELETE FROM wp_comments WHERE comment_approved = 'trash';
-- 親のコメントが無くなった commentmeta を削除
DELETE cm FROM wp_commentmeta cm
LEFT JOIN wp_comments c ON c.comment_ID = cm.comment_id
WHERE c.comment_ID IS NULL;
NOT IN (SELECT ...) で書くより、LEFT JOIN のほうが大きなテーブルで速く動きます。
wp db query から実行する場合は、1文ずつ渡します。
wp db query "DELETE FROM wp_comments WHERE comment_approved = 'spam';"
削除後に領域を返す
大量に削除しても、InnoDB のテーブルファイルはすぐには小さくなりません。テーブルを作り直すとファイルが縮みます。
wp db query "OPTIMIZE TABLE wp_comments, wp_commentmeta;"
InnoDB では「Table does not support optimize, doing recreate + analyze instead」と表示されますが、これは作り直しが行われたという意味で、エラーではありません。作り直しの間はテーブルへの書き込みが待たされることがあるため、アクセスの少ない時間に行います。
スパム登録ユーザーを削除する
ユーザー登録を受け付けていると、スパムのアカウントが大量にできることがあります。ユーザーを SQL で消すと wp_usermeta が残るため、WP-CLI で削除します。
まず一覧を CSV に書き出して確認します。
wp user list --role=subscriber --fields=ID,user_login,user_email,user_registered --format=csv > subscribers.csv
不要と判断した ID を削除します(例の ID は置き換えてください)。
wp user delete 123 124 125 --yes
--reassign を付けずに削除すると、そのユーザーの投稿も削除されます。購読者は通常投稿を持ちませんが、投稿者などの権限を持つユーザーを消すときは --reassign=<残すユーザーのID> で投稿を引き継がせます。
一定日数より前に登録した購読者をまとめて消す場合は、たとえば次のように ID を集めます。会員サイトなど正規の購読者がいるサイトでは使わないでください。
wp db query "SELECT u.ID FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID AND m.meta_key = 'wp_capabilities'
WHERE m.meta_value LIKE '%\"subscriber\"%'
AND u.user_registered < DATE_SUB(NOW(), INTERVAL 90 DAY);" --skip-column-names
出力された ID を確認してから wp user delete に渡します。wp_capabilities の wp_ もテーブル接頭辞に合わせて読み替えます。
再発を防ぐ
- Akismet: Akismet はスパムと判定したコメントを毎日の定期処理で掃除し、15日より古いスパムを削除します(Akismet のソース
class.akismet.phpのakismet_delete_comment_intervalフィルター、既定 15)。Akismet を有効にしていれば、スパムが際限なくたまることはありません。 - ゴミ箱: ゴミ箱のコメントは、WordPress 本体の定期処理が
EMPTY_TRASH_DAYS(既定30日)を過ぎたものを削除します。 - ユーザー登録: 会員登録を使わないなら、「設定」→「一般」の「だれでもユーザー登録ができるようにする」のチェックを外します。
- コメントを使わない: 「設定」→「ディスカッション」で「新しい投稿へのコメントを許可する」を外すと、以後の新しい投稿ではコメントを受け付けません。既存の投稿は投稿ごとの設定が残るため、必要なら一括編集で変更します。
Akismetを使わない場合の自動削除
Akismet 以外のスパム対策を使っていて、スパムに分類されたコメントが残り続ける場合は、WP-Cron で古いスパムを定期的に消せます。wp-content/mu-plugins/spam-cleanup.php として置く例です。
<?php
/**
* Plugin Name: Spam Cleanup
* Description: 30日より古いスパムコメントを毎日削除する。
*/
add_action( 'init', function (): void {
if ( ! wp_next_scheduled( 'myplugin_spam_cleanup' ) ) {
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'myplugin_spam_cleanup' );
}
} );
add_action( 'myplugin_spam_cleanup', function (): void {
$ids = get_comments( array(
'status' => 'spam',
'date_query' => array( array( 'before' => '30 days ago' ) ),
'number' => 500,
'fields' => 'ids',
) );
foreach ( $ids as $id ) {
wp_delete_comment( $id, true );
}
} );
1回の処理を500件に抑えているのは、アクセス時に動く WP-Cron が長時間かからないようにするためです。登録された予定は wp cron event list で確認できます。
まとめ
- 先に
wp db exportでバックアップを取り、wp comment countで件数を確かめる。 - 少量なら管理画面の「スパムをすべて削除」、多ければ WP-CLI で1,000件ずつ削除する。
- SQL で直接消した場合は、孤立した
wp_commentmetaも削除し、必要ならOPTIMIZE TABLEで領域を返す。 - スパムユーザーは
wp_usermetaが残らないようwp user deleteで消す。 - Akismet の自動削除、ユーザー登録の停止で再発を抑える。
WP-CLI でのユーザー操作は WP-CLIのuserコマンドの使い方 も参照してください。