2026年7月7日
2026年7月7日
WordPressでwp-cron.phpが無限ループのように繰り返し実行される問題の診断と解決
アクセスログに wp-cron.php?doing_wp_cron=… が途切れなく並び、CPU使用率が下がらない場合、WP-Cronの予定(イベント)がいつまでも「実行待ち」のまま残り、ページが表示されるたびに処理が起動し直している状態が考えられます。この記事では、WP-Cronが繰り返し起動する仕組みを押さえたうえで、原因のイベントを特定する方法と、実行を止めて正常に戻す手順を説明します。
WP-Cronが「無限ループ」に見える仕組み
WP-CronはOSのcronとは違い、サイトへのアクセスをきっかけに動きます。ページが読み込まれると、WordPressは予定時刻を過ぎたイベントがあるかを確認し、あれば自分自身の wp-cron.php へ非同期のリクエストを送ってイベントを実行させます。
二重起動を防ぐため、実行中は doing_cron という一時データ(トランジェント)がロックとして保存されます。このロックの有効時間は定数 WP_CRON_LOCK_TIMEOUT で決まり、既定値は60秒です。ここから、繰り返し実行が起きる典型的な流れが見えてきます。
- イベントの処理が60秒を超える:ロックの期限が切れ、次のアクセスで新しい
wp-cron.phpが起動する。前の処理が終わる前に次が始まり、同じ処理が重なって走る - 実行後に予定が更新されない:イベントを実行しても、次回の予定を保存する処理が失敗すると、そのイベントは「予定時刻を過ぎたまま」残る。するとアクセスのたびに再実行される
- イベント自体が増え続ける:プラグインが同じイベントを毎回登録し直すと、予定が際限なく増え、いつまでも処理が終わらない
つまり「無限ループ」の多くは、プログラムが文字どおりループしているのではなく、終わらない・片付かないイベントが、アクセスのたびに起動され直している状態です。
症状を確認する
まずは本当にWP-Cronが繰り返し起動しているのかを確かめます。サーバーのアクセスログで wp-cron.php へのリクエスト数を数えると、状況がつかめます。ログの場所はサーバーによって異なります。
# 直近のアクセスログから wp-cron.php へのリクエスト数を数える(ログのパスは環境に合わせて変更)
grep -c "wp-cron.php" /var/log/nginx/access.log
# 1分あたりの件数を見る
grep "wp-cron.php" /var/log/nginx/access.log | awk '{print $4}' | cut -c2-18 | sort | uniq -c | tail -20
通常、WP-Cronの起動は1分に1回程度までに抑えられます。1分間に何十回も記録されている、またはPHPのプロセスが wp-cron.php で長時間動き続けている場合は、以下の手順で原因を探します。
原因のイベントを特定する
WP-CLIで予定の一覧を見る
WP-CLIが使えるなら、登録されているイベントと次回の実行予定を一覧できます。
wp cron event list --fields=hook,next_run_relative,recurrence --format=table
確認したいのは次の3点です。
- 「now」や過去の時刻のまま残っているイベントが多数ないか
- 同じフック名のイベントが何十件、何百件と重複していないか
- 見覚えのないフック名がないか(削除済みプラグインの名残であることが多い)
あわせて、WP-Cron自体が動く環境かどうかも確かめておきます。wp cron test は、WordPressが自分自身の wp-cron.php にリクエストを送れるかを検査します。
wp cron test
管理画面で確認する
WP-CLIが使えない場合は、「WP Crontrol」プラグインを使うと、管理画面の「ツール」メニューからイベントの一覧、次回の実行時刻、登録元のフックを確認できます。予定時刻を過ぎたままのイベントや、処理を担当する関数が見つからないイベントも見分けやすくなっています。
「ツール」→「サイトヘルス」でも、予定されたイベントの実行が遅れている場合に指摘が表示されます。ループの直接の原因までは分かりませんが、WP-Cronに異常があるかの目安になります。
デバッグログで処理の失敗を見る
イベントの処理中にPHPのエラーが起きていると、処理が途中で止まり、毎回やり直しになります。wp-config.php を編集する前にコピーを保存し、デバッグログを有効にします。
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
wp-content/debug.log に、特定のプラグインのファイルで「Maximum execution time」や「Allowed memory size」のエラーが繰り返し出ていれば、そのプラグインのイベントが時間切れ・メモリ不足で終わらずにいる可能性が高くなります。
よくある原因と対処
予定の保存に失敗している
WP-Cronの予定は、wp_options テーブル(接頭辞はサイトにより異なります)の cron というオプションにまとめて保存されています。重複したイベントが溜まってこの値が大きくなりすぎたり、データベースへの書き込みが失敗したりすると、実行後の予定更新が反映されません。
# cron オプションのおおよそのサイズを確認
wp option get cron --format=json | wc -c
Redisなどの永続オブジェクトキャッシュを使っている場合は、キャッシュに古い予定が残り、データベースの内容と食い違っていることもあります。その場合は wp cache flush でオブジェクトキャッシュを消去すると改善することがあります。
重複したイベントや不要なイベントが残っている
同じフック名のイベントが大量に並んでいたら、そのフックの予定を削除します。削除前にデータベースのバックアップを取ってください。
wp db export before-cron-cleanup.sql
# 指定したフックの予定をすべて削除(my_plugin_sync は例)
wp cron event delete my_plugin_sync
削除しても、原因のプラグインが有効なままなら、次のアクセスで再び登録されることがあります。削除後に再び増えるかを観察し、増えるならそのプラグインの更新、設定の見直し、または停止を検討します。
自作のコードでイベントを登録している場合は、すでに予定があるかを確認してから登録する形になっているかを見直します。毎回 wp_schedule_event() を呼ぶだけのコードは、重複の原因になります。
add_action( 'init', function () {
if ( ! wp_next_scheduled( 'my_plugin_sync' ) ) {
wp_schedule_event( time(), 'hourly', 'my_plugin_sync' );
}
} );
重い処理がロックの時間を超えている
外部APIとの同期や大量の画像処理など、1回の処理に時間がかかるイベントは、60秒のロックを超えて重複実行の原因になります。根本的には処理を小分けにするのが望ましいですが、応急処置として WP_CRON_LOCK_TIMEOUT を延ばす方法があります。
// wp-config.php に記述(秒単位。ここでは5分)
define( 'WP_CRON_LOCK_TIMEOUT', 300 );
WooCommerceなどが使う「Action Scheduler」は、WP-Cronを入り口にして独自のキューを処理します。未処理のアクションが大量に溜まっている場合は、管理画面の予定されたアクションの一覧で、失敗を繰り返しているアクションがないかを確認してください。
ALTERNATE_WP_CRON とキャッシュの組み合わせ
wp-config.php に ALTERNATE_WP_CRON を設定していると、WP-Cronはリダイレクトを使う方式で動きます。この方式はページキャッシュやCDNとの相性が悪く、doing_wp_cron 付きのURLへのリダイレクトが繰り返されることがあります。サーバーの都合でこの設定を入れていた場合は、次に紹介するサーバーのcronへの切り替えを検討してください。
WP-Cronをサーバーのcronに切り替える
アクセスのたびに起動する仕組みそのものが負荷の原因になっている場合は、アクセス連動の起動を止め、サーバーのcronから決まった間隔で実行する方式に切り替えます。まず wp-config.php に次の1行を追加します。
define( 'DISABLE_WP_CRON', true );
そのうえで、サーバーのcron(クーロン)に、5分おきなど一定間隔でイベントを実行する設定を登録します。WP-CLIが使えるなら、予定時刻を過ぎたイベントだけを実行する次の形が扱いやすくなります(パスは環境に合わせて変更します)。
*/5 * * * * cd /var/www/example.com/public && wp cron event run --due-now > /dev/null 2>&1
DISABLE_WP_CRON を設定したままサーバー側のcronを登録し忘れると、予約投稿やバックアップなど、WP-Cronに頼っている処理がすべて止まります。切り替え後は wp cron event list で予定が進んでいるかを確認してください。
まとめ
wp-cron.php が繰り返し実行される問題は、次の流れで切り分けると原因にたどり着きやすくなります(2026年10月現在のWordPressとWP-CLIの仕様に基づいています)。
- アクセスログで
wp-cron.phpへのリクエスト頻度を数え、異常かどうかを確かめる wp cron event listやWP Crontrolで、過去の時刻のまま残るイベントや重複したイベントを探すdebug.logで、処理が時間切れやメモリ不足で止まっていないかを確認する- バックアップを取ってから不要なイベントを削除し、重複登録するコードやプラグインを直す
- 重い処理には
WP_CRON_LOCK_TIMEOUTの調整や処理の分割で対応する - 根本対策として
DISABLE_WP_CRONとサーバーのcronを組み合わせる