2026年5月19日
2026年5月19日
WordPressのWP-Cronエラーを解決する方法
はじめに
WordPressでwp_schedule_event()でスケジュールを登録したのにタスクが実行されない・wp_next_scheduled()がfalseを返してスケジュールが登録されているはずなのに次回実行時刻が取得できない・プラグインを再有効化するたびにCronイベントが重複登録される・アクセスが少ないサイトでWP-Cronがほとんど動作しないといった問題は、WordPressのWP-Cronシステムの仕組みを理解することで解決できます。
症状・原因
wp_schedule_event()で登録したフックアクションがadd_action()でリスナー関数に紐付けられていないwp_next_scheduled()で引数($args)を渡す場合、登録時と同じ配列を渡さないと別のイベントとして扱われる- プラグイン有効化時に重複チェックなしで
wp_schedule_event()を呼んでいるため、同一イベントが複数登録される DISABLE_WP_CRON = trueがwp-config.phpで設定されており、WP-Cronが無効化されている
解決手順
ステップ1:WP-Cronの状態を診断する
# 登録済みCronイベントを確認
wp cron event list
# 次回実行予定を確認
wp cron event list --fields=hook,next_run_relative,schedule
# 特定のイベントが登録されているか確認
wp eval "var_dump(wp_next_scheduled('my_plugin_cron_hook'));"
# Cronを手動で実行(テスト)
wp cron event run my_plugin_cron_hook
# WP-Cronが有効か確認
wp eval "echo defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ? '無効' : '有効';"
# 重複したCronイベントを確認
wp eval "print_r(_get_cron_array());"
ステップ2:WP-Cronを正しく実装する
// ✅ プラグイン有効化時にCronを登録(重複チェック必須)
register_activation_hook(__FILE__, 'my_plugin_activate_cron');
function my_plugin_activate_cron(): void {
// ✅ wp_next_scheduled で重複チェックしてから登録
if (!wp_next_scheduled('my_plugin_hourly_hook')) {
wp_schedule_event(
time(), // 最初の実行時刻(Unix タイムスタンプ)
'hourly', // スケジュール: hourly, twicedaily, daily, weekly
'my_plugin_hourly_hook' // フックアクション名
);
}
}
// ✅ プラグイン無効化時にCronを削除
register_deactivation_hook(__FILE__, 'my_plugin_deactivate_cron');
function my_plugin_deactivate_cron(): void {
$timestamp = wp_next_scheduled('my_plugin_hourly_hook');
if ($timestamp) {
wp_unschedule_event($timestamp, 'my_plugin_hourly_hook');
}
// または全スケジュールを一括削除
wp_clear_scheduled_hook('my_plugin_hourly_hook');
}
// ✅ Cronフックにコールバックを登録(必ず add_action で紐付ける)
add_action('my_plugin_hourly_hook', 'my_plugin_do_hourly_task');
function my_plugin_do_hourly_task(): void {
// ✅ タスク実行中のロック(重複実行防止)
if (get_transient('my_plugin_cron_running')) {
return;
}
set_transient('my_plugin_cron_running', true, 5 * MINUTE_IN_SECONDS);
try {
// タスクの処理
my_plugin_process_queue();
} finally {
delete_transient('my_plugin_cron_running');
}
}
ステップ3:カスタムスケジュール間隔を追加する
// ✅ カスタムスケジュール間隔を追加
add_filter('cron_schedules', function(array $schedules): array {
// 5分ごと
$schedules['every_five_minutes'] = [
'interval' => 5 * MINUTE_IN_SECONDS,
'display' => '5分ごと',
];
// 週2回
$schedules['twice_weekly'] = [
'interval' => 3.5 * DAY_IN_SECONDS,
'display' => '週2回',
];
// 月1回
$schedules['monthly'] = [
'interval' => 30 * DAY_IN_SECONDS,
'display' => '月1回',
];
return $schedules;
});
// ✅ カスタム間隔を使ってスケジュール登録
if (!wp_next_scheduled('my_plugin_five_min_hook')) {
wp_schedule_event(time(), 'every_five_minutes', 'my_plugin_five_min_hook');
}
// ✅ 引数付きのCronイベント
function my_plugin_schedule_with_args(int $user_id): void {
$args = [$user_id]; // 引数は配列で渡す
// ✅ 登録と取得で同じ $args を渡す
if (!wp_next_scheduled('my_plugin_user_hook', $args)) {
wp_schedule_single_event(
time() + HOUR_IN_SECONDS,
'my_plugin_user_hook',
$args
);
}
}
add_action('my_plugin_user_hook', function(int $user_id): void {
// $user_id を使って処理
update_user_meta($user_id, 'last_cron_processed', time());
}, 10, 1);
ステップ4:WP-Cronの信頼性を向上させる
// ✅ wp-config.php の設定を確認
// define('DISABLE_WP_CRON', false); // WP-Cronを有効化
// define('WP_CRON_LOCK_TIMEOUT', 120); // ロックタイムアウトを延長(デフォルト60秒)
// ✅ アクセスが少ないサイトはサーバーのcronで実行
// crontab に追加:
// */5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
// または WP-CLI を使用:
// */5 * * * * cd /var/www/html && wp cron event run --due-now --quiet
// ✅ WP-Cronの実行をログに記録
add_action('my_plugin_hourly_hook', function(): void {
error_log(sprintf(
'[%s] my_plugin_hourly_hook started (memory: %s)',
date('Y-m-d H:i:s'),
size_format(memory_get_usage())
));
}, 1);
// ✅ Cronの実行状況を管理画面で確認できるようにする
add_action('admin_notices', function(): void {
if (!current_user_can('manage_options')) {
return;
}
$next = wp_next_scheduled('my_plugin_hourly_hook');
if (!$next) {
echo '<div class="notice notice-error"><p>';
echo 'WP-Cron: my_plugin_hourly_hook が登録されていません。';
echo '</p></div>';
} elseif ($next < time() - HOUR_IN_SECONDS) {
echo '<div class="notice notice-warning"><p>';
printf('WP-Cron: my_plugin_hourly_hook の次回実行が %d 分遅延しています。', (time() - $next) / 60);
echo '</p></div>';
}
});
ステップ5:Cronジョブのバッチ処理
// ✅ 大量データをバッチ処理する
function my_plugin_process_queue(): void {
$batch_size = 50;
$offset = (int) get_option('my_plugin_cron_offset', 0);
$items = get_posts([
'post_type' => 'my_post_type',
'post_status' => 'publish',
'posts_per_page' => $batch_size,
'offset' => $offset,
'fields' => 'ids',
'no_found_rows' => true,
]);
if (empty($items)) {
// 全処理完了:オフセットをリセット
update_option('my_plugin_cron_offset', 0);
return;
}
foreach ($items as $post_id) {
// 各アイテムを処理
update_post_meta($post_id, '_processed_at', time());
}
// 次のバッチのためにオフセットを更新
update_option('my_plugin_cron_offset', $offset + $batch_size);
// ✅ 次のバッチをすぐに実行(まだ残っている場合)
if (count($items) === $batch_size) {
wp_schedule_single_event(time() + 30, 'my_plugin_hourly_hook');
}
}
注意事項
- WP-Cronはサイトへのアクセス時にのみ実行されます。アクセス数が少ないサイトでは、設定した間隔通りに実行されないことがあります。本番環境では
DISABLE_WP_CRON = trueを設定してサーバーのcron(crontab)からWP-CLIで実行する方法を推奨します wp_schedule_event()を呼ぶ際は必ず事前にwp_next_scheduled()で重複チェックしてください。プラグインを更新するたびに有効化フックが実行される環境では、チェックなしで登録するとCronイベントが無限に重複します
まとめ
WordPressのWP-Cronエラーの解決は①wp cron event listで登録確認・wp cron event runで手動テスト・DISABLE_WP_CRON設定確認・_get_cron_array()で重複確認、②有効化フックでwp_next_scheduled()チェック後にwp_schedule_event()・無効化フックでwp_clear_scheduled_hook()・add_action(フック名, コールバック)で必ず紐付ける、③cron_schedulesフィルターでカスタム間隔追加・引数付きイベントは登録と取得で同じ$args配列、④アクセスが少ないサイトはサーバーcron+WP-CLIで確実に実行・WP_CRON_LOCK_TIMEOUTを延長・admin_noticesで遅延を検知、⑤大量データはバッチ分割してget_optionでオフセット管理・Transientでロックして重複実行を防止の手順で解決します。