spawn_cron() は、WP-Cron の予定を動かすために、サイトから自分の wp-cron.php へ接続を送る関数です。ページが開かれたときに WordPress が呼びます。接続は待たずに切るので、ページを開いた人は、予定の処理が終わるのを待たされません。自分で呼ぶことは少なく、送る接続の中身を変えたいとき(cron_request フィルター)や、予定が動かない原因を探すときに、中の動きを知っておくと役に立ちます。
書き方
spawn_cron( int $gmt_time = 0 ): bool
$gmt_time:基準にする UNIX 時刻(世界標準時)。省くと今の時刻- 戻り値:接続を送れたら true。送らなかったとき・送るのに失敗したときは false
関数の中でしていること
- wp-cron.php の中から呼ばれたとき(
DOING_CRONがある・URL にdoing_wp_cronがある)は、何もしない doing_cronという一時データ(トランジェント)に、前に送った時刻が入っていて、60 秒(WP_CRON_LOCK_TIMEOUT)たっていなければ、何もしない- 時刻を過ぎた予定が 1 つもなければ、何もしない
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 にします。
