spawn_cron():wp-cron.php へ接続を送って、予定を動かす(WordPress)

WordPress

spawn_cron() は、WP-Cron の予定を動かすために、サイトから自分の wp-cron.php へ接続を送る関数です。ページが開かれたときに WordPress が呼びます。接続は待たずに切るので、ページを開いた人は、予定の処理が終わるのを待たされません。自分で呼ぶことは少なく、送る接続の中身を変えたいとき(cron_request フィルター)や、予定が動かない原因を探すときに、中の動きを知っておくと役に立ちます。

書き方

spawn_cron( int $gmt_time = 0 ): bool
  • $gmt_time:基準にする UNIX 時刻(世界標準時)。省くと今の時刻
  • 戻り値:接続を送れたら true。送らなかったとき・送るのに失敗したときは false

関数の中でしていること

  1. wp-cron.php の中から呼ばれたとき(DOING_CRON がある・URL に doing_wp_cron がある)は、何もしない
  2. doing_cron という一時データ(トランジェント)に、前に送った時刻が入っていて、60 秒(WP_CRON_LOCK_TIMEOUT)たっていなければ、何もしない
  3. 時刻を過ぎた予定が 1 つもなければ、何もしない
  4. doing_cron に今の時刻を保存してから、wp-cron.php?doing_wp_cron=時刻 へ POST で接続を送る。待ち時間は 0.01 秒で、返事は待たない

wp-config.php で ALTERNATE_WP_CRON を true にしているときは、接続を送るかわりに、開いた人をリダイレクトして、同じ処理の中で wp-cron.php を読み込みます。

使い方の例

作業環境(WordPress 7.1.3)で試した結果を、コメントに書いています。wp-cron.php への接続は、pre_http_request フィルターで止めて、送ろうとした中身だけを見ました。試したあと、doing_cron は元に戻しています。

呼んだときに何が送られるかを見る

<?php
var_dump( spawn_cron() ); // bool(true)
// 送ろうとした接続(作業環境の値)
// URL:http://functions.local/wp-cron.php?doing_wp_cron=1793937999.4084339141845703125000
// method:POST・timeout:0.01・blocking:false・sslverify:false

// すぐにもう一度呼ぶと、60 秒たっていないので送らない
var_dump( spawn_cron() ); // bool(false)

接続が失敗したとき(作業環境では、pre_http_request で WP_Error を返して試した)も、false が返りました。

ベーシック認証のかかったサイトで、wp-cron.php への接続に ID とパスワードを付ける

サイト全体にベーシック認証をかけていると、サイトから自分への接続も認証で止まり、予定が動きません。cron_request フィルターで、送る接続にヘッダーを足せます。

functions.php
<?php
// wp-cron.php への接続に、ベーシック認証の ID とパスワードを付ける
// MY_BASIC_AUTH_USER・MY_BASIC_AUTH_PASS は wp-config.php で define しておく
add_filter( 'cron_request', 'my_cron_request_basic_auth' );
function my_cron_request_basic_auth( $cron_request ) {
	if ( ! defined( 'MY_BASIC_AUTH_USER' ) || ! defined( 'MY_BASIC_AUTH_PASS' ) ) {
		return $cron_request;
	}
	$cron_request['args']['headers']['Authorization'] = 'Basic ' . base64_encode( MY_BASIC_AUTH_USER . ':' . MY_BASIC_AUTH_PASS );
	return $cron_request;
}

作業環境で、この形のフィルターを付けて spawn_cron() を呼ぶと、送ろうとした接続に Authorization のヘッダーが付いていました。

気をつけること

  • spawn_cron() は DISABLE_WP_CRON を見ません。ページの読み込みで WP-Cron を止める定数は、spawn_cron() を呼ぶ側(_wp_cron())が見ています。作業環境(DISABLE_WP_CRON が true)でも、spawn_cron() を直接呼ぶと接続を送ろうとし、_wp_cron() は 0 を返して何もしませんでした。
  • 接続はサイトから自分自身へ送ります。ベーシック認証・IP で絞るアクセスの制限・セキュリティのプラグインやサーバーの WAF が wp-cron.php を止めていると、true が返っても予定は動きません。true は「送った」という意味で、wp-cron.php が動いたかまでは分かりません。
  • 返事を待たない作りなので、wp-cron.php 側のエラーは、ここでは見えません。「ツール」→「サイトヘルス」のループバックリクエストの項目で確認します。
  • sslverify は false が既定です(https_local_ssl_verify フィルターで変えられる)。自分への接続では、証明書をチェックしないで送ります。
  • WordPress 6.9 から、ページの読み込みで WP-Cron を動かすのは、ページを送り終えたあと(shutdown のタイミング)になりました。ALTERNATE_WP_CRON のときは、前と同じく wp_loaded のタイミングです。
  • アクセスに関係なく決まった間隔で予定を動かしたいなら、サーバーの cron から wp-cron.php を呼び、wp-config.php で DISABLE_WP_CRON を true にします。

関係する関数

逆引きリファレンスの一覧へ