WordPress at Your Fingertips

wp_transition_post_status() WP 2.3.0

Fires action hooks related to the transitioning of a post's status. (from draft to publish, from publish to private, etc.).

This function does not change post status, it only calls 3 hooks. This function is called from other functions after the status has been changed to notify plugins, themes and core functions about the change of the post status. To real change post status use: wp_update_post() or wp_publish_post().

The hooks that fire this function:

  1. First hook transition_post_status:

    do_action( 'transition_post_status', $new_status, $old_status, $post );

    Use when you want to connect to any status change.

  2. Second hook OLDSTATUS_to_NEWSTATUS:

    do_action( "{$old_status}_to_{$new_status}", $post );

    Use when you need to connect to specific status changes (from one to another).

    Some useful variants:

    • new_to_publish - when you first publish a new post. For example, if post is added throug wp_insert_post() function.
    • auto-draft_to_publish - when you first publish a new post from the WP admin panel.
    • draft_to_publish - when you publish a saved post.
    • future_to_publish - when you publish a scheduled post.
  3. Third hook: NEWSTATUS_POSTTYPE:

    do_action("{$new_status}_{$post->post_type}", $post->ID, $post);

    Use when you need to do something for the specified status and type of post.

    Some useful variants:

    • publish_post - fires every time when you update/create a post with status publish. wp_insert_post() calls this function when a post of any type other than attachment is updated. I. e. if post status is publish then this hook will be triggered always during post update. So if you need to do something once, only when the post is publishing (not updating), use the hooks above...

    • pending_post - fires every time when you update/create a post with the status pending.

    • draft_post - fires every time when update/create a post with the status draft.
List of all statuses that can be used in hooks above:
  • new - if any status has not been set.
  • publish - published post (page, post or another post type).
  • pending - post on the review before publication.
  • draft - a draft of the post.
  • auto-draft - only created post, without title, content and other information.
  • future - post is scheduled for publication in the future.
  • private - post not available to unauthorized users.
  • inherit - revision or attachment. See get_children().
  • trash - post is in the recycle bin.

This function is already used where it is needed in basic WordPress features. There is no need to call it when changing the status of a post when using wp_update_post() or wp_insert_post().


null. Nothing.


wp_transition_post_status( $new_status, $old_status, $post );
$new_status(string) (required)
Transition to this post status.
$old_status(string) (required)
Previous post status.
$post(WP_Post) (required)
Post data.


#1 Let's see how the function works

To do this, let's take a look at the wp_publish_post(): function code:

function wp_publish_post( $post ) {
	global $wpdb;

	if ( ! $post = get_post( $post ) )

	if ( 'publish' == $post->post_status )

	$wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post->ID ) );

	clean_post_cache( $post->ID );

	$old_status = $post->post_status;
	$post->post_status = 'publish';

	// now, when the status of the post is changed call hooks 
	// which later plugins, themes and other functions can use.
	wp_transition_post_status( 'publish', $old_status, $post );

	do_action( 'edit_post', $post->ID, $post );

	do_action( "save_post_{$post->post_type}", $post->ID, $post, true );

	do_action( 'save_post', $post->ID, $post, true );

	do_action( 'wp_insert_post', $post->ID, $post, true );

#2 Using the hook transition_post_status

This is a General hook that works when we need to connect at the time of changing any status to any other. The hook passes 3 parameters: $new_status, $old_status, $post.
This example shows how to connect when a post's status changes from publish to any other status:

add_action( 'transition_post_status', 'post_unpublished', 10, 3 );
function post_unpublished( $new_status, $old_status, $post ) {
	if ( $old_status == 'publish' && $new_status != 'publish' ) {
		// Post removed from publication

#2.1. Hook triggered at any change of status

add_action( 'transition_post_status', 'intercept_all_status_changes', 10, 3 );
function intercept_all_status_changes( $new_status, $old_status, $post ) {
	if ( $new_status != $old_status ) {
		// Post status changed

#3 Using the hook {$old_status}_to_{$new_status}

Add an action that will be triggered when the draft status changes to publish - draft_to_publish, that is, when you publish a draft.

add_action( 'draft_to_publish', function( $post ){
	// your code
} );

If you want to connect to the time of approval post (pending), you need to use the hook pending_to_publish.

#4 Using the hook {$new_status}_{$post->post_type}

If you want to connect to the current status, no matter what was the status before then use the following construction: STATUS_POSTTYPE.

For example, if you want to do something when a post with the status publish is publishing or updating, the construction will look like publish_post:

add_action( 'publish_post', 'publish_post_action', 10, 2 );
function publish_post_action($post_id, $post){
	// what to do when publishing the post

Note that this hook will also be triggered when a post is updating, if the status is publish or if the status is not specified, but before that it was publish.


Since 2.3.0 Introduced.

Code of wp_transition_post_status() WP 5.8.1

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 );

	 * Fires when a post is transitioned from one status to another.
	 * The dynamic portions of the hook name, `$new_status` and `$old_status`,
	 * refer to the old and new post statuses, respectively.
	 * @since 2.3.0
	 * @param WP_Post $post Post object.
	do_action( "{$old_status}_to_{$new_status}", $post );

	 * Fires when a post is transitioned from one status to another.
	 * The dynamic portions of the hook name, `$new_status` and `$post->post_type`,
	 * refer to the new post status and post type, respectively.
	 * Possible hook names include:
	 *  - `draft_post`
	 *  - `future_post`
	 *  - `pending_post`
	 *  - `private_post`
	 *  - `publish_post`
	 *  - `trash_post`
	 *  - `draft_page`
	 *  - `future_page`
	 *  - `pending_page`
	 *  - `private_page`
	 *  - `publish_page`
	 *  - `trash_page`
	 *  - `publish_attachment`
	 *  - `trash_attachment`
	 * Please note: When this action is hooked using a particular post status (like
	 * 'publish', as `publish_{$post->post_type}`), it will fire both when a post is
	 * first transitioned to that status from something else, as well as upon
	 * subsequent post updates (old and new status are both the same).
	 * Therefore, if you are looking to only fire a callback when a post is first
	 * transitioned to a status, use the {@see 'transition_post_status'} hook instead.
	 * @since 2.3.0
	 * @param int     $post_id Post ID.
	 * @param WP_Post $post    Post object.
	do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );

statuses (of post comment user)


vladlu 100vlad.lu
Editors: Kama 101
No comments
    Log In