事象
WordPress で普通に投稿して、現在時刻から公開とした場合、なぜか予約投稿となってしまい、更にそれが失敗して公開されない事象に遭遇した。
調べたら色々な人が「予約投稿に失敗」することは書いているが、原因の調査に色々と苦労したので経緯とか解決方法とかをメモ。
問題
1. WordPress の wp-cron.php 呼び出しそのもの
今回問題が発生したのは検証環境であり、実際にアクセスするURLとwp_options の home / siteurl のドメインが異なる状態だった (別の環境から dump などを一式持ってきて、 nginx の sub_filter とか proxy_redirect でページに表示されているドメイン情報を置き換えて動作確認していた状態)。
そのため、この状態だと wp-cron.php の呼び出しが home/siteurl で指定したドメイン側のサイトへと行われてしまう 。
この場合の解消方法としては、/etc/hosts
に記述を追加して本番を自身と認識させたり、サーバー上の cron によって開発の wp-cron.php を定期的に呼び出すようにしたり、そもそもの問題である home / siteurl を適切な値に直す、といった方法が必要になる。
ただ、これは明らかに普通の範囲を逸脱した使い方だとは思うので、あくまで参考まで。
2. Basic 認証による wp-cron.php 実行阻害
これは検索したらよく出てくるが、 wp-cron.php が呼ばれないと予約投稿は上手く投稿されない。
今回は前段に nginx + Basic 認証がいたので、これをちゃんとパスさせて WordPress から wp-cron.php を実行できる環境を作っておくこと。
3. OS上の不完全な時刻あわせ
Basic認証はともかく、home / siteurl をだますパターンは滅多なことでは起こり得ないと思うので、同様の問題にあたる人がいるとすれば、ほぼこの 3. の問題だと思う。
この問題が原因かどうかは、WordPress の設定 > タイムゾーンを見てみよう。 ここでは、タイムゾーンに「東京」が指定されることを想定している。 この時、以下のように「協定世界時」と「現地時間」が一致していると、この問題の可能性が高い。
協定世界時 (GMT) は現地時間 (JST) のマイナス9時間であるため、これらの間の差は9時間ないとおかしい状態なのである。
# タイムゾーンは東京を指定しているので後者が日本時間、前者はその9時間前になる
協定世界時は2020-08-06 01:23:45です。 現地時間は 2020-08-06 01:23:45 です。
色々と調査しましたが、この問題は /etc/localtime
だけ書き換えたことが原因でした。 今回、Dockerで動かしてたので、親の /etc/localtime
を :ro
でマウントするという方法を採っていたのです 。
そして、何が起こったかはまさに以下で説明されている通りです。
そんな /etc/localtime をホストに volume マウントするとどうなるか? symlink である /etc/localtime がホストの /etc/localtime に置き換わると思いきや、実はリンク先のファイルが置き換わる、つまり、UTC の zoneinfo の中身が JST のそれに置き換わってしまうのです。
Docker で /etc/localtime をホストに volume マウントしてハマった話 - https://qiita.com/jeffi7/items/9d4c85cf049644f711b8
UTCの時刻がJSTのそれに置き換わる、ということで、確かに UTC が JST に置き換わってますので、事象と一致しますね。
WordPress の中身は詳しくないんですが、どうも「WordPressの時刻回りはすごい複雑」に見えたので、この2つの時刻の取得のソース元が違うとかなんでしょう、多分。 で、これらが混ざりあっている結果、こういう状況になってしまったのではないかと思いますが、インフラ設定がちゃんとしてればいい話ではあるので、これ以上は突っ込みませんでした。
というわけで、Docker でタイムゾーンを合わせるのであれば -e TZ=Asia/Tokyo
のように環境変数を渡すことで指定できるので、環境変数を使ってコンテナのタイムゾーン合わせをしましょう。