Ticket #43316: 43316.diff
File 43316.diff, 16.9 KB (added by , 7 years ago) |
---|
-
src/wp-includes/js/wp-api.js
diff --git src/wp-includes/js/wp-api.js src/wp-includes/js/wp-api.js index d796ddc475..35fcb5c5d1 100644
287 287 * @param {Object} loadingObjects An object containing the models and collections we are building. 288 288 */ 289 289 wp.api.utils.addMixinsAndHelpers = function( model, modelClassName, loadingObjects ) { 290 291 290 var hasDate = false, 292 291 292 /** 293 * Specify the models that save autosaves. 294 */ 295 canSaveAutosaves = wpApiSettings.canSaveAutosaves || 296 [ 'Post', 'Page' ], 297 298 /** 299 * Specify the models that retrieve autosaves. 300 */ 301 canRetrieveAutosaves = wpApiSettings.canRetrieveAutosaves || 302 [ 'PostRevision', 'PageRevision' ], 303 293 304 /** 294 305 * Array of parseable dates. 295 306 * … … 741 752 getFeaturedMedia: function() { 742 753 return buildModelGetter( this, this.get( 'featured_media' ), 'Media', 'wp:featuredmedia', 'source_url' ); 743 754 } 755 }, 756 757 /** 758 * Add a helper to enable saving autosaves. 759 */ 760 autosaveMixin = { 761 autosave: function() { 762 return this.save( { is_autosave: true } ); 763 } 764 }, 765 766 /** 767 * Add a helper to enable retrieving autosaves. 768 */ 769 getAutosaveMixin = { 770 getAutosave: function() { 771 return this.fetch( { data: { is_autosave: true } } ); 772 } 744 773 }; 745 774 775 // Add Autosaving for specific models 776 if ( _.indexOf( canSaveAutosaves, modelClassName ) >= 0 ) { 777 model = model.extend( autosaveMixin ); 778 } 779 780 // Add Autosaving for specific models 781 if ( _.indexOf( canRetrieveAutosaves, modelClassName ) >= 0 ) { 782 model = model.extend( getAutosaveMixin ); 783 } 784 746 785 // Exit if we don't have valid model defaults. 747 786 if ( _.isUndefined( model.prototype.args ) ) { 748 787 return model; -
src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php
diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 0661152de6..05f27713b5 100644
class WP_REST_Posts_Controller extends WP_REST_Controller { 657 657 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 658 658 */ 659 659 public function update_item( $request ) { 660 $ valid_check= $this->get_post( $request['id'] );661 if ( is_wp_error( $ valid_check) ) {662 return $ valid_check;660 $existing_post = $this->get_post( $request['id'] ); 661 if ( is_wp_error( $existing_post ) ) { 662 return $existing_post; 663 663 } 664 664 665 $ post = $this->prepare_item_for_database( $request );665 $new_post = $this->prepare_item_for_database( $request ); 666 666 667 if ( is_wp_error( $ post ) ) {668 return $ post;667 if ( is_wp_error( $new_post ) ) { 668 return $new_post; 669 669 } 670 670 671 // convert the post object to an array, otherwise wp_update_post will expect non-escaped input. 672 $post_id = wp_update_post( wp_slash( (array) $post ), true ); 671 // Keep the ID for later. 672 $post_id = $new_post->ID; 673 674 // The following functions expect array. 675 $post_data = get_object_vars( $new_post ); 676 677 // Autosave 678 if ( ! empty( $request['is_autosave'] ) ) { 679 if ( ! defined( 'DOING_AUTOSAVE' ) ) { 680 define( 'DOING_AUTOSAVE', true ); 681 } 682 683 $post_author = get_current_user_id(); 684 $autosave_id = 0; 685 686 // Also needs to check post lock. 687 if ( $post_author == $existing_post->post_author && ( 'auto-draft' === $existing_post->post_status || 'draft' === $existing_post->post_status ) ) { 688 // Drafts and auto-drafts are just overwritten by autosave for the same user. 689 // Expects escaped input when array. 690 $post_id = wp_update_post( wp_slash( $post_data ), true ); 691 } else { 692 // Store one autosave per author. If there is already an autosave, update it. 693 if ( $old_autosave = wp_get_post_autosave( $post_data['ID'], $post_author ) ) { 694 $new_autosave = _wp_post_revision_data( $post_data, true ); 695 $new_autosave['ID'] = $old_autosave->ID; 696 $new_autosave['post_author'] = $post_author; 697 698 // If the new autosave has the same content as the post, delete the autosave. 699 $autosave_is_different = false; 700 701 foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $existing_post ) ) ) as $field ) { 702 if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $existing_post->$field ) ) { 703 $autosave_is_different = true; 704 break; 705 } 706 } 707 708 if ( ! $autosave_is_different ) { 709 wp_delete_post_revision( $old_autosave->ID ); 710 } else { 711 /** 712 * Fires before an autosave is stored via the REST API. 713 * 714 * @since 5.0.0 715 * 716 * @param array $new_autosave Post array - the autosave that is about to be saved. 717 * @param WP_REST_Request $request Request object. 718 */ 719 do_action( 'rest_creating_autosave', $new_autosave, $request ); 720 721 $autosave_id = wp_update_post( $new_autosave ); 722 } 723 } else { 724 // Need to merge the autosave data with some of the existing post data. 725 foreach ( array_keys( _wp_post_revision_fields( $existing_post ) ) as $field ) { 726 if ( empty( $post_data[ $field ] ) ) { 727 $post_data[ $field ] = $existing_post->$field; 728 } 729 } 730 731 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ 732 do_action( 'rest_creating_autosave', $post_data, $request ); 733 734 $autosave_id = _wp_put_post_revision( $post_data, true ); 735 } 736 737 if ( is_wp_error( $autosave_id ) ) { 738 // Pass on the error. 739 $post_id = $autosave_id; 740 } 741 } 742 } else { 743 // Expects escaped input when array. 744 $post_id = wp_update_post( wp_slash( $post_data ), true ); 745 } 673 746 674 747 if ( is_wp_error( $post_id ) ) { 675 748 if ( 'db_update_error' === $post_id->get_error_code() ) { -
src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
diff --git src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php index 471c4c4b4f..8caaa43bfb 100644
class WP_REST_Revisions_Controller extends WP_REST_Controller { 187 187 return $revision; 188 188 } 189 189 190 /** 191 * Get autosave revision if it exists. 192 * 193 * @since 5.0.0 194 * 195 * @param WP_REST_Request $request Full data about the request. 196 * @return WP_Post|WP_Error Revision post object if post autosave exists, WP_Error otherwise. 197 */ 198 protected function get_autosave( $request ) { 199 $parent = $this->get_parent( $request['parent'] ); 200 if ( is_wp_error( $parent ) ) { 201 return $parent; 202 } 203 204 $user_id = 0; 205 206 if ( ! empty( $request['author'] ) ) { 207 $post_author = (int) $request['author']; 208 $user_obj = get_userdata( $post_author ); 209 210 if ( ! $user_obj ) { 211 return new WP_Error( 'rest_invalid_author', __( 'Invalid author ID.' ), array( 'status' => 400 ) ); 212 } else { 213 $user_id = $post_author; 214 } 215 } 216 217 $revision = wp_get_post_autosave( $parent->ID, $user_id ); 218 if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) { 219 return new WP_Error( 'rest_post_no_autosave', __( 'Autosave does not exist.' ), array( 'status' => 404 ) ); 220 } 221 222 return $revision; 223 } 224 190 225 /** 191 226 * Gets a collection of revisions. 192 227 * … … class WP_REST_Revisions_Controller extends WP_REST_Controller { 201 236 return $parent; 202 237 } 203 238 204 $revisions = wp_get_post_revisions( $request['parent'] ); 239 $revisions = wp_get_post_revisions( $parent->ID ); 240 241 if ( ! empty( $request['is_autosave'] ) ) { 242 foreach ( $revisions as $revision_id => $revision ) { 243 if ( ! wp_is_post_autosave( $revision ) ) { 244 unset( $revisions[ $revision_id ] ); 245 } 246 } 247 } 205 248 206 249 $response = array(); 207 250 foreach ( $revisions as $revision ) { … … class WP_REST_Revisions_Controller extends WP_REST_Controller { 237 280 return $parent; 238 281 } 239 282 240 $revision = $this->get_revision( $request['id'] ); 283 if ( ! empty( $request['is_autosave'] ) ) { 284 $revision = $this->get_autosave( $request ); 285 } else { 286 $revision = $this->get_revision( $request['id'] ); 287 } 288 241 289 if ( is_wp_error( $revision ) ) { 242 290 return $revision; 243 291 } -
tests/phpunit/tests/rest-api/rest-posts-controller.php
diff --git tests/phpunit/tests/rest-api/rest-posts-controller.php tests/phpunit/tests/rest-api/rest-posts-controller.php index bc820a8796..30f4378e5a 100644
class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te 2363 2363 $this->assertEquals( $params['excerpt'], $post->post_excerpt ); 2364 2364 } 2365 2365 2366 public function test_rest_autosave_published_post() { 2367 wp_set_current_user( self::$editor_id ); 2368 2369 $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) ); 2370 $request->add_header( 'content-type', 'application/json' ); 2371 2372 $autosave_data = $this->set_post_data( 2373 array( 2374 'id' => self::$post_id, 2375 'is_autosave' => true, 2376 'content' => 'Updated post content', 2377 ) 2378 ); 2379 2380 $request->set_body( wp_json_encode( $autosave_data ) ); 2381 $response = $this->server->dispatch( $request ); 2382 2383 $this->check_update_post_response( $response ); 2384 $new_data = $response->get_data(); 2385 2386 // The published post shouldn't change. 2387 $current_post = get_post( self::$post_id ); 2388 $this->assertEquals( $current_post->ID, $new_data['id'] ); 2389 $this->assertEquals( $current_post->post_title, $new_data['title']['raw'] ); 2390 $this->assertEquals( $current_post->post_content, $new_data['content']['raw'] ); 2391 $this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] ); 2392 2393 $autosave_post = wp_get_post_autosave( self::$post_id ); 2394 $this->assertEquals( $autosave_data['title'], $autosave_post->post_title ); 2395 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 2396 $this->assertEquals( $autosave_data['excerpt'], $autosave_post->post_excerpt ); 2397 } 2398 2399 public function test_rest_autosave_draft_post_same_author() { 2400 wp_set_current_user( self::$editor_id ); 2401 2402 $post_data = array( 2403 'post_content' => 'Test post content', 2404 'post_title' => 'Test post title', 2405 'post_excerpt' => 'Test post excerpt', 2406 ); 2407 $post_id = wp_insert_post( $post_data ); 2408 2409 $autosave_data = array( 2410 'id' => $post_id, 2411 'is_autosave' => true, 2412 'content' => 'Updated post content', 2413 ); 2414 2415 $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) ); 2416 $request->add_header( 'content-type', 'application/json' ); 2417 $request->set_body( wp_json_encode( $autosave_data ) ); 2418 $response = $this->server->dispatch( $request ); 2419 2420 $this->check_update_post_response( $response ); 2421 $new_data = $response->get_data(); 2422 2423 // The draft post should be updated. 2424 $this->assertEquals( $post_id, $new_data['id'] ); 2425 $this->assertEquals( $autosave_data['content'], $new_data['content']['raw'] ); 2426 2427 $post = get_post( $post_id ); 2428 $this->assertEquals( $post_data['post_title'], $post->post_title ); 2429 $this->assertEquals( $autosave_data['content'], $post->post_content ); 2430 $this->assertEquals( $post_data['post_excerpt'], $post->post_excerpt ); 2431 2432 wp_delete_post( $post_id ); 2433 } 2434 2435 public function test_rest_autosave_draft_post_different_author() { 2436 wp_set_current_user( self::$editor_id ); 2437 2438 $post_data = array( 2439 'post_content' => 'Test post content', 2440 'post_title' => 'Test post title', 2441 'post_excerpt' => 'Test post excerpt', 2442 'post_author' => ++self::$editor_id, 2443 ); 2444 $post_id = wp_insert_post( $post_data ); 2445 2446 $autosave_data = array( 2447 'id' => $post_id, 2448 'is_autosave' => true, 2449 'content' => 'Updated post content', 2450 ); 2451 2452 $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) ); 2453 $request->add_header( 'content-type', 'application/json' ); 2454 $request->set_body( wp_json_encode( $autosave_data ) ); 2455 $response = $this->server->dispatch( $request ); 2456 2457 $this->check_update_post_response( $response ); 2458 $new_data = $response->get_data(); 2459 2460 2461 // The draft post shouldn't change. 2462 $current_post = get_post( $post_id ); 2463 $this->assertEquals( $current_post->ID, $new_data['id'] ); 2464 $this->assertEquals( $current_post->post_title, $new_data['title']['raw'] ); 2465 $this->assertEquals( $current_post->post_content, $new_data['content']['raw'] ); 2466 $this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] ); 2467 2468 $autosave_post = wp_get_post_autosave( $post_id ); 2469 // No changes 2470 $this->assertEquals( $current_post->post_title, $autosave_post->post_title ); 2471 $this->assertEquals( $current_post->post_excerpt, $autosave_post->post_excerpt ); 2472 2473 // Has changes 2474 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 2475 2476 wp_delete_post( $post_id ); 2477 } 2478 2366 2479 public function test_rest_update_post_raw() { 2367 2480 wp_set_current_user( self::$editor_id ); 2368 2481 -
tests/phpunit/tests/rest-api/rest-revisions-controller.php
diff --git tests/phpunit/tests/rest-api/rest-revisions-controller.php tests/phpunit/tests/rest-api/rest-revisions-controller.php index c30ab17c85..11576889d4 100644
class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase 44 44 'ID' => self::$post_id, 45 45 ) 46 46 ); 47 48 // Autosave, different user 49 wp_set_current_user( self::$contributor_id ); 50 _wp_put_post_revision( 51 array( 52 'post_content' => 'This content is better autosaved.', 53 'ID' => self::$post_id, 54 ), 55 true 56 ); 47 57 wp_set_current_user( 0 ); 48 58 } 49 59 … … class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase 64 74 $this->revision_id1 = $this->revision_1->ID; 65 75 $this->revision_2 = array_pop( $revisions ); 66 76 $this->revision_id2 = $this->revision_2->ID; 77 $this->revision_3 = array_pop( $revisions ); 78 $this->revision_id3 = $this->revision_3->ID; 67 79 } 68 80 69 81 public function test_register_routes() { … … class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase 95 107 $response = rest_get_server()->dispatch( $request ); 96 108 $data = $response->get_data(); 97 109 $this->assertEquals( 200, $response->get_status() ); 98 $this->assertCount( 2, $data );110 $this->assertCount( 3, $data ); 99 111 100 112 // Reverse chron 101 $this->assertEquals( $this->revision_id2, $data[0]['id'] ); 102 $this->check_get_revision_response( $data[0], $this->revision_2 ); 113 $this->assertEquals( $this->revision_id3, $data[0]['id'] ); 114 $this->check_get_revision_response( $data[0], $this->revision_3 ); 115 116 $this->assertEquals( $this->revision_id2, $data[1]['id'] ); 117 $this->check_get_revision_response( $data[1], $this->revision_2 ); 103 118 104 $this->assertEquals( $this->revision_id1, $data[ 1]['id'] );105 $this->check_get_revision_response( $data[ 1], $this->revision_1 );119 $this->assertEquals( $this->revision_id1, $data[2]['id'] ); 120 $this->check_get_revision_response( $data[2], $this->revision_1 ); 106 121 } 107 122 108 123 public function test_get_items_no_permission() { … … class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase 155 170 $this->assertSame( self::$editor_id, $data['author'] ); 156 171 } 157 172 173 public function test_get_autosave_item() { 174 wp_set_current_user( self::$editor_id ); 175 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id3 ); 176 $request->set_param( 'is_autosave', true ); 177 $response = rest_get_server()->dispatch( $request ); 178 179 $this->assertEquals( 200, $response->get_status() ); 180 $data = $response->get_data(); 181 182 $this->assertNotEquals( self::$editor_id, $data['author'] ); 183 $this->assertEquals( $this->revision_id3, $data['id'] ); 184 $this->check_get_revision_response( $response, $this->revision_3 ); 185 } 186 158 187 public function test_get_item_embed_context() { 159 188 wp_set_current_user( self::$editor_id ); 160 189 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/revisions/' . $this->revision_id1 ); … … class WP_Test_REST_Revisions_Controller extends WP_Test_REST_Controller_Testcase 330 359 $this->assertEquals( mysql_to_rfc3339( $revision->post_date ), $response['date'] ); 331 360 $this->assertEquals( mysql_to_rfc3339( $revision->post_date_gmt ), $response['date_gmt'] ); 332 361 333 $rendered_excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $revision->post_excerpt, $revision ) ); 334 $this->assertEquals( $rendered_excerpt, $response['excerpt']['rendered'] ); 362 if ( ! empty( $revision->post_excerpt ) ) { 363 $rendered_excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $revision->post_excerpt, $revision ) ); 364 $this->assertEquals( $rendered_excerpt, $response['excerpt']['rendered'] ); 365 } 335 366 336 367 $rendered_guid = apply_filters( 'get_the_guid', $revision->guid, $revision->ID ); 337 368 $this->assertEquals( $rendered_guid, $response['guid']['rendered'] );