「決まった時刻にメールを送りたい」——WordPressでサイトを運用していると、いつか必ず出てくる願いです。
たとえばこんな場面。
- 会員向けに「明日のイベントのリマインド」を自動送信したい
- 申し込みから数日後にフォローメールを送って、離脱を減らしたい
- 毎週決まった曜日に、レポートを担当者へ送信したい
私も同じことを考えて、WordPress側でスケジュールを組み、メール送信処理を登録しました。準備は完璧……のはずでした。
ところが、深夜〜早朝だけメールが送られない。管理画面上は「スケジュール登録できている」ように見えるのに、肝心の送信が起きない。ログを追っても、送信処理そのものが呼ばれていない。地味に見えて、運用としては致命的でした。
この記事では、私がハマった原因(WP-Cronの仕様)と、XserverのcronでWP-Cronを5分ごとに動かして安定運用に持ち込んだ手順を、図解とスクリーンショット付きでまとめます。
起きたこと:スケジュールはあるのに送られない
問題の原因はメール設定ではなく、送信処理そのものが「走っていない」ことでした。深夜〜早朝のアクセスがゼロの時間帯に、WP-Cronが起動していなかったのです。
最初に疑ったのはメール周りでした。SMTPの設定ミス? 迷惑メール判定? 宛先側の受信制限?
でも調べるほど、違和感が増えます。なぜなら「届かない」ではなく、送信処理が”走っていない”からです。
そして妙に条件が揃っていました。
| 時間帯 | アクセス数 | メール送信 |
|---|---|---|
| 昼間(10:00〜18:00) | 多い | 正常に動く |
| 夕方〜夜(18:00〜24:00) | やや減る | たまに遅延 |
| 深夜〜早朝(0:00〜7:00) | ほぼゼロ | 完全に止まる |
この時点で、ようやく「WP-Cronかもしれない」と疑い始めました。WordPressでスケジュールを組むと、つい「cron=時間で勝手に回る」と思いがちなんですよね。ここが私の反省ポイントです。
原因:WP-Cronは”アクセスがトリガー”になりがち
WP-Cronはタイマーではなく「訪問者が来たときにチェックする仕組み」です。誰もサイトに来なければ、スケジュールは永遠に実行されません。
WordPressのWP-Cronは、OSのcron(サーバーのcron)のように常駐して定期実行する仕組みではありません。
多くの環境では、サイトへのアクセスをきっかけに「期限が来ているイベントはあるか?」を確認し、あれば実行します。
以下の図は、デフォルトのWP-Cron(左)と、サーバーcronに切り替えた後(右)の動作の違いを表しています。
▲ WP-Cronの2つの動作モード比較(左:デフォルト / 右:サーバーcron運用)
私のサイトは、深夜にアクセスがほとんど無い日がありました。結果、メール送信の予定時刻を過ぎてもWP-Cronが走らず、「送られるはずのメール」が”保留”のままになっていたわけです。
この仕様は、低トラフィックサイトだけでなく、強力なページキャッシュが効いて「WordPressまでリクエストが届きにくい」構成でも、似たような症状が出ます。
解決策:Xserverのcronでwp-cron.phpを5分ごとに起動
やることは2つだけです。wp-config.phpにDISABLE_WP_CRONを追加し、Xserverのcronで5分ごとにwp-cron.phpを叩く。これだけで時間通りの実行が安定します。
▲ 解決策の全体像:たった2ステップで完了
私は5分ごとにしました。理由は、メール送信を「だいたい時間通り」にしたかったのと、負荷を増やし過ぎたくなかったからです。
| 実行間隔 | 向いている用途 | サーバー負荷 |
|---|---|---|
| 5分(おすすめ) | 時刻指定メール、予約投稿 | 低(問題なし) |
| 10分 | 通知系、バックアップ | ごく低い |
| 15分 | ゆるい定期処理 | 最小 |
手順:WordPress設定 → Xserver cron設定
DISABLE_WP_CRONの追加とXserverのcron設定は必ずセットで行ってください。片方だけでは不完全です。
ステップ1:wp-config.php に DISABLE_WP_CRON を追加
重要:これを入れたら、サーバーcronを設定するまでWP-Cronは完全に動かなくなります。予約投稿もバックアップも止まります。先に手順全体を把握してから作業してください。
wp-config.php をサーバー上で開き、「That’s all, stop editing!」のコメントより上に以下の1行を追加します。
|
1 |
define('DISABLE_WP_CRON', true); |
これで「アクセスが来たタイミングでcronを起動する」デフォルトの挙動を止めます。
ステップ2:Xserverのサーバーパネルでcronを設定(5分ごと)
Xserverはサーバーパネルから簡単にcronを設定できます。
① サーバーパネルにログイン → 「Cron設定」を開く
サーバーパネルの「Cron設定」の場所
② 実行間隔とコマンドを入力
以下のように設定します。
| 設定項目 | 入力値 | 説明 |
|---|---|---|
| 分 | */5 |
5分ごとに実行 |
| 時間 | * |
毎時 |
| 日 | * |
毎日 |
| 月 | * |
毎月 |
| 曜日 | * |
毎曜日 |
コマンドには以下を入力します(example.com は自分のドメインに置換)。
curl の場合(推奨):
|
1 |
/usr/bin/curl -s https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1 |
wget の場合:
|
1 |
/usr/bin/wget -q -O - https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1 |
コマンドのポイント:
> /dev/null 2>&1は出力を捨てて、ログ肥大化を防ぐおまじない- サイトがhttps運用なら、必ず
https://で叩くこと - Xserverではcurlのパスが
/usr/bin/curlであることを確認(which curlで調べられます)
③ 設定完了後、一覧に追加されたことを確認
動作確認:本当に回っているか確かめる3つの方法
設定して「たぶん動いた」で終わるのが一番危険です。テストメール、アクセスログ、予約投稿の3つで確実に確認してください。
確認①:テストメールを飛ばす
「1分後に自分のアドレスへ送信」するテストイベントを作成し、5分以内に届くか確かめます。
確認②:アクセスログで wp-cron.php への定期アクセスを確認
Xserverのアクセスログ、またはサーバーログで wp-cron.php への5分間隔のアクセスが記録されていれば、cronは正常に動作しています。
確認③:予約投稿や定期処理の遅延チェック
予約投稿がある場合、以前と比べて時間のズレが小さくなっていれば成功です。私はメール送信が時間通りになったことで、ここで確信に変わりました。
運用のコツ:重複送信を防ぐロック機構
cronが安定したら、次に対策すべきは重複送信です。トランジェントによる短時間ロックで、同時実行による二重送信を防げます。
何らかの理由でcronが同時実行されたり、処理が重くて次の起動と重なったりすると、同じ対象にメールを2回送る事故が起きます。
そこで有効なのが、トランジェントによる短時間ロックです。
▲ トランジェントを使ったロック機構のフロー
以下は考え方のサンプルコードです(設計に合わせて調整してください)。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 短時間ロックで多重実行を防ぐ $lock_key = 'my_mail_job_lock'; if ( get_transient($lock_key) ) { return; // すでに実行中 → スキップ } set_transient($lock_key, 1, 5 * MINUTE_IN_SECONDS); try { // ここで対象ユーザーを抽出して送信 // wp_mail(...) など } finally { delete_transient($lock_key); } |
さらに確実にするなら、以下の対策を組み合わせると事故率がぐっと下がります。
| 対策 | やること | 効果 |
|---|---|---|
| 送信済みフラグ | ユーザーmetaや独自テーブルに記録 | 同じユーザーへの二重送信を防止 |
| ジョブIDの一意化 | 日付+種別でIDを生成 | 同じジョブの重複実行を検知 |
| 再送キュー | 失敗時にキューへ戻す | 送信漏れを救済 |
よくある質問(FAQ)
WP-Cronのcron化にあたってよく聞かれる5つの疑問に答えます。
Q. DISABLE_WP_CRON を入れると、何が止まりますか?
予約投稿、定期バックアップ、各種プラグインの定期処理など、WP-Cronに依存しているものはすべて止まります。だからこそ、サーバーcronとセットで運用します。片方だけでは不完全です。
Q. サーバーcronとWP-Cron(アクセス起動)を両方動かしたらどうなる?
起動回数が増え、重複実行や負荷の原因になることがあります。基本はどちらか一方に寄せるのがおすすめです(本記事ではサーバーcronに寄せています)。
Q. 5分ごとじゃないとダメ?
用途次第です。厳密な時刻が重要なら5分、ゆるい通知なら10〜15分でも十分です。まずは「遅れて困る許容範囲」から決めるのが現実的です。
Q. Basic認証やアクセス制限がある場合は?
HTTPで叩く方式は制限の影響を受けます。wp-cron.php だけ例外にするか、WP-CLIで wp cron event run --due-now を使う方法も検討してください。
Q. cron設定後も動かない場合は?
XserverのWAF(Web Application Firewall)がcurlからのリクエストをブロックしているケースがあります。サーバーパネルのWAF設定でwp-cron.phpへのアクセスが遮断されていないか確認してください。WAFが原因で403エラーが出るパターンと対処法は「XserverのWAFで403エラーが出たときの対処法」で詳しく解説しています。
ちなみに、Xserverの共用サーバーではWebSocketやSSEも動作しません。リアルタイム通信をロングポーリングで代替した話を以下にまとめています。
関連記事
Xserverでの運用やWordPressのトラブル対応に関連する記事です。
まとめ
WP-Cronは「時間で勝手に回る」のではなく「アクセスが来たときにチェックする」仕組みです。低トラフィック時間帯に処理が止まる問題は、Xserverのcronで5分ごとに起動することで解決できます。
WP-Cronは便利ですが、アクセスが少ない時間帯に処理が遅れたり止まったりすることがあります。私はそこに気付けず、スケジュールメールが送れない状態でしばらく悩みました。
最終的にやったことは、この2つだけです。
| ステップ | 作業内容 |
|---|---|
| 1 | define('DISABLE_WP_CRON', true); でアクセス起動を止める |
| 2 | Xserverのcronで wp-cron.php を 5分ごとに起動する |
この構成にして、時間通りのメール送信を取り戻せました。
もしあなたも「予約メールが送れない」「深夜だけ動かない」といった症状に心当たりがあるなら、一度WP-Cronの起動条件を疑ってみてください。作業時間は10分程度ですが、運用の安定度がびっくりするくらい変わりますよ。











コメント