WordPress: transition_post_status action

I needed an action to monitor for posts being published, unpublished or updated after they were already published in my WordPress plugin. I discovered Post_Status_Transitions and specifically the transtion_post_status action that is called for every change to a post’s status. I then check if either the $old_status or the $new_status variables are ‘publish‘ and then I know the article is either being published or being unpublished.

An important note when you are implementing the transition_post_status action

When you call add_action, you need to modify the $accepted_args parameter. The default value is 1, it needs to be changed to 3.

If you only write add_action('transition_post_status', 'my_function'), the default number of parameters that are sent to my_function is 1 so you will only get the $new_status parameter and the other two params won’t be sent.

The correct syntax to add a transition_post_status action is: add_action('transition_post_status', 'my_function', 10, 3); my_function will then be called with all three parameters ($new_status, $old_status, $post).

2 responses so far ↓

From my experience (WordPress 3.5.1), and in spite of what it says in WP Codex, in reality this hook is triggered every time a post is saved and not only when there’s an actual status transition. When I edited a published post the hook was triggered though both $old_status and $new_status were ‘publish’.

I also see nothing in WordPress code (in version 3.5.1) that conditions it to fire only if there’s a change in the status. The function that triggers it in wp-includes/post.php is wp_transition_post_status(). This function is called from two functions in post.php – wp_publish_post(), where there’s an actual post transition, and wp_insert_post() that saves post data to the database, including edited posts, regardless of their status, and there isn’t an IF condition that calls the function only if $new_status is different from $old_status.

It seems to only give you the *possibility* to detect a status transition by giving you both the old and new status, which means that to verify there was really a transition one should check BOTH the old status and the new status. Or else add the following condition at the beginning of your function so it would run only when there is a status change:

if ($new_status == $old_status) return;

Perhaps it’s a bug, but personally, I prefer it this way because I use this hook for some changes beyond the post status, so it’s useful for me to be able to handle posts whose status stayed the same without having to write a new separate function for it.

There are also hooks for specific post transitions – {$old_status}_to_{$new_status} – e.g. ‘draft_to_publish’, ‘publish_to_pending’ etc. – but that’s indeed not very useful if all you need to know is if a post’s status was changed from ‘publish’ status to any non-‘publish’ status and vice versa. transition_post_status will cover all the possibilities.