transition_post_statusのアクションフックで$postを使う時の注意点

Post Status Transitions « WordPress Codex

transition_post_statusは投稿の状態が変更されたときに呼び出されるフック。以下のように使う。
予約投稿されたらその予約日時をメールで通知するというものだ。


add_action('transition_post_status', function($new_status, $old_status, $post) {
  if ($new_status == 'future') {
    send_publish_notify_mail($post);
  }
}, 10, 3);

function send_publish_notify_mail($post) {
  ...
}

ここで引数の$postを関数間で引き回すのがめんどくさかったので以下のようにglobal $postをつかっていたところ、ちょっとハマった。


add_action('transition_post_status', function($new_status, $old_status, $post) {
  if ($post->post_status == 'future') {
    send_publish_notify_mail();
  }
}, 10, 3);

function send_publish_notify_mail() {
  global $post;
  ...
}

なにやらメール本文に予約日時を入れようとしてもうまく入らない。

簡潔にこの原因を述べると・・・

global $postには更新前の$postが入ってる。
例えば$post->post_statusが$old_statusと同様になる。公開日時も更新前のものが入っている。

コールバック引数の$postは更新後の$post。
$post->post_statusは$new_statusと同じになる。こっちをちゃんと使わないといけない。

transition_post_statusは更新後に呼び出されるフックのはずだが、globalな$postはDBからの再読み込みがされていないということだね。
WordPressに限らずフックでありがちな罠だ。

逆にこれを利用して新旧の値を比較して何かするといったこともできそうだが、アンドキュメンテッドな挙動なのでこれをアテにして処理を書くのはやめた方がいいだろう。

ともあれ結論としてはglobalのではなくコールバックの引数でわたってくる$postを使いましょうと言うことだ。