Skip to content

Commit 96d1b3f

Browse files
committed
REST API: Restore global post state in WP_REST_Posts_Controller.Ensures that the global $post object is restored to its original state after calling setup_postdata() in prepare_item_for_response(). This fixes a regression where the global context could be 'polluted' during REST API requests.Fixes #43502.
1 parent 4d3b0b9 commit 96d1b3f

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,12 +1886,16 @@ public function prepare_item_for_response( $item, $request ) {
18861886
// Restores the more descriptive, specific name for use within this method.
18871887
$post = $item;
18881888

1889+
$previous_post = isset( $GLOBALS['post'] ) ? $GLOBALS['post'] : null;
18891890
$GLOBALS['post'] = $post;
18901891

18911892
setup_postdata( $post );
18921893

18931894
// Don't prepare the response body for HEAD requests.
18941895
if ( $request->is_method( 'HEAD' ) ) {
1896+
$GLOBALS['post'] = $previous_post;
1897+
wp_reset_postdata();
1898+
18951899
/** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */
18961900
return apply_filters( "rest_prepare_{$this->post_type}", new WP_REST_Response( array() ), $post, $request );
18971901
}
@@ -2207,6 +2211,9 @@ public function prepare_item_for_response( $item, $request ) {
22072211
* @param WP_Post $post Post object.
22082212
* @param WP_REST_Request $request Request object.
22092213
*/
2214+
$GLOBALS['post'] = $previous_post;
2215+
wp_reset_postdata();
2216+
22102217
return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request );
22112218
}
22122219

tests/phpunit/tests/rest-api/rest-posts-controller.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,50 @@ function ( $classes ) {
28052805
$this->assertTrue( array_is_list( $data['class_list'] ), 'Expected class_list to be a list.' );
28062806
}
28072807

2808+
/**
2809+
* @ticket 43502
2810+
*
2811+
* @covers WP_REST_Posts_Controller::prepare_item_for_response
2812+
*/
2813+
public function test_prepare_item_for_response_restores_global_post() {
2814+
$post_1 = self::factory()->post->create_and_get();
2815+
$post_2 = self::factory()->post->create_and_get();
2816+
2817+
// Set up a known global $post state.
2818+
$GLOBALS['post'] = $post_1;
2819+
setup_postdata( $post_1 );
2820+
2821+
$endpoint = new WP_REST_Posts_Controller( 'post' );
2822+
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_2->ID );
2823+
$endpoint->prepare_item_for_response( $post_2, $request );
2824+
2825+
$this->assertSame(
2826+
$post_1->ID,
2827+
$GLOBALS['post']->ID,
2828+
'Global $post should be restored after prepare_item_for_response().'
2829+
);
2830+
}
2831+
2832+
/**
2833+
* @ticket 43502
2834+
*
2835+
* @covers WP_REST_Posts_Controller::prepare_item_for_response
2836+
*/
2837+
public function test_prepare_item_for_response_restores_null_global_post() {
2838+
unset( $GLOBALS['post'] );
2839+
2840+
$post = self::factory()->post->create_and_get();
2841+
2842+
$endpoint = new WP_REST_Posts_Controller( 'post' );
2843+
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post->ID );
2844+
$endpoint->prepare_item_for_response( $post, $request );
2845+
2846+
$this->assertNull(
2847+
$GLOBALS['post'],
2848+
'Global $post should be restored to null when it was not set before prepare_item_for_response().'
2849+
);
2850+
}
2851+
28082852
public function test_create_item() {
28092853
wp_set_current_user( self::$editor_id );
28102854

0 commit comments

Comments
 (0)