公開していたはずのWordPressの記事が、ある朝まとめて下書きに戻っていたり、完全に消えていたりする。私自身、制作したサイトで実際にこれをやられて血の気が引きました。
ゴミ箱にも入っていない。誰かが編集した形跡もない。それなのに、複数の記事がほぼ同じ時刻に一斉に変わっている。最初は不正アクセスやデータベースの破損を本気で疑いました。
ところがアクセスログを一行ずつ追い、WordPress内部の処理とプラグインの動きを調べていくと、犯人はもっと身近なところにいました。PublishPress Futureという期限管理プラグイン、WP-Cron、そしてAction Scheduler。この3つの組み合わせです。
しかも「不正アクセスではなかった」と分かっても、仕組みを理解していないと再発します。設定画面で自動処理をOFFにしたのに、また同じことが起きる。そんな厄介な挙動もありました。
今回は実際に起きたトラブルをもとに、なぜWordPressの投稿が一斉に下書き・削除されるのか、その仕組みと切り分けの手順、そして二度と起こさないための設定を、確認コマンドや設定例も交えて具体的にまとめます。同じ現象で頭を抱えている方の手がかりになれば嬉しいです。
まず落ち着いて確認したいチェックリスト
WordPressの投稿が勝手に下書きになったり消えたりすると、反射的にプラグインを削除したり設定を変えたくなります。でも、その前にやることがあります。
先に設定をいじってしまうと、あとから原因を追えなくなります。特にアクセスログとScheduled Actions(予約処理)の履歴は、原因を切り分ける一番の証拠になります。まずは現状をそのまま記録しておきましょう。
- 変更された投稿が複数あるか
- それらがほぼ同じ時刻に変わっていないか
- 投稿のリビジョンが増えているか、増えていないか
- ゴミ箱に移動された投稿が残っているか
- PublishPress Futureのアクションやワークフローが有効になっていないか
- 「Automatically create actions(自動でアクションを作成)」が有効になっていないか
- Scheduled Actionsに過去の予約処理が残っていないか
- サーバーログに
wp-cron.phpへのアクセスが記録されているか admin-ajax.php?action=as_async_request_queue_runnerのリクエストが記録されているか- ベーシック認証やアクセス制限でWP-Cronが止まっていなかったか
複数の投稿が同じタイミングでまとめて変わっているなら、手動操作よりも自動処理を疑うのが自然です。PublishPress FutureやAction Schedulerに溜まっていた予約処理が、WP-Cronの再開時に一気に流れた、というパターンが典型だからです。
複数投稿が同時刻に変更された理由
私が最初に注目したのは、変更された投稿の更新時刻がほぼ揃っていたことです。
人が管理画面で一つずつ操作したなら、どれだけ急いでも投稿ごとの時刻は数秒から数十秒はズレます。ところが今回は、まるでスイッチを一つ押したかのように、複数の記事が同じ分・同じ秒に近いタイミングで書き換わっていました。
さらに、通常の編集なら必ず増えるはずのリビジョンが増えていません。この2点だけで「人が触ったのではなく、WordPress内部の自動処理が動いた」という線がかなり濃くなりました。
サーバーのアクセスログを見ると、同じ時間帯にwp-cron.phpへのPOSTと、admin-ajax.phpへのリクエストが並んで記録されていました。
POST /wp-cron.php
POST /wp-admin/admin-ajax.php?action=as_async_request_queue_runner
この組み合わせは、WordPressのスケジュール処理やAction Schedulerの非同期処理が走ったときに見られるものです。つまり今回の一斉変更は、人の手ではなくWordPress側の自動処理が引き起こした可能性が高いということになります。
不正アクセスや手動操作との見分け方
投稿が勝手に下書きや削除になると、まず不正アクセスを疑いたくなります。もちろん不正ログインや権限の悪用を完全に否定はできません。ログイン履歴やセキュリティプラグインのログは必ず見ておくべきです。
ただ、今回のように複数投稿が同時刻に変わり、リビジョンも増えていないなら、天秤は自動処理側に傾きます。判断材料を表にすると切り分けやすくなります。
| 確認項目 | 手動操作の可能性 | 自動処理の可能性 |
|---|---|---|
| 変更時刻 | 投稿ごとに少しずつズレやすい | 複数投稿が同時刻に変わりやすい |
| リビジョン | 増えることが多い | 増えない場合がある |
| アクセスログ | 投稿編集画面へのアクセスが残りやすい | wp-cron.phpやadmin-ajax.phpが目立つ |
| 対象投稿 | 一部の記事に限られやすい | 条件に合う投稿がまとめて処理される |
管理者アカウントのログイン履歴に見覚えのないIPがないか、二段階認証は破られていないか、といったセキュリティ面の確認もあわせて行えば安心です。その上で、同じ時刻に大量の記事が変わっているなら、まずプラグインの予約処理とWP-Cronを見に行く価値は十分あります。
WP-CronとAction Schedulerの仕組み
ここが今回の核心です。原因を理解するには、WP-CronとAction Schedulerの関係を押さえる必要があります。
WP-Cronは、サイトへのアクセスをきっかけに動くWordPress独自の疑似スケジューラーです。名前に「Cron」と付きますが、時刻が来たら勝手に動くサーバー本来のcronとは別物です。誰かがサイトを開いた瞬間に「そういえば実行すべき予約があったな」とまとめて処理する、という後追い式の仕組みです。
予約投稿、プラグインの定期処理、メール送信、期限付きアクションなどがこの上で動きます。ただし、次のようなクセがあります。
- サイトへのアクセスがないと実行されない
- アクセスの少ないサイトでは処理が遅れる
- ベーシック認証やアクセス制限の影響を受けることがある
- 止まっていた処理が、再開時にまとめて実行される
そして多くのプラグインは、WooCommerce由来のAction Schedulerというライブラリでバックグラウンド処理を管理しています。これは「あとで実行する処理をキュー(順番待ちの列)として保存しておく仕組み」です。将来実行するアクションを登録しておき、WP-Cronなどをきっかけに順に処理します。
PublishPress Futureの期限アクションも、このキューに登録されます。もし何らかの理由でWP-Cronが止まっていれば、キューは実行されずに溜まり続けます。そして再びWP-Cronが動いた瞬間、溜まっていたジョブがまとめて処理される。今回の現象は、まさにこの動きとぴったり一致していました。
WP-Cronが実際に動いているかは、WP-CLIが使える環境なら次のコマンドで確認できます。
wp cron event list
wp cron event run --due-now
wp cron event listで予約済みイベントの一覧と次回実行予定が見られます。実行予定を大きく過ぎたイベントが並んでいたら、WP-Cronが正常に回っていないサインです。
PublishPress Futureが影響した可能性
今回のサイトには、投稿の公開後に自動でステータスやカテゴリを変更できる「PublishPress Future」(旧Post Expirator)を入れていました。
このプラグインは、公開後の投稿を指定日時に自動で下書き(Draft)に戻す、非公開(Private)にする、ゴミ箱(Trash)へ送る、完全削除(Delete)する、カテゴリを付け替える、といった処理をスケジュールできます。期間限定のお知らせ、キャンペーン記事、求人・イベント情報などでは本当に便利で、手作業で戻す手間がなくなります。
ただ、便利さの裏で、設定を誤ると影響範囲が一気に広がります。特に注意すべきは、投稿タイプ全体やワークフローに対する一括ルールです。
たとえば「公開から1週間後にDraftへ変更」というルールが投稿タイプ全体に効いていれば、条件を満たした投稿はすべて自動で下書きになります。個別に期限を設定した覚えがなくても、投稿タイプ側やワークフロー側でルールが適用されていれば、対象は全記事に及びます。
今回、個別に期限を設定していない投稿まで巻き込まれたのは、この一括ルールが知らないうちに全投稿へ適用されていたためだと考えられます。
PublishPress FutureとScheduled Actionsの確認方法
PublishPress Futureを使っているなら、今の設定だけでなく、過去に登録された予約処理が残っていないかまで確認しておきましょう。ここを見落とすと再発します。
設定画面で自動処理をOFFにしても、すでにキューへ登録済みのアクションは残ります。後から条件が揃えば、それが実行されてしまうのです。
PublishPress Future側で確認する項目
まずプラグインの設定を見ます。
- WordPress管理画面にログインする
- PublishPress Futureの設定画面を開く
- 投稿タイプごとの期限(Post Types)設定を確認する
- 「Automatically create actions」が有効になっていないか確認する
- 全投稿に自動適用されるワークフローがないか確認する
- 期限到来時の動作が「Draft」「Trash」「Delete」になっていないか確認する
一番危ないのは、全投稿へ自動的に期限アクションを作る設定です。意図せず有効になっていると、公開済みの記事にまで下書き化や削除の予約が付いてしまいます。特に動作が「Delete」や「Trash」だと、誤作動したときの被害が大きくなります。
Scheduled Actionsで確認する項目
次に、Action Scheduler側に過去の予約処理が残っていないかを見ます。WooCommerceなどが入った環境では、管理画面の「ツール」内や、プラグインによっては専用画面にScheduled Actionsの一覧が表示されます。次のような処理がないか探しましょう。
- ステータスが「Pending(保留)」や「Failed(失敗)」の処理
- 投稿ステータスを変更する系のアクション
- 同じ時刻に大量に登録されているアクション
- PublishPress Futureに関連するアクション名(
publishpress_future_run_workflowなど) - 過去の日付のまま未実行で残っている処理
WP-CLIが使えるなら、溜まった保留アクションを手元で流し切って挙動を確かめることもできます。
wp action-scheduler run
ただし、これは残った予約処理を実際に実行するコマンドです。本番サイトでいきなり流すと、まさに下書き化や削除が走る可能性があります。不審なアクションが見つかったら、実行や削除の前に必ずスクリーンショットやメモを残しておきましょう。「どの処理が・いつ・どの投稿に」を後から追えるかどうかで、原因調査のしやすさがまったく変わります。
Automatically create actionsがOFFでも起きた理由
今回いちばんややこしかったのが、「Automatically create actions」をOFFにしていても、すでに登録済みのスケジュールは消えないという点でした。
この設定はあくまで「今後作成する投稿に自動で期限を付けるかどうか」を決めるものです。過去に作られたアクションや、すでにキューへ入っている予約処理まで取り消してくれるわけではありません。
つまり、以前の設定で何らかの期限アクションが作られていた場合、あとからこの項目をOFFにしても、登録済みのアクションが残っていれば条件が揃った瞬間に実行されます。「今はOFFだから大丈夫」という思い込みが通用しないのです。
今回も、以前の設定で登録されたルールが有効なまま残り、WP-Cronが再開したタイミングで一気に流れた、というのが最も辻褄の合う説明でした。設定を変えたら、必ずScheduled Actions側の残骸まで掃除する。これが鉄則です。
ベーシック認証とCron停止の関係
もう一つの大きな要素が、サイトにベーシック認証をかけていたことでした。
制作中や公開前のサイトでは、外部に見られないようベーシック認証をかけるのが定番です。ところが環境によっては、これがWordPress自身の内部通信まで止めてしまいます。
WordPressは、予約投稿やスケジュール処理のために「ループバックリクエスト」という、自分自身のサイトへアクセスする内部通信を使います。WP-Cronもこの仕組みに乗っています。ベーシック認証があると、このループバック通信が認証で弾かれ、サーバーには「401(認証が必要)」が返ってしまうことがあります。
その結果、WP-Cronが回らず、期限処理がキューに溜まり続けます。そしてベーシック認証を解除した瞬間、WP-Cronが再び動き出し、溜まっていた期限処理が一気に実行される。今回のログの時刻と挙動は、この流れとかなり一致していました。
どうしてもベーシック認証を維持したまま予約処理を動かしたい場合は、wp-cron.phpだけを認証の対象から外す方法があります。Apache系サーバーの.htaccessなら、次のような記述です。
<Files "wp-cron.php">
Satisfy Any
Order allow,deny
Allow from all
</Files>
認証設定の直後にこの記述を置くと、wp-cron.phpへのアクセスだけは認証を免除できます。サーバーやプラグインの構成によって最適な書き方は変わるので、必ずテスト環境で動作を確かめてから本番に反映してください。
関連記事:WordPressで特定の固定ページやカテゴリーにBasic認証をかける方法
アクセスログで確認したいポイント
サーバーのアクセスログを見られる環境なら、投稿が変わった時刻の前後に、次のようなリクエストがないか探してみましょう。
POST /wp-cron.php
POST /wp-admin/admin-ajax.php?action=as_async_request_queue_runner
wp-cron.phpはWordPressのスケジュール処理の入口です。admin-ajax.php?action=as_async_request_queue_runnerは、Action Schedulerの非同期処理として記録されるリクエストです。これらが投稿変更の時刻と近ければ、人の操作ではなく自動処理でステータスが変わった可能性が高いと判断できます。
ログを読むときは、次の点もあわせて見ると切り分けが進みます。
- 投稿変更の時刻とログの時刻が近いか
- 同じ時間帯に
wp-cron.phpが何度も実行されていないか - 投稿編集ページ(
post.php)へのアクセスが残っているか - 見覚えのないIPからのログイン試行がないか
- セキュリティプラグインのログに異常がないか
自動処理の線が濃くても、不正アクセスの確認は並行してやっておくと安心です。両方を潰して初めて「原因はこれだった」と言い切れます。
安全に期限機能を使うための設定
期限機能そのものはとても便利です。キャンペーン終了後に記事を自動で非公開にしたり、期間限定情報を整理したりするなら、PublishPress Futureは頼れる存在です。使うのをやめる必要はありません。使い方を安全側に寄せればいいだけです。
一般的な運用なら、次のような設計をおすすめします。
- 全投稿に自動適用されるワークフローは使わない、使うなら慎重に絞る
- 投稿タイプの「Automatically create actions」は必要がなければOFFにする
- 期限は必要な投稿だけ手動で設定する
- 期限到来時の動作はDeleteよりPrivateやカテゴリ変更を選ぶ
- 設定を変えたら必ずScheduled Actionsの残骸を確認する
特にSEOを重視するサイトでは、誤って下書きや削除になるリスクは避けたいところです。公開URLが突然404になったり、インデックスから外れたりすれば、検索流入に直結します。期限到来時の動作は、影響の小さいものを選ぶのが安全です。
| 期限到来時の動作 | リスク | おすすめ度 |
|---|---|---|
| Delete / 完全削除 | 復旧が難しく、SEO面の打撃も大きい | 低い |
| Trash / ゴミ箱 | 復旧はできるが、公開URLは表示されなくなる | 低〜中 |
| Draft / 下書き | 管理画面から戻せるが、公開URLは一時的に消える | 中 |
| Private / 非公開 | 公開状態は変わるが、完全削除よりずっと安全 | 比較的高い |
| カテゴリ変更 | 公開を維持したまま整理できる | 高い |
「期限が来たら削除」は一見スマートですが、実運用ではかなり攻めた設定です。どうしても使うなら対象投稿を限定し、後述のバックアップ体制も必ず整えておきましょう。
再発防止のために見直したいポイント
同じトラブルを防ぐ鍵は、Scheduled Actionsを定期的に見て、不要なワークフローや予約処理を溜めないことです。特に次のタイミングでは確認しておくと安心です。
- サイト公開前にベーシック認証を解除するとき
- PublishPress Futureの設定を変更したとき
- プラグインを有効化・無効化したとき
- WordPress本体やプラグインを大きく更新したとき
- 予約投稿や期限付き投稿を大量に扱ったあと
そしてWP-Cronが安定して動いているかも要チェックです。アクセスが少ないサイトや、認証・アクセス制限をかけたサイトでは、WP-Cronが期待通りに動かないことがあります。そんな環境では、WordPress標準の疑似Cronを止めて、サーバー本来のcronからwp-cron.phpを定期実行する方法が安定します。
まずwp-config.phpで標準のWP-Cronを無効化します。
define( 'DISABLE_WP_CRON', true );
そのうえで、サーバー側のcronから一定間隔で実行します。たとえば5分おきに叩くなら、次のような設定です。
*/5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
こうするとアクセスの有無に関係なく一定間隔で処理が回り、予約が溜まりにくくなります。ただし、WP-Cronを無効化せずにサーバーcronも設定すると二重実行になるため、必ずDISABLE_WP_CRONとセットで行ってください。設定手順はレンタルサーバーによって異なるので、各社のマニュアルや管理画面の仕様を確認しながら進めるのが確実です。
よくある質問
WordPressの投稿が勝手に下書きになるのは不正アクセスですか?
不正アクセスの可能性もゼロではありません。ただし、複数の投稿が同じ時刻に変わり、リビジョンが増えていない場合は、プラグインやWP-Cronによる自動処理を疑う方が自然です。アクセスログ、ログイン履歴、Scheduled Actionsの3つを確認して判断しましょう。
PublishPress Futureを無効化すれば解決しますか?
今後の処理を止める意味では有効なことがあります。ただし、過去に登録された予約処理が残っている可能性があるため、無効化だけでは安心し切れません。Scheduled Actionsに残った処理も確認してから判断しましょう。
Automatically create actionsをOFFにしたのに投稿が下書きになるのはなぜですか?
この設定は「今後作成する投稿」への自動アクションを制御するものです。すでに登録済みの予約処理やワークフローが残っていると、それらは後から実行されます。OFFにした後は、既存のScheduled Actionsを確認して残骸を削除してください。
ベーシック認証をかけているとWP-Cronに影響しますか?
環境によっては影響します。WordPressが自分のサイトへアクセスするループバックリクエストが認証で401になると、WP-Cronや予約投稿、プラグインの自動処理が動かなくなることがあります。wp-cron.phpを認証対象から外すか、サーバーcronで実行する方法を検討しましょう。
完全削除された投稿は復元できますか?
バックアップがあれば復元できる可能性があります。ゴミ箱にも残っていない場合、WordPress管理画面だけでは戻せないことが多いため、サーバーバックアップ、データベースバックアップ、バックアッププラグインの保存データを確認してください。日頃から自動バックアップを用意しておくことが最大の保険になります。
参考情報
- WordPress.org:PublishPress Future(Post Expirator)
- WordPress.org:Action Scheduler
- WordPress Developer:Loopbacks
まとめ
今回の「投稿が一斉に下書き・完全削除される」問題は、不正アクセスでも単純なシステム障害でもなく、PublishPress Futureの期限アクション、WP-Cron、Action Schedulerの挙動が重なった結果でした。犯人が分かってしまえば拍子抜けするほど地味ですが、仕組みを知らないと何度でも再発する厄介さがあります。
押さえておきたい要点は3つです。まず、「Automatically create actions」をOFFにしても、過去に登録された予約処理は残り、後から実行されること。次に、ベーシック認証がループバックリクエストを止めると、WP-Cronが動かず処理が溜まり、認証解除の瞬間に一気に流れること。そして、期限到来時の動作にDeleteやDraftを選ぶと被害が大きくなること。
- PublishPress Futureのワークフローや自動アクションが意図せず有効になっていないか
- Scheduled Actionsに過去の予約処理が残っていないか
- WP-Cronやループバックリクエストが正常に動いているか
この3点を確認し、ワークフローを整理し、期限は必要な投稿だけに設定する。さらに期限到来時の動作をPrivateやカテゴリ変更に寄せ、バックアップを用意しておく。これだけで同じ事故はかなり防げます。
自動化は本当に便利ですが、裏で何が動いているのかを知らないまま使うと、思わぬタイミングで大きな穴を開けます。今回の失敗談が、あなたのWordPress運用の安心材料になれば嬉しいです。