2026年7月11日

2026年7月11日

WordPressのwp_cronで定期処理を実装する方法

はじめに

「毎日深夜に古い一時データを削除したい」「1時間ごとに外部APIからデータを取得して更新したい」「定期的にサイトマップを再生成したい」——wp_cronを使えばWordPressで定期的なバックグラウンド処理を実装できます。

症状・原因

WordPressのwp_cronはリクエストベースで動作するため、サイトへのアクセスがないと発火しません。アクセスの少ないサイトではサーバーの実cronと組み合わせると確実に実行できます。また重複登録を防がないと、同じジョブが複数スケジュールされる問題が発生します。

解決手順

ステップ1:cronイベントを登録する

// functions.php: cronイベントをactivation時に登録
register_activation_hook( __FILE__, 'my_cron_activation' );

function my_cron_activation() {
    if ( ! wp_next_scheduled( 'my_daily_cleanup' ) ) {
        wp_schedule_event( time(), 'daily', 'my_daily_cleanup' );
    }
}

// プラグイン無効化時にcronを削除
register_deactivation_hook( __FILE__, 'my_cron_deactivation' );

function my_cron_deactivation() {
    $timestamp = wp_next_scheduled( 'my_daily_cleanup' );
    if ( $timestamp ) {
        wp_unschedule_event( $timestamp, 'my_daily_cleanup' );
    }
}

// テーマのfunctions.phpで使う場合(activation hookが使えないため)
add_action( 'init', function() {
    if ( ! wp_next_scheduled( 'my_daily_cleanup' ) ) {
        wp_schedule_event( time(), 'daily', 'my_daily_cleanup' );
    }
} );

ステップ2:カスタムスケジュール間隔を追加する

// functions.php: WordPressのデフォルトにないスケジュール間隔を追加
add_filter( 'cron_schedules', function( $schedules ) {

    // 5分ごと
    $schedules['every_5_minutes'] = [
        'interval' => 5 * MINUTE_IN_SECONDS,
        'display'  => '5分ごと',
    ];

    // 30分ごと
    $schedules['every_30_minutes'] = [
        'interval' => 30 * MINUTE_IN_SECONDS,
        'display'  => '30分ごと',
    ];

    // 週2回(月・木)はwp_cronの制限で正確には実装できないため
    // 毎週でスケジュールして関数内で曜日チェック

    return $schedules;
} );

// カスタム間隔でイベントを登録
add_action( 'init', function() {
    if ( ! wp_next_scheduled( 'my_api_fetch' ) ) {
        wp_schedule_event( time(), 'every_30_minutes', 'my_api_fetch' );
    }
} );

ステップ3:cronフックに処理を実装する

// functions.php: 日次クリーンアップ処理
add_action( 'my_daily_cleanup', function() {
    global $wpdb;

    // 30日以上前の自動下書きを削除
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM {$wpdb->posts}
             WHERE post_status = 'auto-draft'
               AND post_modified < %s",
            gmdate( 'Y-m-d H:i:s', strtotime( '-30 days' ) )
        )
    );

    // 期限切れトランジェントを削除
    delete_expired_transients();

    error_log( '[my_cron] daily_cleanup 実行完了: ' . gmdate( 'Y-m-d H:i:s' ) );
} );

// 外部APIからデータを取得してキャッシュに保存
add_action( 'my_api_fetch', function() {
    $cache_key = 'my_api_data';

    // APIリクエスト
    $response = wp_remote_get( 'https://api.example.com/data', [
        'timeout' => 15,
        'headers' => [
            'Authorization' => 'Bearer ' . get_option( 'my_api_key' ),
        ],
    ] );

    if ( is_wp_error( $response ) ) {
        error_log( '[my_cron] API取得エラー: ' . $response->get_error_message() );
        return;
    }

    $code = wp_remote_retrieve_response_code( $response );
    if ( 200 !== $code ) {
        error_log( '[my_cron] API HTTPエラー: ' . $code );
        return;
    }

    $body = json_decode( wp_remote_retrieve_body( $response ), true );
    if ( $body ) {
        set_transient( $cache_key, $body, HOUR_IN_SECONDS );
        error_log( '[my_cron] API取得完了: ' . gmdate( 'Y-m-d H:i:s' ) );
    }
} );

ステップ4:サーバーcronと連携して確実に実行する

# /etc/cron.d/wordpress または crontab -e で設定
# DISABLE_WP_CRON を有効にしてサーバーcronで呼び出す

# 毎分WordPressのcronを実行(wp-cliを使用)
* * * * * www-data /usr/local/bin/wp cron event run --due-now --path=/var/www/html --quiet

# または wgetで直接叩く(wp-cliがない場合)
* * * * * www-data wget -q -O /dev/null https://example.com/wp-cron.php?doing_wp_cron

# wp-config.phpでWordPress側のcronを無効化
# define( 'DISABLE_WP_CRON', true );
// wp-config.php: サーバーcronを使う場合はWordPressの自動cronを無効化
define( 'DISABLE_WP_CRON', true );
// これによりページ読み込み時にcronが自動実行されなくなり、
// サーバーのcrontabからのみ実行されるようになる

ステップ5:WP-CLIとログでcronをデバッグする

# 登録済みcronイベントの一覧表示
wp cron event list

# 特定のcronイベントを今すぐ実行(テスト用)
wp cron event run my_daily_cleanup

# 期限が来ているすべてのcronを実行
wp cron event run --due-now

# cronスケジュールの一覧表示
wp cron schedule list

# cronイベントを手動で削除
wp cron event delete my_api_fetch

# wp-config.phpのDISABLE_WP_CRONがtrueかチェック
wp config get DISABLE_WP_CRON
// functions.php: cronの実行ログをWordPressのdebug.logに出力
add_action( 'my_daily_cleanup', function() {
    if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
        error_log( sprintf(
            '[my_cron] %s を実行 - メモリ使用量: %s',
            current_action(),
            size_format( memory_get_usage() )
        ) );
    }
    // 処理内容...
} );

注意事項

  • wp_schedule_event()の第1引数のタイムスタンプはUTCのunixtimeです。time()はサーバーのタイムゾーン設定に依存するため、WordPress側ではtime()current_time('timestamp', true)(UTC)を使ってください。
  • wp_cronはページアクセス時に発火するため、アクセスのないサイトでは遅延が発生します。重要な定期処理にはサーバーcronとDISABLE_WP_CRONの組み合わせを使ってください。
  • initフックでwp_next_scheduled()を確認せずにwp_schedule_event()を呼ぶと、ページリクエストのたびに重複登録されます。必ず登録済みか確認してから実行してください。

まとめ

wp_cronの実装は「cron_schedulesでカスタム間隔を追加→wp_next_scheduled()で重複確認後wp_schedule_event()でイベント登録→add_action()でフックに処理を実装→wp-config.phpでDISABLE_WP_CRON=trueにしてサーバーcronと連携→WP-CLIでデバッグ」の流れで整備します。関連記事:WordPressのトランジェントAPIでキャッシュを実装する方法WordPressのショートコードを作成する方法

お気軽にご相談ください

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