WordPress のアクションフック transition_post_status の挙動にあれ? と思うことがありましたので調べてみました。
- 関数 wp_transiton_post_status
- 即時作成される「自動下書き」の秘密
- 自動保存、下書き保存、リビジョン
- 公開すると…
- transition_post_status のまとめ
- 公開時に1回だけ実行する
01関数 wp_transiton_post_status
transition_post_status アクションフックポイントは includes/post.php にある関数 wp_transiton_post_status の中にあります。
function wp_transition_post_status( $new_status, $old_status, $post ) {
/**
* Fires when a post is transitioned from one status to another.
*
* @since 2.3.0
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*/
do_action( 'transition_post_status', $new_status, $old_status, $post );
この関数 wp_transition_post_status は transition_post_status を含めた3つのアクションフックポイントが登録されているだけの関数です。他には、
do_action( "{$old_status}_to_{$new_status}", $post );
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post, $old_status );
の2つが登録されています。
transition_post_status は上のコードのコメントにあるように投稿のステータスが $old_status から $new_status に変わるタイミングで実行され、その2つと投稿データ $post のパラメータをコールバック関数に渡します。
この transition_post_status がいつ実行され、その時の $old_status と $new_status がどうなっているかを次のコールバック関数を functions.php に入れて調べてみました。
function save_status( $new_status, $old_status, $post ) {
$status = $old_status . ' ' . $new_status . "\n";
file_put_contents('status.txt', $status, FILE_APPEND);
}
add_action('transition_post_status', 'save_status', 10, 3);
関数 wp_transition_post_status が呼ばれますと呼んだ元のディレクトリ下の status.txt に $old_status $new_status を追記していきます。
02即時作成される「自動下書き」の秘密
ということでまず「投稿を追加」から始めたのですがちょっと驚きました。このアクションフックは「投稿を追加」をクリックして投稿ページを開くだけで2回も実行されます。
new auto-draft
auto-draft auto-draft
なぜ2回も実行されるかはソースコードを読まないとわかりませんので後回しにするとして、投稿ページを開くだけでその空データが自動保存されるということのようです。実際、データベースの wp_posts テーブルには「自動下書き」のタイトルでレコードが1行保存されています。

で、ふと思ったのですが、この「自動下書き」データはそのまま何も入力せずに閉じたり、他のメニューに移動しても残ったままです。当然次に「投稿を追加」を開けば新たに「自動下書き」が作成されます。これじゃ wp_posts にどんどんゴミがたまってしまいます。
と思ったのですが、そうではありませんでした。
調べてみましたら今まで知らなかったことがわかりました。「投稿を追加」をクリックするだけで wp_posts に保存されるこのレコードは WordPress のシステム上なくせないもので、たとえばこれがあるからこそ下書き保存する前でもその投稿に画像をアップロードできることになります。また、WordPress は複数のユーザーが投稿できるシステムですので、この機能がないと複数人の最初の自動保存が同時に行われた場合に競合が起きる可能性があるそうです。
なお、この「自動下書き」は7日間使用されなかった場合に自動的に削除されるとのことです。確かに wp_posts を「自動下書き」でクエリしてみても7日前以上のものはありませんでした。
なお、この場合の status.txt は wp-admin ディレクトリ下に保存されていますので、そこから wp_transition_post_status が呼ばれているのだと思います。
03自動保存、下書き保存、リビジョン
続いて、タイトルなり本文なり何かを入力してそのまま放置し、自動保存が実行されるまで待ってみますと、今度はサイトのルート下に status.txt が保存され、
auto-draft draft
draft draft
と、ステータスが auto-draft から draft に変わっています。やはり2回呼ばれています。今はそれは置くとして、データベースを見てみますと、

タイトルが入力され、ステータスも draft になっています。この時点では下書き保存もしておらず自動保存だけです。
ここで下書き保存してみますと、ルート下の status.txt は、
auto-draft draft
draft draft
draft draft
draft draft
new inherit
となり、wp-admin 下の status.txt には、
new auto-draft
auto-draft auto-draft
draft draft
draft draft
となります。データベースは、

1行 revision が増えています。「下書き保存」しますと、元データがコピーされてリビジョンとなるようです。それが new inherit ですね。
この後、記事に変更があれば一定時間ごと(デフォルトは60秒)に自動保存が実行され、ルート下の status.txt に draft draft が2行ずつ追加されていき、手動で「下書き保存」をクリックしますとルート下、wp-admin 下両方の status.txt に draft draft が2行ずつ追加され、その後リビジョンの上限まで new inherit が追加されていきます。
ルート下の status.txt はこうなっています。無駄に長いです(笑)。
auto-draft draft
draft draft
draft draft
draft draft
draft draft
draft draft
new inherit
draft draft
draft draft
draft draft
draft draft
new inherit
draft draft
draft draft
draft draft
draft draft
new inherit
draft draft
draft draft
draft draft
draft draft
draft draft
draft draft
new inherit
draft draft
draft draft
draft draft
draft draft
draft draft
draft draft
draft draft
draft draft
結局、アクションフック transition_post_status は自動保存時に2回、手動「下書き保存」時には5回呼ばれていることになります(多分…)。
04公開すると…
そして記事を公開しますと、ルート下の status.txt には、
draft publish
publish publish
となり、wp-admin 下は、
publish publish
publish publish
データベースは、

となっています。
05transition_post_status のまとめ
結局、投稿ステータスには次のものがあり、
- new …… 無
- auto-draft …… 自動下書き
- draft …… 下書き
- inherite …… 継承(リビジョン)
- publish …… 公開
- future …… 予約
- pending …… 承認待ち
- private …… 非公開
- trash …… ゴミ箱
いろいろな局面によってそのステータスが変化するということになります。主要なステータスの変化は次のようになります。
- new to auto-draft …… 「投稿を追加」で投稿ページを開いたとき
- auto-draft to draft …… 続いて「下書き保存」をクリックしたとき
- new to inherit …… リビジョンが作られるとき
- draft to publish …… 公開したとき
アクションフック transition_post_status を使って確実にステータスの変化を補足する場合は、$old_status あるいは $new_status どちらか一方ではなく、両方を指定したほうがよさそうです。
06公開時に1回だけ実行する
今回このアクションフック transition_post_status を調べようと思ったきっかけは、記事を公開する前にデータベースに保存したいものがあり、そのアクセスを1回だけにしようとあれこれやっているうちにわけがわからなくなってしまったからです(笑)。
これでいけそうです。
function post_status_publish_only( $new_status, $old_status, $post ) {
if($old_status !== 'publish' && $new_status === 'publish'){
// 公開したときの作業
}
if($old_status !== 'trash' && $new_status === 'trash'){
// 削除したときの作業
}
}
add_action('transition_post_status', 'post_status_publish_only', 10, 3);
何度も呼ばれるわけも調べないといけないですね。