Ticket #43316: 43316.18.diff
File 43316.18.diff, 51.9 KB (added by , 6 years ago) |
---|
-
src/wp-includes/rest-api.php
diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 82d856a063..0bb1bce426 100644
a b function create_initial_rest_routes() { 189 189 190 190 $controller->register_routes(); 191 191 192 if ( 'attachment' !== $post_type->name ) { 193 $controller = new WP_REST_Autosaves_Controller( $post_type->name ); 194 $controller->register_routes(); 195 } 196 192 197 if ( post_type_supports( $post_type->name, 'revisions' ) ) { 193 198 $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name ); 194 199 $revisions_controller->register_routes(); -
new file src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php new file mode 100644 index 0000000000..fe15b3f3f3
- + 1 <?php 2 /** 3 * REST API: WP_REST_Autosaves_Controller class. 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 5.0.0 8 */ 9 10 /** 11 * Core class used to access autosaves via the REST API. 12 * 13 * @since 5.0.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { 18 19 /** 20 * Parent post type. 21 * 22 * @since 5.0.0 23 * @var string 24 */ 25 private $parent_post_type; 26 27 /** 28 * Parent post controller. 29 * 30 * @since 5.0.0 31 * @var WP_REST_Controller 32 */ 33 private $parent_controller; 34 35 /** 36 * Revision controller. 37 * 38 * @since 5.0.0 39 * @var WP_REST_Controller 40 */ 41 private $revisions_controller; 42 43 /** 44 * The base of the parent controller's route. 45 * 46 * @since 5.0.0 47 * @var string 48 */ 49 private $parent_base; 50 51 /** 52 * Constructor. 53 * 54 * @since 5.0.0 55 * 56 * @param string $parent_post_type Post type of the parent. 57 */ 58 public function __construct( $parent_post_type ) { 59 $this->parent_post_type = $parent_post_type; 60 $post_type_object = get_post_type_object( $parent_post_type ); 61 62 // Ensure that post type-specific controller logic is available. 63 $parent_controller_class = ! empty( $post_type_object->rest_controller_class ) ? $post_type_object->rest_controller_class : 'WP_REST_Posts_Controller'; 64 65 $this->parent_controller = new $parent_controller_class( $post_type_object->name ); 66 $this->revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); 67 $this->rest_namespace = 'wp/v2'; 68 $this->rest_base = 'autosaves'; 69 $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; 70 } 71 72 /** 73 * Registers routes for autosaves. 74 * 75 * @since 5.0.0 76 * 77 * @see register_rest_route() 78 */ 79 public function register_routes() { 80 register_rest_route( 81 $this->rest_namespace, 82 '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base, 83 array( 84 'args' => array( 85 'parent' => array( 86 'description' => __( 'The ID for the parent of the object.', 'gutenberg' ), 87 'type' => 'integer', 88 ), 89 ), 90 array( 91 'methods' => WP_REST_Server::READABLE, 92 'callback' => array( $this, 'get_items' ), 93 'permission_callback' => array( $this->revisions_controller, 'get_items_permissions_check' ), 94 'args' => $this->get_collection_params(), 95 ), 96 array( 97 'methods' => WP_REST_Server::CREATABLE, 98 'callback' => array( $this, 'create_item' ), 99 'permission_callback' => array( $this, 'create_item_permissions_check' ), 100 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), 101 ), 102 'schema' => array( $this, 'get_public_item_schema' ), 103 ) 104 ); 105 106 register_rest_route( 107 $this->rest_namespace, 108 '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', 109 array( 110 'args' => array( 111 'parent' => array( 112 'description' => __( 'The ID for the parent of the object.', 'gutenberg' ), 113 'type' => 'integer', 114 ), 115 'id' => array( 116 'description' => __( 'The ID for the object.', 'gutenberg' ), 117 'type' => 'integer', 118 ), 119 ), 120 array( 121 'methods' => WP_REST_Server::READABLE, 122 'callback' => array( $this, 'get_item' ), 123 'permission_callback' => array( $this->revisions_controller, 'get_item_permissions_check' ), 124 'args' => array( 125 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 126 ), 127 ), 128 'schema' => array( $this, 'get_public_item_schema' ), 129 ) 130 ); 131 132 } 133 134 /** 135 * Get the parent post. 136 * 137 * @since 5.0.0 138 * 139 * @param int $parent_id Supplied ID. 140 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. 141 */ 142 protected function get_parent( $parent_id ) { 143 return $this->revisions_controller->get_parent( $parent_id ); 144 } 145 146 /** 147 * Checks if a given request has access to create an autosave revision. 148 * 149 * Autosave revisions inherit permissions from the parent post, 150 * check if the current user has permission to edit the post. 151 * 152 * @since 5.0.0 153 * 154 * @param WP_REST_Request $request Full details about the request. 155 * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. 156 */ 157 public function create_item_permissions_check( $request ) { 158 $id = $request->get_param( 'id' ); 159 if ( empty( $id ) ) { 160 return new WP_Error( 'rest_post_invalid_id', __( 'Invalid item ID.', 'gutenberg' ), array( 'status' => 404 ) ); 161 } 162 163 return $this->parent_controller->update_item_permissions_check( $request ); 164 } 165 166 /** 167 * Creates, updates or deletes an autosave revision. 168 * 169 * @since 5.0.0 170 * 171 * @param WP_REST_Request $request Full details about the request. 172 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 173 */ 174 public function create_item( $request ) { 175 176 if ( ! defined( 'DOING_AUTOSAVE' ) ) { 177 define( 'DOING_AUTOSAVE', true ); 178 } 179 180 $post = get_post( $request->get_param( 'id' ) ); 181 182 if ( is_wp_error( $post ) ) { 183 return $post; 184 } 185 186 $prepared_post = $this->parent_controller->prepare_item_for_database( $request ); 187 $prepared_post->ID = $post->ID; 188 $user_id = get_current_user_id(); 189 190 if ( ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status ) && $post->post_author == $user_id ) { 191 // Draft posts for the same author: autosaving updates the post and does not create a revision. 192 // Convert the post object to an array and add slashes, wp_update_post expects escaped array. 193 $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true ); 194 } else { 195 // Non-draft posts: create or update the post autosave. 196 $autosave_id = $this->create_post_autosave( (array) $prepared_post ); 197 } 198 199 if ( is_wp_error( $autosave_id ) ) { 200 return $autosave_id; 201 } 202 203 $autosave = get_post( $autosave_id ); 204 $request->set_param( 'context', 'edit' ); 205 206 $response = $this->prepare_item_for_response( $autosave, $request ); 207 $response = rest_ensure_response( $response ); 208 209 return $response; 210 } 211 212 /** 213 * Get the autosave, if the ID is valid. 214 * 215 * @since 5.0.0 216 * 217 * @param WP_REST_Request $request Full data about the request. 218 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. 219 */ 220 public function get_item( $request ) { 221 $parent_id = (int) $request->get_param( 'parent' ); 222 223 if ( $parent_id <= 0 ) { 224 return new WP_Error( 'rest_post_invalid_id', __( 'Invalid parent post ID.', 'gutenberg' ), array( 'status' => 404 ) ); 225 } 226 227 $autosave = wp_get_post_autosave( $parent_id ); 228 229 if ( ! $autosave ) { 230 return new WP_Error( 'rest_post_no_autosave', __( 'There is no autosave revision for this post.', 'gutenberg' ), array( 'status' => 404 ) ); 231 } 232 233 $response = $this->prepare_item_for_response( $autosave, $request ); 234 return $response; 235 } 236 237 /** 238 * Gets a collection of autosaves using wp_get_post_autosave. 239 * 240 * Contains the user's autosave, for empty if it doesn't exist. 241 * 242 * @since 5.0.0 243 * 244 * @param WP_REST_Request $request Full data about the request. 245 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 246 */ 247 public function get_items( $request ) { 248 $parent = $this->get_parent( $request->get_param( 'parent' ) ); 249 if ( is_wp_error( $parent ) ) { 250 return $parent; 251 } 252 253 $response = array(); 254 $parent_id = $parent->ID; 255 $revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) ); 256 257 foreach ( $revisions as $revision ) { 258 if ( false !== strpos( $revision->post_name, "{$parent_id}-autosave" ) ) { 259 $data = $this->prepare_item_for_response( $revision, $request ); 260 $response[] = $this->prepare_response_for_collection( $data ); 261 } 262 } 263 264 return rest_ensure_response( $response ); 265 } 266 267 268 /** 269 * Retrieves the autosave's schema, conforming to JSON Schema. 270 * 271 * @since 5.0.0 272 * 273 * @return array Item schema data. 274 */ 275 public function get_item_schema() { 276 $schema = $this->revisions_controller->get_item_schema(); 277 278 $schema['properties']['preview_link'] = array( 279 'description' => __( 'Preview link for the post.', 'gutenberg' ), 280 'type' => 'string', 281 'format' => 'uri', 282 'context' => array( 'edit' ), 283 'readonly' => true, 284 ); 285 286 return $schema; 287 } 288 289 /** 290 * Creates autosave for the specified post. 291 * 292 * From wp-admin/post.php. 293 * 294 * @since 5.0.0 295 * 296 * @param mixed $post_data Associative array containing the post data. 297 * @return mixed The autosave revision ID or WP_Error. 298 */ 299 public function create_post_autosave( $post_data ) { 300 301 $post_id = (int) $post_data['ID']; 302 $post = get_post( $post_id ); 303 304 if ( is_wp_error( $post ) ) { 305 return $post; 306 } 307 308 $user_id = get_current_user_id(); 309 310 // Store one autosave per author. If there is already an autosave, overwrite it. 311 $old_autosave = wp_get_post_autosave( $post_id, $user_id ); 312 313 if ( $old_autosave ) { 314 $new_autosave = _wp_post_revision_data( $post_data, true ); 315 $new_autosave['ID'] = $old_autosave->ID; 316 $new_autosave['post_author'] = $user_id; 317 318 // If the new autosave has the same content as the post, delete the autosave. 319 $autosave_is_different = false; 320 321 foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) { 322 if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) { 323 $autosave_is_different = true; 324 break; 325 } 326 } 327 328 if ( ! $autosave_is_different ) { 329 wp_delete_post_revision( $old_autosave->ID ); 330 return new WP_Error( 'rest_autosave_no_changes', __( 'There is nothing to save. The autosave and the post content are the same.', 'gutenberg' ), array( 'status' => 400 ) ); 331 } 332 333 /** 334 * This filter is documented in wp-admin/post.php. 335 */ 336 do_action( 'wp_creating_autosave', $new_autosave ); 337 338 // wp_update_post expects escaped array. 339 return wp_update_post( wp_slash( $new_autosave ) ); 340 } 341 342 // Create the new autosave as a special post revision. 343 return _wp_put_post_revision( $post_data, true ); 344 } 345 346 /** 347 * Prepares the revision for the REST response. 348 * 349 * @since 5.0.0 350 * 351 * @param WP_Post $post Post revision object. 352 * @param WP_REST_Request $request Request object. 353 * 354 * @return WP_REST_Response Response object. 355 */ 356 public function prepare_item_for_response( $post, $request ) { 357 358 $response = $this->revisions_controller->prepare_item_for_response( $post, $request ); 359 360 $schema = $this->get_item_schema(); 361 362 if ( ! empty( $schema['properties']['preview_link'] ) ) { 363 $parent_id = wp_is_post_autosave( $post ); 364 $preview_post_id = false === $parent_id ? $post->ID : $parent_id; 365 $preview_query_args = array(); 366 367 if ( false !== $parent_id ) { 368 $preview_query_args['preview_id'] = $parent_id; 369 $preview_query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $parent_id ); 370 } 371 372 $response->data['preview_link'] = get_preview_post_link( $preview_post_id, $preview_query_args ); 373 } 374 375 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 376 $response->data = $this->filter_response_by_context( $response->data, $context ); 377 378 /** 379 * Filters a revision returned from the API. 380 * 381 * Allows modification of the revision right before it is returned. 382 * 383 * @since 5.0.0 384 * 385 * @param WP_REST_Response $response The response object. 386 * @param WP_Post $post The original revision object. 387 * @param WP_REST_Request $request Request used to generate the response. 388 */ 389 return apply_filters( 'rest_prepare_autosave', $response, $post, $request ); 390 } 391 } -
src/wp-settings.php
diff --git a/src/wp-settings.php b/src/wp-settings.php index bacf4cfddd..f4f2ba0d88 100644
a b require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-attachments-contro 229 229 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-types-controller.php' ); 230 230 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-statuses-controller.php' ); 231 231 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-revisions-controller.php' ); 232 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-autosaves-controller.php' ); 232 233 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-taxonomies-controller.php' ); 233 234 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.php' ); 234 235 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); -
new file tests/phpunit/tests/rest-api/rest-autosaves-controller.php
diff --git a/tests/phpunit/tests/rest-api/rest-autosaves-controller.php b/tests/phpunit/tests/rest-api/rest-autosaves-controller.php new file mode 100644 index 0000000000..4b02fe2ec4
- + 1 <?php 2 /** 3 * Unit tests covering WP_REST_Autosaves_Controller functionality. 4 * 5 * @package WordPress 6 * @subpackage REST API 7 */ 8 9 /** 10 * @group restapi-autosave 11 * @group restapi 12 */ 13 class WP_Test_REST_Autosaves_Controller extends WP_Test_REST_Post_Type_Controller_Testcase { 14 protected static $post_id; 15 protected static $page_id; 16 17 protected static $autosave_post_id; 18 protected static $autosave_page_id; 19 20 protected static $editor_id; 21 protected static $contributor_id; 22 23 protected function set_post_data( $args = array() ) { 24 $defaults = array( 25 'title' => 'Post Title', 26 'content' => 'Post content', 27 'excerpt' => 'Post excerpt', 28 'name' => 'test', 29 'author' => get_current_user_id(), 30 ); 31 32 return wp_parse_args( $args, $defaults ); 33 } 34 35 protected function check_create_autosave_response( $response ) { 36 $this->assertNotInstanceOf( 'WP_Error', $response ); 37 $response = rest_ensure_response( $response ); 38 $data = $response->get_data(); 39 40 $this->assertArrayHasKey( 'content', $data ); 41 $this->assertArrayHasKey( 'excerpt', $data ); 42 $this->assertArrayHasKey( 'title', $data ); 43 } 44 45 public static function wpSetUpBeforeClass( $factory ) { 46 self::$post_id = $factory->post->create(); 47 self::$page_id = $factory->post->create( array( 'post_type' => 'page' ) ); 48 49 self::$editor_id = $factory->user->create( 50 array( 51 'role' => 'editor', 52 ) 53 ); 54 self::$contributor_id = $factory->user->create( 55 array( 56 'role' => 'contributor', 57 ) 58 ); 59 60 wp_set_current_user( self::$editor_id ); 61 62 // Create an autosave. 63 self::$autosave_post_id = wp_create_post_autosave( 64 array( 65 'post_content' => 'This content is better.', 66 'post_ID' => self::$post_id, 67 'post_type' => 'post', 68 ) 69 ); 70 71 self::$autosave_page_id = wp_create_post_autosave( 72 array( 73 'post_content' => 'This content is better.', 74 'post_ID' => self::$page_id, 75 'post_type' => 'post', 76 ) 77 ); 78 79 } 80 81 public static function wpTearDownAfterClass() { 82 // Also deletes revisions. 83 wp_delete_post( self::$post_id, true ); 84 wp_delete_post( self::$page_id, true ); 85 86 self::delete_user( self::$editor_id ); 87 self::delete_user( self::$contributor_id ); 88 } 89 90 public function setUp() { 91 parent::setUp(); 92 wp_set_current_user( self::$editor_id ); 93 94 $this->post_autosave = wp_get_post_autosave( self::$post_id ); 95 } 96 97 public function test_register_routes() { 98 $routes = rest_get_server()->get_routes(); 99 $this->assertArrayHasKey( '/wp/v2/posts/(?P<parent>[\d]+)/autosaves', $routes ); 100 $this->assertArrayHasKey( '/wp/v2/posts/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)', $routes ); 101 $this->assertArrayHasKey( '/wp/v2/pages/(?P<parent>[\d]+)/autosaves', $routes ); 102 $this->assertArrayHasKey( '/wp/v2/pages/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)', $routes ); 103 } 104 105 public function test_context_param() { 106 // Collection 107 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 108 $response = rest_get_server()->dispatch( $request ); 109 $data = $response->get_data(); 110 $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] ); 111 $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] ); 112 // Single 113 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 114 $response = rest_get_server()->dispatch( $request ); 115 $data = $response->get_data(); 116 $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] ); 117 $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] ); } 118 119 public function test_get_items() { 120 wp_set_current_user( self::$editor_id ); 121 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 122 $response = rest_get_server()->dispatch( $request ); 123 $data = $response->get_data(); 124 $this->assertEquals( 200, $response->get_status() ); 125 $this->assertCount( 1, $data ); 126 127 $this->assertEquals( self::$autosave_post_id, $data[0]['id'] ); 128 129 $this->check_get_autosave_response( $data[0], $this->post_autosave ); 130 } 131 132 public function test_get_items_no_permission() { 133 wp_set_current_user( 0 ); 134 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 135 $response = rest_get_server()->dispatch( $request ); 136 $this->assertErrorResponse( 'rest_cannot_read', $response, 401 ); 137 wp_set_current_user( self::$contributor_id ); 138 $response = rest_get_server()->dispatch( $request ); 139 $this->assertErrorResponse( 'rest_cannot_read', $response, 403 ); 140 } 141 142 public function test_get_items_missing_parent() { 143 wp_set_current_user( self::$editor_id ); 144 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves' ); 145 $response = rest_get_server()->dispatch( $request ); 146 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 147 } 148 149 public function test_get_items_invalid_parent_post_type() { 150 wp_set_current_user( self::$editor_id ); 151 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' ); 152 $response = rest_get_server()->dispatch( $request ); 153 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 154 } 155 156 public function test_get_item() { 157 wp_set_current_user( self::$editor_id ); 158 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 159 $response = rest_get_server()->dispatch( $request ); 160 $this->assertEquals( 200, $response->get_status() ); 161 $data = $response->get_data(); 162 163 $this->check_get_autosave_response( $response, $this->post_autosave ); 164 $fields = array( 165 'author', 166 'date', 167 'date_gmt', 168 'modified', 169 'modified_gmt', 170 'guid', 171 'id', 172 'parent', 173 'slug', 174 'title', 175 'excerpt', 176 'content', 177 ); 178 $this->assertEqualSets( $fields, array_keys( $data ) ); 179 $this->assertSame( self::$editor_id, $data['author'] ); 180 } 181 182 public function test_get_item_embed_context() { 183 wp_set_current_user( self::$editor_id ); 184 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 185 $request->set_param( 'context', 'embed' ); 186 $response = rest_get_server()->dispatch( $request ); 187 $fields = array( 188 'author', 189 'date', 190 'id', 191 'parent', 192 'slug', 193 'title', 194 'excerpt', 195 ); 196 $data = $response->get_data(); 197 $this->assertEqualSets( $fields, array_keys( $data ) ); 198 } 199 200 public function test_get_item_no_permission() { 201 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 202 wp_set_current_user( self::$contributor_id ); 203 $response = rest_get_server()->dispatch( $request ); 204 $this->assertErrorResponse( 'rest_cannot_read', $response, 403 ); 205 } 206 207 public function test_get_item_missing_parent() { 208 wp_set_current_user( self::$editor_id ); 209 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves/' . self::$autosave_post_id ); 210 $response = rest_get_server()->dispatch( $request ); 211 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 212 213 } 214 215 public function test_get_item_invalid_parent_post_type() { 216 wp_set_current_user( self::$editor_id ); 217 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' ); 218 $response = rest_get_server()->dispatch( $request ); 219 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 220 } 221 222 public function test_delete_item() { 223 // Doesn't exist. 224 } 225 226 public function test_prepare_item() { 227 wp_set_current_user( self::$editor_id ); 228 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 229 $response = rest_get_server()->dispatch( $request ); 230 $this->assertEquals( 200, $response->get_status() ); 231 $this->check_get_autosave_response( $response, $this->post_autosave ); 232 } 233 234 public function test_get_item_schema() { 235 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 236 $response = rest_get_server()->dispatch( $request ); 237 $data = $response->get_data(); 238 $properties = $data['schema']['properties']; 239 $this->assertEquals( 12, count( $properties ) ); 240 $this->assertArrayHasKey( 'author', $properties ); 241 $this->assertArrayHasKey( 'content', $properties ); 242 $this->assertArrayHasKey( 'date', $properties ); 243 $this->assertArrayHasKey( 'date_gmt', $properties ); 244 $this->assertArrayHasKey( 'excerpt', $properties ); 245 $this->assertArrayHasKey( 'guid', $properties ); 246 $this->assertArrayHasKey( 'id', $properties ); 247 $this->assertArrayHasKey( 'modified', $properties ); 248 $this->assertArrayHasKey( 'modified_gmt', $properties ); 249 $this->assertArrayHasKey( 'parent', $properties ); 250 $this->assertArrayHasKey( 'slug', $properties ); 251 $this->assertArrayHasKey( 'title', $properties ); 252 } 253 254 public function test_create_item() { 255 wp_set_current_user( self::$editor_id ); 256 257 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 258 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 259 260 $params = $this->set_post_data( 261 array( 262 'id' => self::$post_id, 263 ) 264 ); 265 $request->set_body_params( $params ); 266 $response = rest_get_server()->dispatch( $request ); 267 268 $this->check_create_autosave_response( $response ); 269 } 270 271 public function test_update_item() { 272 wp_set_current_user( self::$editor_id ); 273 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 274 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 275 276 $params = $this->set_post_data( 277 array( 278 'id' => self::$post_id, 279 'author' => self::$contributor_id, 280 ) 281 ); 282 283 $request->set_body_params( $params ); 284 $response = rest_get_server()->dispatch( $request ); 285 286 $this->check_create_autosave_response( $response ); 287 } 288 289 public function test_update_item_nopriv() { 290 wp_set_current_user( self::$contributor_id ); 291 292 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 293 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 294 295 $params = $this->set_post_data( 296 array( 297 'id' => self::$post_id, 298 'author' => self::$editor_id, 299 ) 300 ); 301 302 $request->set_body_params( $params ); 303 $response = rest_get_server()->dispatch( $request ); 304 305 $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 ); 306 } 307 308 public function test_rest_autosave_published_post() { 309 wp_set_current_user( self::$editor_id ); 310 311 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 312 $request->add_header( 'content-type', 'application/json' ); 313 314 $current_post = get_post( self::$post_id ); 315 316 $autosave_data = $this->set_post_data( 317 array( 318 'id' => self::$post_id, 319 'content' => 'Updated post \ content', 320 'excerpt' => $current_post->post_excerpt, 321 'title' => $current_post->post_title, 322 ) 323 ); 324 325 $request->set_body( wp_json_encode( $autosave_data ) ); 326 $response = rest_get_server()->dispatch( $request ); 327 $new_data = $response->get_data(); 328 329 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 330 $this->assertEquals( $current_post->post_title, $new_data['title']['raw'] ); 331 $this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] ); 332 // Updated post_content 333 $this->assertNotEquals( $current_post->post_content, $new_data['content']['raw'] ); 334 335 $autosave_post = wp_get_post_autosave( self::$post_id ); 336 $this->assertEquals( $autosave_data['title'], $autosave_post->post_title ); 337 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 338 $this->assertEquals( $autosave_data['excerpt'], $autosave_post->post_excerpt ); 339 } 340 341 public function test_rest_autosave_draft_post_same_author() { 342 wp_set_current_user( self::$editor_id ); 343 344 $post_data = array( 345 'post_content' => 'Test post content', 346 'post_title' => 'Test post title', 347 'post_excerpt' => 'Test post excerpt', 348 ); 349 $post_id = wp_insert_post( $post_data ); 350 351 $autosave_data = array( 352 'id' => $post_id, 353 'content' => 'Updated post \ content', 354 'title' => 'Updated post title', 355 ); 356 357 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 358 $request->add_header( 'content-type', 'application/json' ); 359 $request->set_body( wp_json_encode( $autosave_data ) ); 360 361 $response = rest_get_server()->dispatch( $request ); 362 $new_data = $response->get_data(); 363 $post = get_post( $post_id ); 364 365 $this->assertEquals( $post_id, $new_data['id'] ); 366 // The draft post should be updated. 367 $this->assertEquals( $autosave_data['content'], $new_data['content']['raw'] ); 368 $this->assertEquals( $autosave_data['title'], $new_data['title']['raw'] ); 369 $this->assertEquals( $autosave_data['content'], $post->post_content ); 370 $this->assertEquals( $autosave_data['title'], $post->post_title ); 371 372 // Not updated. 373 $this->assertEquals( $post_data['post_excerpt'], $post->post_excerpt ); 374 375 wp_delete_post( $post_id ); 376 } 377 378 public function test_rest_autosave_draft_post_different_author() { 379 wp_set_current_user( self::$editor_id ); 380 381 $post_data = array( 382 'post_content' => 'Test post content', 383 'post_title' => 'Test post title', 384 'post_excerpt' => 'Test post excerpt', 385 'post_author' => self::$editor_id + 1, 386 ); 387 $post_id = wp_insert_post( $post_data ); 388 389 $autosave_data = array( 390 'id' => $post_id, 391 'content' => 'Updated post content', 392 'excerpt' => $post_data['post_excerpt'], 393 'title' => $post_data['post_title'], 394 ); 395 396 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 397 $request->add_header( 'content-type', 'application/json' ); 398 $request->set_body( wp_json_encode( $autosave_data ) ); 399 400 $response = rest_get_server()->dispatch( $request ); 401 $new_data = $response->get_data(); 402 $current_post = get_post( $post_id ); 403 404 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 405 406 // The draft post shouldn't change. 407 $this->assertEquals( $current_post->post_title, $post_data['post_title'] ); 408 $this->assertEquals( $current_post->post_content, $post_data['post_content'] ); 409 $this->assertEquals( $current_post->post_excerpt, $post_data['post_excerpt'] ); 410 411 $autosave_post = wp_get_post_autosave( $post_id ); 412 413 // No changes 414 $this->assertEquals( $current_post->post_title, $autosave_post->post_title ); 415 $this->assertEquals( $current_post->post_excerpt, $autosave_post->post_excerpt ); 416 417 // Has changes 418 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 419 420 wp_delete_post( $post_id ); 421 } 422 423 public function test_get_additional_field_registration() { 424 $schema = array( 425 'type' => 'integer', 426 'description' => 'Some integer of mine', 427 'enum' => array( 1, 2, 3, 4 ), 428 'context' => array( 'view', 'edit' ), 429 ); 430 431 register_rest_field( 432 'post-revision', 'my_custom_int', array( 433 'schema' => $schema, 434 'get_callback' => array( $this, 'additional_field_get_callback' ), 435 'update_callback' => array( $this, 'additional_field_update_callback' ), 436 ) 437 ); 438 439 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 440 441 $response = rest_get_server()->dispatch( $request ); 442 $data = $response->get_data(); 443 444 $this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] ); 445 $this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] ); 446 447 wp_set_current_user( 1 ); 448 449 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 450 451 $response = rest_get_server()->dispatch( $request ); 452 $this->assertArrayHasKey( 'my_custom_int', $response->data ); 453 454 global $wp_rest_additional_fields; 455 $wp_rest_additional_fields = array(); 456 } 457 458 public function additional_field_get_callback( $object ) { 459 return get_post_meta( $object['id'], 'my_custom_int', true ); 460 } 461 462 public function additional_field_update_callback( $value, $post ) { 463 update_post_meta( $post->ID, 'my_custom_int', $value ); 464 } 465 466 protected function check_get_autosave_response( $response, $autosave ) { 467 if ( $response instanceof WP_REST_Response ) { 468 $links = $response->get_links(); 469 $response = $response->get_data(); 470 } else { 471 $this->assertArrayHasKey( '_links', $response ); 472 $links = $response['_links']; 473 } 474 475 $this->assertEquals( $autosave->post_author, $response['author'] ); 476 477 $rendered_content = apply_filters( 'the_content', $autosave->post_content ); 478 $this->assertEquals( $rendered_content, $response['content']['rendered'] ); 479 480 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date ), $response['date'] ); 481 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date_gmt ), $response['date_gmt'] ); 482 483 $rendered_guid = apply_filters( 'get_the_guid', $autosave->guid, $autosave->ID ); 484 $this->assertEquals( $rendered_guid, $response['guid']['rendered'] ); 485 486 $this->assertEquals( $autosave->ID, $response['id'] ); 487 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified ), $response['modified'] ); 488 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified_gmt ), $response['modified_gmt'] ); 489 $this->assertEquals( $autosave->post_name, $response['slug'] ); 490 491 $rendered_title = get_the_title( $autosave->ID ); 492 $this->assertEquals( $rendered_title, $response['title']['rendered'] ); 493 494 $parent = get_post( $autosave->post_parent ); 495 $parent_controller = new WP_REST_Posts_Controller( $parent->post_type ); 496 $parent_object = get_post_type_object( $parent->post_type ); 497 $parent_base = ! empty( $parent_object->rest_base ) ? $parent_object->rest_base : $parent_object->name; 498 $this->assertEquals( rest_url( '/wp/v2/' . $parent_base . '/' . $autosave->post_parent ), $links['parent'][0]['href'] ); 499 } 500 501 public function test_get_item_sets_up_postdata() { 502 wp_set_current_user( self::$editor_id ); 503 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 504 rest_get_server()->dispatch( $request ); 505 506 $post = get_post(); 507 $parent_post_id = wp_is_post_revision( $post->ID ); 508 509 $this->assertEquals( $post->ID, self::$autosave_post_id ); 510 $this->assertEquals( $parent_post_id, self::$post_id ); 511 } 512 513 } -
tests/phpunit/tests/rest-api/rest-schema-setup.php
diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php index c23dcb5020..e19a46d47d 100644
a b class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 89 89 '/wp/v2/posts/(?P<id>[\\d]+)', 90 90 '/wp/v2/posts/(?P<parent>[\\d]+)/revisions', 91 91 '/wp/v2/posts/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)', 92 '/wp/v2/posts/(?P<parent>[\\d]+)/autosaves', 93 '/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)', 92 94 '/wp/v2/pages', 93 95 '/wp/v2/pages/(?P<id>[\\d]+)', 94 96 '/wp/v2/pages/(?P<parent>[\\d]+)/revisions', 95 97 '/wp/v2/pages/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)', 98 '/wp/v2/pages/(?P<parent>[\\d]+)/autosaves', 99 '/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)', 96 100 '/wp/v2/media', 97 101 '/wp/v2/media/(?P<id>[\\d]+)', 98 102 '/wp/v2/types', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 153 157 $post_revisions = array_values( wp_get_post_revisions( $post_id ) ); 154 158 $post_revision_id = $post_revisions[ count( $post_revisions ) - 1 ]->ID; 155 159 160 // Create an autosave. 161 wp_create_post_autosave( 162 array( 163 'post_ID' => $post_id, 164 'post_content' => 'Autosave post content.', 165 'post_type' => 'post', 166 ) 167 ); 168 169 156 170 $page_id = $this->factory->post->create( array( 157 171 'post_type' => 'page', 158 172 'post_name' => 'restapi-client-fixture-page', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 170 184 $page_revisions = array_values( wp_get_post_revisions( $page_id ) ); 171 185 $page_revision_id = $page_revisions[ count( $page_revisions ) - 1 ]->ID; 172 186 187 // Create an autosave. 188 wp_create_post_autosave( 189 array( 190 'post_ID' => $page_id, 191 'post_content' => 'Autosave page content.', 192 'post_type' => 'page', 193 ) 194 ); 195 173 196 $tag_id = $this->factory->tag->create( array( 174 197 'name' => 'REST API Client Fixture: Tag', 175 198 'slug' => 'restapi-client-fixture-tag', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 255 278 'route' => '/wp/v2/posts/' . $post_id . '/revisions/' . $post_revision_id, 256 279 'name' => 'revision', 257 280 ), 281 array( 282 'route' => '/wp/v2/posts/' . $post_id . '/autosaves', 283 'name' => 'postAutosaves', 284 ), 285 array( 286 'route' => '/wp/v2/posts/' . $post_id . '/autosaves/' . $post_revision_id, 287 'name' => 'autosave', 288 ), 258 289 array( 259 290 'route' => '/wp/v2/pages', 260 291 'name' => 'PagesCollection', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 271 302 'route' => '/wp/v2/pages/'. $page_id . '/revisions/' . $page_revision_id, 272 303 'name' => 'pageRevision', 273 304 ), 305 array( 306 'route' => '/wp/v2/pages/' . $page_id . '/autosaves', 307 'name' => 'pageAutosaves', 308 ), 309 array( 310 'route' => '/wp/v2/pages/' . $page_id . '/autosaves/' . $page_revision_id, 311 'name' => 'pageAutosave', 312 ), 274 313 array( 275 314 'route' => '/wp/v2/media', 276 315 'name' => 'MediaCollection', -
tests/qunit/fixtures/wp-api-generated.js
diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 25b13a29d8..26b2640db1 100644
a b mockedApiResponse.Schema = { 850 850 } 851 851 ] 852 852 }, 853 "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves": { 854 "namespace": "wp/v2", 855 "methods": [ 856 "GET", 857 "POST" 858 ], 859 "endpoints": [ 860 { 861 "methods": [ 862 "GET" 863 ], 864 "args": { 865 "parent": { 866 "required": false, 867 "description": "The ID for the parent of the object.", 868 "type": "integer" 869 }, 870 "context": { 871 "required": false, 872 "default": "view", 873 "enum": [ 874 "view", 875 "embed", 876 "edit" 877 ], 878 "description": "Scope under which the request is made; determines fields present in response.", 879 "type": "string" 880 } 881 } 882 }, 883 { 884 "methods": [ 885 "POST" 886 ], 887 "args": { 888 "parent": { 889 "required": false, 890 "description": "The ID for the parent of the object.", 891 "type": "integer" 892 }, 893 "author": { 894 "required": false, 895 "description": "The ID for the author of the object.", 896 "type": "integer" 897 }, 898 "date": { 899 "required": false, 900 "description": "The date the object was published, in the site's timezone.", 901 "type": "string" 902 }, 903 "date_gmt": { 904 "required": false, 905 "description": "The date the object was published, as GMT.", 906 "type": "string" 907 }, 908 "id": { 909 "required": false, 910 "description": "Unique identifier for the object.", 911 "type": "integer" 912 }, 913 "modified": { 914 "required": false, 915 "description": "The date the object was last modified, in the site's timezone.", 916 "type": "string" 917 }, 918 "modified_gmt": { 919 "required": false, 920 "description": "The date the object was last modified, as GMT.", 921 "type": "string" 922 }, 923 "slug": { 924 "required": false, 925 "description": "An alphanumeric identifier for the object unique to its type.", 926 "type": "string" 927 }, 928 "title": { 929 "required": false, 930 "description": "The title for the object.", 931 "type": "object" 932 }, 933 "content": { 934 "required": false, 935 "description": "The content for the object.", 936 "type": "object" 937 }, 938 "excerpt": { 939 "required": false, 940 "description": "The excerpt for the object.", 941 "type": "object" 942 } 943 } 944 } 945 ] 946 }, 947 "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 948 "namespace": "wp/v2", 949 "methods": [ 950 "GET" 951 ], 952 "endpoints": [ 953 { 954 "methods": [ 955 "GET" 956 ], 957 "args": { 958 "parent": { 959 "required": false, 960 "description": "The ID for the parent of the object.", 961 "type": "integer" 962 }, 963 "id": { 964 "required": false, 965 "description": "The ID for the object.", 966 "type": "integer" 967 }, 968 "context": { 969 "required": false, 970 "default": "view", 971 "enum": [ 972 "view", 973 "embed", 974 "edit" 975 ], 976 "description": "Scope under which the request is made; determines fields present in response.", 977 "type": "string" 978 } 979 } 980 } 981 ] 982 }, 853 983 "/wp/v2/pages": { 854 984 "namespace": "wp/v2", 855 985 "methods": [ … … mockedApiResponse.Schema = { 1456 1586 } 1457 1587 ] 1458 1588 }, 1589 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves": { 1590 "namespace": "wp/v2", 1591 "methods": [ 1592 "GET", 1593 "POST" 1594 ], 1595 "endpoints": [ 1596 { 1597 "methods": [ 1598 "GET" 1599 ], 1600 "args": { 1601 "parent": { 1602 "required": false, 1603 "description": "The ID for the parent of the object.", 1604 "type": "integer" 1605 }, 1606 "context": { 1607 "required": false, 1608 "default": "view", 1609 "enum": [ 1610 "view", 1611 "embed", 1612 "edit" 1613 ], 1614 "description": "Scope under which the request is made; determines fields present in response.", 1615 "type": "string" 1616 } 1617 } 1618 }, 1619 { 1620 "methods": [ 1621 "POST" 1622 ], 1623 "args": { 1624 "parent": { 1625 "required": false, 1626 "description": "The ID for the parent of the object.", 1627 "type": "integer" 1628 }, 1629 "author": { 1630 "required": false, 1631 "description": "The ID for the author of the object.", 1632 "type": "integer" 1633 }, 1634 "date": { 1635 "required": false, 1636 "description": "The date the object was published, in the site's timezone.", 1637 "type": "string" 1638 }, 1639 "date_gmt": { 1640 "required": false, 1641 "description": "The date the object was published, as GMT.", 1642 "type": "string" 1643 }, 1644 "id": { 1645 "required": false, 1646 "description": "Unique identifier for the object.", 1647 "type": "integer" 1648 }, 1649 "modified": { 1650 "required": false, 1651 "description": "The date the object was last modified, in the site's timezone.", 1652 "type": "string" 1653 }, 1654 "modified_gmt": { 1655 "required": false, 1656 "description": "The date the object was last modified, as GMT.", 1657 "type": "string" 1658 }, 1659 "slug": { 1660 "required": false, 1661 "description": "An alphanumeric identifier for the object unique to its type.", 1662 "type": "string" 1663 }, 1664 "title": { 1665 "required": false, 1666 "description": "The title for the object.", 1667 "type": "object" 1668 }, 1669 "content": { 1670 "required": false, 1671 "description": "The content for the object.", 1672 "type": "object" 1673 }, 1674 "excerpt": { 1675 "required": false, 1676 "description": "The excerpt for the object.", 1677 "type": "object" 1678 } 1679 } 1680 } 1681 ] 1682 }, 1683 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 1684 "namespace": "wp/v2", 1685 "methods": [ 1686 "GET" 1687 ], 1688 "endpoints": [ 1689 { 1690 "methods": [ 1691 "GET" 1692 ], 1693 "args": { 1694 "parent": { 1695 "required": false, 1696 "description": "The ID for the parent of the object.", 1697 "type": "integer" 1698 }, 1699 "id": { 1700 "required": false, 1701 "description": "The ID for the object.", 1702 "type": "integer" 1703 }, 1704 "context": { 1705 "required": false, 1706 "default": "view", 1707 "enum": [ 1708 "view", 1709 "embed", 1710 "edit" 1711 ], 1712 "description": "Scope under which the request is made; determines fields present in response.", 1713 "type": "string" 1714 } 1715 } 1716 } 1717 ] 1718 }, 1459 1719 "/wp/v2/media": { 1460 1720 "namespace": "wp/v2", 1461 1721 "methods": [ … … mockedApiResponse.postRevisions = [ 3814 4074 "guid": { 3815 4075 "rendered": "http://example.org/?p=5" 3816 4076 }, 4077 "title": { 4078 "rendered": "" 4079 }, 4080 "content": { 4081 "rendered": "<p>Autosave post content.</p>\n" 4082 }, 4083 "excerpt": { 4084 "rendered": "" 4085 }, 4086 "_links": { 4087 "parent": [ 4088 { 4089 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3" 4090 } 4091 ] 4092 } 4093 }, 4094 { 4095 "author": 2, 4096 "date": "2017-02-14T00:00:00", 4097 "date_gmt": "2017-02-14T00:00:00", 4098 "id": 4, 4099 "modified": "2017-02-14T00:00:00", 4100 "modified_gmt": "2017-02-14T00:00:00", 4101 "parent": 3, 4102 "slug": "3-revision-v1", 4103 "guid": { 4104 "rendered": "http://example.org/?p=4" 4105 }, 3817 4106 "title": { 3818 4107 "rendered": "REST API Client Fixture: Post" 3819 4108 }, … … mockedApiResponse.revision = { 3856 4145 } 3857 4146 }; 3858 4147 4148 mockedApiResponse.postAutosaves = [ 4149 { 4150 "author": 2, 4151 "date": "2017-02-14T00:00:00", 4152 "date_gmt": "2017-02-14T00:00:00", 4153 "id": 5, 4154 "modified": "2017-02-14T00:00:00", 4155 "modified_gmt": "2017-02-14T00:00:00", 4156 "parent": 3, 4157 "slug": "3-autosave-v1", 4158 "guid": { 4159 "rendered": "http://example.org/?p=5" 4160 }, 4161 "title": { 4162 "rendered": "" 4163 }, 4164 "content": { 4165 "rendered": "<p>Autosave post content.</p>\n" 4166 }, 4167 "excerpt": { 4168 "rendered": "" 4169 }, 4170 "_links": { 4171 "parent": [ 4172 { 4173 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3" 4174 } 4175 ] 4176 } 4177 } 4178 ]; 4179 4180 mockedApiResponse.autosave = { 4181 "author": 2, 4182 "date": "2017-02-14T00:00:00", 4183 "date_gmt": "2017-02-14T00:00:00", 4184 "id": 5, 4185 "modified": "2017-02-14T00:00:00", 4186 "modified_gmt": "2017-02-14T00:00:00", 4187 "parent": 3, 4188 "slug": "3-autosave-v1", 4189 "guid": { 4190 "rendered": "http://example.org/?p=5" 4191 }, 4192 "title": { 4193 "rendered": "" 4194 }, 4195 "content": { 4196 "rendered": "<p>Autosave post content.</p>\n" 4197 }, 4198 "excerpt": { 4199 "rendered": "" 4200 } 4201 }; 4202 3859 4203 mockedApiResponse.PagesCollection = [ 3860 4204 { 3861 4205 "id": 6, … … mockedApiResponse.PageModel = { 3978 4322 }; 3979 4323 3980 4324 mockedApiResponse.pageRevisions = [ 4325 { 4326 "author": 2, 4327 "date": "2017-02-14T00:00:00", 4328 "date_gmt": "2017-02-14T00:00:00", 4329 "id": 7, 4330 "modified": "2017-02-14T00:00:00", 4331 "modified_gmt": "2017-02-14T00:00:00", 4332 "parent": 6, 4333 "slug": "6-revision-v1", 4334 "guid": { 4335 "rendered": "http://example.org/?p=7" 4336 }, 4337 "title": { 4338 "rendered": "" 4339 }, 4340 "content": { 4341 "rendered": "<p>Autosave page content.</p>\n" 4342 }, 4343 "excerpt": { 4344 "rendered": "" 4345 }, 4346 "_links": { 4347 "parent": [ 4348 { 4349 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/5" 4350 } 4351 ] 4352 } 4353 }, 3981 4354 { 3982 4355 "author": 2, 3983 4356 "date": "2017-02-14T00:00:00", … … mockedApiResponse.pageRevision = { 4032 4405 } 4033 4406 }; 4034 4407 4408 mockedApiResponse.pageAutosaves = [ 4409 { 4410 "author": 2, 4411 "date": "2017-02-14T00:00:00", 4412 "date_gmt": "2017-02-14T00:00:00", 4413 "id": 8, 4414 "modified": "2017-02-14T00:00:00", 4415 "modified_gmt": "2017-02-14T00:00:00", 4416 "parent": 6, 4417 "slug": "6-autosave-v1", 4418 "guid": { 4419 "rendered": "http://example.org/?p=8" 4420 }, 4421 "title": { 4422 "rendered": "" 4423 }, 4424 "content": { 4425 "rendered": "<p>Autosave page content.</p>\n" 4426 }, 4427 "excerpt": { 4428 "rendered": "" 4429 }, 4430 "_links": { 4431 "parent": [ 4432 { 4433 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6" 4434 } 4435 ] 4436 } 4437 } 4438 ]; 4439 4440 mockedApiResponse.pageAutosave = { 4441 "author": 2, 4442 "date": "2017-02-14T00:00:00", 4443 "date_gmt": "2017-02-14T00:00:00", 4444 "id": 8, 4445 "modified": "2017-02-14T00:00:00", 4446 "modified_gmt": "2017-02-14T00:00:00", 4447 "parent": 6, 4448 "slug": "6-autosave-v1", 4449 "guid": { 4450 "rendered": "http://example.org/?p=8" 4451 }, 4452 "title": { 4453 "rendered": "" 4454 }, 4455 "content": { 4456 "rendered": "<p>Autosave page content.</p>\n" 4457 }, 4458 "excerpt": { 4459 "rendered": "" 4460 } 4461 }; 4462 4035 4463 mockedApiResponse.MediaCollection = [ 4036 4464 { 4037 4465 "id": 8,