WordPress マルチサイト環境で、ほぼ同じ構成にもかかわらず、一部サイトだけ予約投稿が失敗する事象が発生した場合、最初に確認すべきなのは「WordPress 本体が壊れているか」ではなく、WP-Cron、予約投稿イベント、対象投稿の状態、コアフック、サイト単位の差分です。
今回の事例では、サイトAでは予約投稿が正常に処理されていた一方で、サイトBでは複数の投稿が「予約投稿の失敗」になっていました。最終的には Missed Scheduled Posts Publisher by WPBeginner を有効化することで解消しましたが、結論だけを見ると原因の整理が不十分になります。そこで本記事では、WP-CLI を使って事実ベースで切り分けた流れを、再現しやすい形で整理します。:contentReference[oaicite:0]{index=0}
発生した現象
- WordPress はマルチサイト構成で運用していた
- サイトAでは予約投稿が成功していた
- サイトBでは複数の予約投稿が「予約投稿の失敗」になっていた
- サーバー側の crontab には WordPress 用の cron は設定されていなかった
- 運用としては WP-Cron 依存の状態だった
この状況では、WordPress 全体障害よりも、サイトごとの発火条件の差、プラグイン差分、あるいは publish_future_post 周辺の処理差を疑う方が整理しやすくなります。
最初に疑ったポイント
- WP-Cron そのものが正常に spawn できていない可能性
- サイトBはアクセス量や発火条件の差で scheduled post を取りこぼしている可能性
- サイトAとサイトBで、予約投稿を救済するプラグインや設定差分がある可能性
- publish_future_post またはそのコア処理に干渉している可能性
ここで重要なのは、最初からプラグイン導入を解決策として決め打ちしないことです。まずは、どこまで正常で、どこから異常かを順に確認します。
実際に行った調査手順
1. WP-Cron 自体が起動できるか確認する
最初に確認したのは、WP-Cron の spawn 自体が壊れていないかです。WP-Cron が起動できない状態であれば、予約投稿イベントの詳細を追う前に、基盤側の問題として対処する必要があります。
wp cron test --url=https://example.com
この確認では、WP-Cron spawning is working as expected. という結果が返ってきました。つまり、WP-Cron の起動機構そのものは正常であり、「cron がまったく動いていない」という切り分けは外せます。
2. 予約投稿イベントが登録されているか確認する
次に確認したのは、publish_future_post イベントが登録されているか、また期限を過ぎたイベントが残っていないかです。予約投稿失敗では、イベントが存在しないのか、存在するが処理されていないのかで意味が変わります。
wp cron event list --url=https://example.com
wp cron event list --fields=hook,next_run_gmt,args --url=https://example.com
結果として、publish_future_post は複数登録されており、しかも本来なら処理済みであるべき時刻のイベントが残っていました。args には投稿ID相当の引数も入っていました。この時点で、「予約投稿イベントの登録」は正常だが、「実行」が進んでいない可能性が高いと判断できます。
3. future 投稿が実際に残っているか確認する
イベントだけを見ても、対象投稿の状態が分からなければ十分ではありません。そこで、公開時刻を過ぎた future 投稿が残っているかを確認します。
wp post list --post_status=future --fields=ID,post_title,post_date --url=https://example.com
ここでは、公開時刻を過ぎた future 投稿が複数残っていました。つまり現象は「予約がされていない」ではなく、「予約はされているが publish へ進んでいない」と整理できます。この差は重要です。
4. due な cron を手動実行して挙動を確認する
次に、自動実行だけが弱いのか、それとも手動実行でも publish できないのかを切り分けます。これにより、問題が WordPress の公開機能そのものにあるのか、通常運用時の発火条件にあるのかを見分けやすくなります。
wp cron event run --due-now --url=https://example.com
wp cron event run publish_future_post --all --url=https://example.com
この手動実行では、publish_future_post が実行され、future 投稿の一部が実際に publish に変わりました。ここから分かるのは、WordPress 本体の予約投稿機能そのものは壊れていない、という点です。自動実行時に missed schedule を取りこぼしている可能性が高くなります。
5. コアの公開処理が外れていないか確認する
publish_future_post が登録されていても、実際にそれを処理する WordPress コアの関数が外れていれば、公開は進みません。そのため、check_and_publish_future_post がフックされているかを確認します。
wp eval 'var_dump( has_action("publish_future_post", "check_and_publish_future_post") );' --url=https://example.com
戻り値は int(10) でした。これは check_and_publish_future_post が正常にフックされていることを示しています。したがって、コア処理が無効化されている、あるいは消されているという可能性は低いと判断できます。
6. タイムゾーン差とプラグイン差分を比較する
マルチサイトで一部サイトだけ失敗する場合、最後に比較すべきなのはサイト単位の差分です。特に、タイムゾーン設定とプラグインの有効状態は優先して確認した方がよい項目です。
wp option get timezone_string --url=https://site-a.example.com
wp option get timezone_string --url=https://site-b.example.com
wp option get gmt_offset --url=https://site-a.example.com
wp option get gmt_offset --url=https://site-b.example.com
wp plugin list --url=https://site-a.example.com
wp plugin list --url=https://site-b.example.com
タイムゾーンについては、両サイトで timezone_string と gmt_offset に大きな差はありませんでした。主因がタイムゾーン不一致である可能性は低い状態です。
一方で、プラグイン一覧を比較すると、サイトAでは Missed Scheduled Posts Publisher by WPBeginner が有効で、サイトBでは無効でした。この差分が、最も有力な要因として浮かび上がりました。
調査結果の整理
| 確認項目 | 結果 | 解釈 |
|---|---|---|
| WP-Cron の spawn | 正常 | 基盤としての cron 起動機構は生きている |
| publish_future_post イベント | 登録あり | 予約投稿イベント自体は作成されている |
| future 投稿 | 残存あり | 公開時刻を過ぎても publish へ進んでいない |
| 手動で due イベント実行 | publish へ進行 | WordPress 本体の公開機能は動作している |
| check_and_publish_future_post | フックあり | コア処理が外れているわけではない |
| タイムゾーン差 | 大差なし | 主因ではなさそう |
| プラグイン差分 | あり | サイト単位の挙動差として最有力 |
この結果から、少なくとも今回の範囲では「WordPress コアが壊れていた」というより、「通常運用時に missed schedule を取りこぼしていた」と見るのが自然です。サイトAは正常だったというより、救済系プラグインが入っていたため問題が表面化しにくかった可能性があります。
最終的な解決策
サイトBで Missed Scheduled Posts Publisher by WPBeginner を有効化したところ、その後は予約投稿の失敗が解消しました。今回の対処としては、これが最も実務的な解決策でした。
ここで整理しておきたいのは、このプラグインが「壊れた WordPress を修復した」というより、「missed schedule を救済した」という見方です。手動実行では publish に進んでいたため、本質的には予約投稿のコア機能ではなく、自動運用時の取りこぼしに近い問題でした。
今回の切り分け順序が有効だった理由
- cron が起動できるかを最初に確認し、基盤障害かどうかを切り分けられた
- イベントがあるかを確認し、未登録なのか未実行なのかを分離できた
- future 投稿の残存確認により、現象を投稿ステータスでも裏づけできた
- 手動実行により、本体機能の健全性を確認できた
- コアフック確認により、関数差し替えや無効化の可能性を下げられた
- 最後にサイト差分を比較し、実際の有力差分を特定できた
この順序の利点は、感覚ではなく、コマンドごとの事実で判断できることです。WP-CLI を使うことで、予約投稿失敗を「たぶん cron の問題」と曖昧に扱わず、どこまで正常でどこから異常かを明確にできます。
再発防止のための注意点
- マルチサイトでも、サイトごとのプラグイン有効状態は必ず比較する
- WP-Cron 依存運用では、アクセス条件や発火条件によって missed schedule が起こりうる
- 救済プラグインは実務上有効だが、恒久的な安定運用を重視するならサーバー cron の導入も検討する
- 予約投稿失敗時は、WP-Cron、イベント、future 投稿、手動実行、コアフック、プラグイン差分の順で見ると整理しやすい
特に、同じ WordPress インストール配下だから挙動も同じだろう、と考えるのは危険です。マルチサイトでは、サイト単位のプラグイン状態や設定差分で挙動が変わることがあります。今回のように、一部サイトだけ失敗したからこそ、むしろ WordPress 全体障害ではなくサイト差分として切り分けやすくなりました。
まとめ
予約投稿の失敗は、即座に WordPress 本体故障と判断すべき事象ではありません。今回の事例では、WP-Cron の spawn は正常、publish_future_post イベントも登録済み、future 投稿も存在し、コアフックも生きており、手動実行では publish へ進みました。そこまで確認した上で、サイト単位のプラグイン差分が最も有力な要因として見つかりました。
実務的には、まず「cron が動くか」、次に「イベントがあるか」、「対象投稿が future のまま残っているか」、「手動実行で publish できるか」、「コアフックは生きているか」、「サイト差分はあるか」を順番に確認するのが有効です。この流れを押さえておけば、予約投稿失敗の調査はかなり整理しやすくなります。

コメント