diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index cb2cd060dd..fbf11b3ded 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -687,13 +687,13 @@ function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) 'post_status' => 'auto-draft', ), false, - true + false ); $post = get_post( $post_id ); if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) ) { set_post_format( $post, get_option( 'default_post_format' ) ); } - wp_after_insert_post( $post, false ); + wp_after_insert_post( $post, false, null ); // Schedule auto-draft cleanup. if ( ! wp_next_scheduled( 'wp_scheduled_auto_draft_delete' ) ) { diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php index a46b97fa5a..ff433fe5db 100644 --- a/src/wp-includes/class-wp-customize-manager.php +++ b/src/wp-includes/class-wp-customize-manager.php @@ -3105,7 +3105,7 @@ final class WP_Customize_Manager { /** This action is documented in wp-includes/post.php */ do_action( 'wp_insert_post', $post->ID, $post, true ); - wp_after_insert_post( $post, true ); + wp_after_insert_post( get_post( $post_id ), true, $post ); wp_trash_post_comments( $post_id ); diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 05321e73a7..4f9c3f8086 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -3716,6 +3716,7 @@ function wp_insert_post( $postarr, $wp_error = false, $fire_after_hooks = true ) $previous_status = get_post_field( 'post_status', $post_ID ); } else { $previous_status = 'new'; + $post_before = null; } $post_type = empty( $postarr['post_type'] ) ? 'post' : $postarr['post_type']; @@ -4318,7 +4319,7 @@ function wp_insert_post( $postarr, $wp_error = false, $fire_after_hooks = true ) do_action( 'wp_insert_post', $post_ID, $post, $update ); if ( $fire_after_hooks ) { - wp_after_insert_post( $post, $update ); + wp_after_insert_post( $post, $update, $post_before ); } return $post_ID; @@ -4431,6 +4432,8 @@ function wp_publish_post( $post ) { return; } + $post_before = get_post( $post->ID ); + // Ensure at least one term is applied for taxonomies with a default term. foreach ( get_object_taxonomies( $post->post_type, 'object' ) as $taxonomy => $tax_object ) { // Skip taxonomy if no default term is set. @@ -4481,7 +4484,7 @@ function wp_publish_post( $post ) { /** This action is documented in wp-includes/post.php */ do_action( 'wp_insert_post', $post->ID, $post, true ); - wp_after_insert_post( $post, true ); + wp_after_insert_post( $post, true, $post_before ); } /** @@ -4936,10 +4939,12 @@ function wp_transition_post_status( $new_status, $old_status, $post ) { * * @since 5.6.0 * - * @param int|WP_Post $post The post ID or object that has been saved. - * @param bool $update Whether this is an existing post being updated. + * @param int|WP_Post $post The post ID or object that has been saved. + * @param bool $update Whether this is an existing post being updated. + * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior + * to the update for updated posts. */ -function wp_after_insert_post( $post, $update ) { +function wp_after_insert_post( $post, $update, $post_before ) { $post = get_post( $post ); if ( ! $post ) { return; @@ -4952,11 +4957,13 @@ function wp_after_insert_post( $post, $update ) { * * @since 5.6.0 * - * @param int $post_id Post ID. - * @param WP_Post $post Post object. - * @param bool $update Whether this is an existing post being updated. + * @param int $post_id Post ID. + * @param WP_Post $post Post object. + * @param bool $update Whether this is an existing post being updated. + * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior + * to the update for updated posts. */ - do_action( 'wp_after_insert_post', $post_id, $post, $update ); + do_action( 'wp_after_insert_post', $post_id, $post, $update, $post_before ); } // diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index fcbf70f501..3eb0490960 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -191,7 +191,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { */ do_action( 'rest_after_insert_attachment', $attachment, $request, true ); - wp_after_insert_post( $attachment, false ); + wp_after_insert_post( $attachment, false, null ); if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { // Set a custom header with the attachment_id. @@ -321,7 +321,8 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { ); } - $response = parent::update_item( $request ); + $attachment_before = get_post( $request['id'] ); + $response = parent::update_item( $request ); if ( is_wp_error( $response ) ) { return $response; @@ -347,7 +348,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ do_action( 'rest_after_insert_attachment', $attachment, $request, false ); - wp_after_insert_post( $attachment, true ); + wp_after_insert_post( $attachment, true, $attachment_before ); $response = $this->prepare_item_for_response( $attachment, $request ); $response = rest_ensure_response( $response ); diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index c168d8993c..a052d04964 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -677,7 +677,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); - wp_after_insert_post( $post, false ); + wp_after_insert_post( $post, false, null ); $response = $this->prepare_item_for_response( $post, $request ); $response = rest_ensure_response( $response ); @@ -753,7 +753,8 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { return $valid_check; } - $post = $this->prepare_item_for_database( $request ); + $post_before = get_post( $request['id'] ); + $post = $this->prepare_item_for_database( $request ); if ( is_wp_error( $post ) ) { return $post; @@ -830,7 +831,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, false ); - wp_after_insert_post( $post, true ); + wp_after_insert_post( $post, true, $post_before ); $response = $this->prepare_item_for_response( $post, $request ); diff --git a/tests/phpunit/tests/post/wpAfterInsertPost.php b/tests/phpunit/tests/post/wpAfterInsertPost.php new file mode 100644 index 0000000000..d4dc826461 --- /dev/null +++ b/tests/phpunit/tests/post/wpAfterInsertPost.php @@ -0,0 +1,221 @@ +user->create( + array( + 'role' => 'administrator', + 'user_login' => 'administrator', + ) + ); + + self::$post_id = $factory->post->create( + array( + 'post_status' => 'draft', + 'post_title' => '45114 to be updated', + ) + ); + + self::$attachment_id = $factory->attachment->create( + array( + 'post_status' => 'inherit', + 'post_title' => '45114 attachment to be updated', + 'post_parent' => self::$post_id, + ) + ); + } + + public function setUp() { + parent::setUp(); + add_action( 'wp_after_insert_post', array( $this, 'action_wp_after_insert_post' ), 10, 4 ); + } + + public function tearDown() { + self::$passed_post_title = ''; + self::$passed_post_status = ''; + self::$passed_post_before_title = ''; + self::$passed_post_before_status = ''; + parent::tearDown(); + } + + /** + * Helper function to obtain data running on the hook `wp_after_insert_post`. + * + * @param int $post_id Post ID. + * @param WP_Post $post Post object. + * @param bool $update Whether this is an existing post being updated. + * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior + * to the update for updated posts. + */ + function action_wp_after_insert_post( $post_id, $post, $update, $post_before ) { + self::$passed_post_title = $post->post_title; + self::$passed_post_status = $post->post_status; + + if ( null === $post_before ) { + self::$passed_post_before_title = null; + self::$passed_post_before_status = null; + return; + } + + self::$passed_post_before_title = $post_before->post_title; + self::$passed_post_before_status = $post_before->post_status; + + // Prevent this firing when the revision is generated. + remove_action( 'wp_after_insert_post', array( $this, 'action_wp_after_insert_post' ), 10 ); + } + + /** + * Ensure before post is correct when updating a post object. + * + * @ticket 45114 + */ + public function test_update_via_wp_update_post() { + $post = get_post( self::$post_id, ARRAY_A ); + $post['post_title'] = 'new title'; + wp_update_post( $post ); + + $this->assertSame( '45114 to be updated', self::$passed_post_before_title ); + $this->assertSame( 'new title', self::$passed_post_title ); + } + + /** + * Ensure before post is correct when publishing a post object. + * + * @ticket 45114 + */ + public function test_update_via_wp_publish_post() { + wp_publish_post( self::$post_id ); + + $this->assertSame( 'draft', self::$passed_post_before_status ); + $this->assertSame( 'publish', self::$passed_post_status ); + } + + /** + * Ensure before post is correct when inserting a new post. + * + * @ticket 45114 + */ + public function test_new_post_via_wp_insert_post() { + wp_insert_post( + array( + 'post_status' => 'draft', + 'post_title' => 'a new post', + 'post_content' => 'new', + ) + ); + + $this->assertSame( null, self::$passed_post_before_status ); + $this->assertSame( 'a new post', self::$passed_post_title ); + } + + /** + * Ensure before post is correct when updating post via REST API. + * + * @ticket 45114 + */ + public function test_update_via_rest_contoller() { + wp_set_current_user( self::$admin_id ); + $post_id = self::$post_id; + + $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( array( 'title' => 'new title' ) ); + rest_get_server()->dispatch( $request ); + + $this->assertSame( '45114 to be updated', self::$passed_post_before_title ); + $this->assertSame( 'new title', self::$passed_post_title ); + } + + /** + * Ensure before post is correct when creating post via REST API. + * + * @ticket 45114 + */ + public function test_new_post_via_rest_contoller() { + wp_set_current_user( self::$admin_id ); + + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts' ) ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( + array( + 'title' => 'new title', + 'status' => 'draft', + ) + ); + rest_get_server()->dispatch( $request ); + + $this->assertSame( null, self::$passed_post_before_title ); + $this->assertSame( 'new title', self::$passed_post_title ); + } + + /** + * Ensure before post is correct when updating post via REST API. + * + * @ticket 45114 + */ + public function test_update_attachment_via_rest_contoller() { + wp_set_current_user( self::$admin_id ); + $attachment_id = self::$attachment_id; + + $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/media/%d', $attachment_id ) ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( array( 'title' => 'new attachment title' ) ); + rest_get_server()->dispatch( $request ); + + $this->assertSame( '45114 attachment to be updated', self::$passed_post_before_title ); + $this->assertSame( 'new attachment title', self::$passed_post_title ); + } +}