2026年5月19日
2026年5月19日
WordPress WP-Cronが動作しない問題を解決する方法
はじめに
WordPressで定期的に実行するはずのバックアップ・メール送信・キャッシュ更新がいつまでも実行されない・wp_schedule_event()でスケジュール登録したのに一度も動いていない・DISABLE_WP_CRONを設定してサーバーのcrontabも設定したが両方動いていない・同じcronイベントが何百件も重複登録されてテーブルが肥大化しているといった問題は、WP-Cronの仕組みとサイトへのトラフィック量・フック名の重複・イベントのアンスケジュール漏れが原因です。
症状・原因
- サイトへのアクセスが少ないためWP-Cronがトリガーされない(WP-Cronはページ読み込み時に起動する)
wp_schedule_event()の第1引数($timestamp)に過去の時刻やfalseを渡している- プラグインの
deactivation_hookでcronイベントをwp_clear_scheduled_hook()で削除していない DISABLE_WP_CRON=trueにしたがサーバーcronのwp-cron.phpのURLが間違っている
解決手順
ステップ1:WP-Cronの状態を診断する
# スケジュール済みイベント一覧
wp cron event list --fields=hook,next_run_relative,recurrence
# 特定フックの次回実行時刻
wp cron event list --fields=hook,next_run_gmt | grep "my_custom_hook"
# cronイベントの手動実行
wp cron event run my_custom_hook
# cronスケジュール(繰り返し間隔)一覧
wp cron schedule list
# optionに保存されているcronデータを確認
wp option get cron --format=json | python -m json.tool | head -50
ステップ2:WP-Cronイベントを正しく登録する
// プラグインの activation_hook でイベントを登録
register_activation_hook(__FILE__, function(): void {
// 既に登録されているか確認してから登録(重複防止)
if (! wp_next_scheduled('my_daily_task')) {
wp_schedule_event(
time(), // 次回実行時刻(現在時刻)
'daily', // 繰り返し間隔
'my_daily_task' // フック名
);
}
});
// deactivation_hook で必ずイベントを削除
register_deactivation_hook(__FILE__, function(): void {
$timestamp = wp_next_scheduled('my_daily_task');
if ($timestamp) {
wp_unschedule_event($timestamp, 'my_daily_task');
}
// または全ての同名イベントを一括削除
wp_clear_scheduled_hook('my_daily_task');
});
// cronフックに処理を紐付け
add_action('my_daily_task', function(): void {
// ここに実行したい処理を記述
error_log('Daily task executed at ' . current_time('mysql'));
});
ステップ3:カスタムcron間隔を追加する
// デフォルトにない間隔を追加(例:5分ごと・週1回)
add_filter('cron_schedules', function(array $schedules): array {
$schedules['every_five_minutes'] = [
'interval' => 5 * MINUTE_IN_SECONDS, // 300秒
'display' => '5分ごと',
];
$schedules['weekly'] = [
'interval' => WEEK_IN_SECONDS, // 604800秒
'display' => '週1回',
];
return $schedules;
});
// 登録時に使用
if (! wp_next_scheduled('my_five_min_task')) {
wp_schedule_event(time(), 'every_five_minutes', 'my_five_min_task');
}
ステップ4:DISABLE_WP_CRONとサーバーcronを設定する
// wp-config.php: WordPress側のcronを無効化
define('DISABLE_WP_CRON', true);
define('WP_CRON_LOCK_TIMEOUT', 120); // ロックタイムアウト(秒)
# サーバーのcrontabを設定(毎分実行)
crontab -e
# 以下を追加(PHPのパスは環境に合わせる)
* * * * * php /var/www/html/wp-cron.php > /dev/null 2>&1
# wp-cli を使う方法(推奨)
* * * * * cd /var/www/html && wp cron event run --due-now >> /var/log/wp-cron.log 2>&1
# 動作確認
wp cron event run --due-now
ステップ5:重複登録されたcronイベントをクリーンアップする
// 重複したcronイベントを検出・削除する
function cleanup_duplicate_cron_events(string $hook_name): int {
$crons = _get_cron_array();
$removed = 0;
$found_one = false;
foreach ($crons as $timestamp => $cron) {
if (isset($cron[$hook_name])) {
if ($found_one) {
// 2件目以降を削除
unset($crons[$timestamp][$hook_name]);
$removed++;
} else {
$found_one = true;
}
}
}
if ($removed > 0) {
_set_cron_array($crons);
}
return $removed;
}
# cronオプションを直接リセット(最終手段)
wp option delete cron
# → 次回ページ読み込み時にWordPressが再構築する
注意事項
- WP-Cronはページ読み込み時に起動するため、アクセスが少ないサイトでは予定時刻より大幅に遅れて実行されます。正確な時刻に実行したい場合はサーバーcronと組み合わせてください
wp_schedule_event()はプラグイン有効化時に1回だけ呼ぶ設計です。毎回のページ読み込みで呼ぶと重複登録が蓄積します- サーバーcronでwp-cron.phpを直接curlで叩く方法もありますが、HTTP認証がある環境では失敗します。
wp cron event run --due-nowの方が確実です
まとめ
WordPress WP-Cron不動作の解決は①wp cron event listでスケジュール済みイベントを確認・wp cron event runで手動実行テスト・wp option get cronでcronデータを直接確認、②activation_hookでwp_next_scheduled()チェック後にwp_schedule_event()登録・deactivation_hookでwp_clear_scheduled_hook()を必ず呼ぶ・add_action()でフック名に処理を紐付け、③cron_schedulesフィルターで5分ごと・週1回などのカスタム間隔を追加・MINUTE_IN_SECONDS等の定数を使用、④DISABLE_WP_CRON=trueでWordPress側cronを無効化・crontabにwp cron event run --due-nowを毎分登録・ログファイルで実行を確認、⑤重複イベントは_get_cron_array()で検出して_set_cron_array()で修正・最終手段はwp option delete cronでリセットの手順で解決します。