Ticket #43316: 43316.11.diff
File 43316.11.diff, 56.4 KB (added by , 7 years ago) |
---|
-
src/wp-includes/rest-api.php
192 192 if ( post_type_supports( $post_type->name, 'revisions' ) ) { 193 193 $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name ); 194 194 $revisions_controller->register_routes(); 195 $controller = new WP_REST_Autosaves_Controller( $post_type->name ); 196 $controller->register_routes(); 195 197 } 196 198 } 197 199 -
src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php
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 controller. 29 * 30 * @since 5.0.0 31 * @var WP_REST_Controller 32 */ 33 private $parent_controller; 34 35 /** 36 * Parent controller. 37 * 38 * @since 5.0.0 39 * @var WP_REST_Controller 40 */ 41 private $revision_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 $this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); 61 $this->revision_controller = new WP_REST_Revisions_Controller( $parent_post_type ); 62 $this->rest_namespace = 'wp/v2'; 63 $this->rest_base = 'autosaves'; 64 $post_type_object = get_post_type_object( $parent_post_type ); 65 $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; 66 } 67 68 /**o 69 * Registers routes for autosaves. 70 * 71 * @since 5.0.0 72 * 73 * @see register_rest_route() 74 */ 75 public function register_routes() { 76 register_rest_route( 77 $this->rest_namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base, array( 78 'args' => array( 79 'parent' => array( 80 'description' => __( 'The ID for the parent of the object.' ), 81 'type' => 'integer', 82 ), 83 ), 84 array( 85 'methods' => WP_REST_Server::READABLE, 86 'callback' => array( $this, 'get_items' ), 87 'permission_callback' => array( $this->revision_controller, 'get_items_permissions_check' ), 88 'args' => $this->get_collection_params(), 89 ), 90 array( 91 'methods' => WP_REST_Server::CREATABLE, 92 'callback' => array( $this, 'create_item' ), 93 'permission_callback' => array( $this, 'create_item_permissions_check' ), 94 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), 95 ), 96 'schema' => array( $this, 'get_public_item_schema' ), 97 ) 98 ); 99 100 register_rest_route( 101 $this->rest_namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', array( 102 'args' => array( 103 'parent' => array( 104 'description' => __( 'The ID for the parent of the object.' ), 105 'type' => 'integer', 106 ), 107 'id' => array( 108 'description' => __( 'The ID for the object.' ), 109 'type' => 'integer', 110 ), 111 ), 112 array( 113 'methods' => WP_REST_Server::READABLE, 114 'callback' => array( $this, 'get_item' ), 115 'permission_callback' => array( $this->revision_controller, 'get_item_permissions_check' ), 116 'args' => array( 117 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 118 ), 119 ), 120 array( 121 'methods' => WP_REST_Server::DELETABLE, 122 'callback' => array( $this, 'delete_item' ), 123 'permission_callback' => array( $this->revision_controller, 'delete_item_permissions_check' ), 124 'args' => array( 125 'force' => array( 126 'type' => 'boolean', 127 'default' => false, 128 'description' => __( 'Required to be true, as autosaves do not support trashing.' ), 129 ), 130 ), 131 ), 132 'schema' => array( $this, 'get_public_item_schema' ), 133 ) 134 ); 135 136 } 137 138 /** 139 * Get the parent post. 140 * 141 * @since 5.0.0 142 * 143 * @param int $parent_id Supplied ID. 144 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. 145 */ 146 protected function get_parent( $parent_id ) { 147 return $this->revision_controller->get_parent( $parent_id ); 148 } 149 150 /** 151 * Checks if a given request has access to create an autosave revision. 152 * 153 * Autosave revisions inherit permissions from the parent post, 154 * check if the current user has permission to edit the post. 155 * 156 * @since 5.0.0 157 * 158 * @param WP_REST_Request $request Full details about the request. 159 * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. 160 */ 161 public function create_item_permissions_check( $request ) { 162 if ( empty( $request->get_param( 'id' ) ) ) { 163 return new WP_Error( 'rest_post_invalid_id', __( 'Invalid item ID.' ), array( 'status' => 404 ) ); 164 } 165 166 return $this->parent_controller->update_item_permissions_check( $request ); 167 } 168 169 /** 170 * Create a revision when the autosave content is significantly different. 171 * 172 * If the autosave content is significantly different from the current post or the previous autosave, 173 * create a revision from the old data. 174 * 175 * @since 5.0.0 176 * 177 * @param WP_Post $post The current post or the previous autosave revision. 178 * @param array $autosave_data The autosave data. 179 */ 180 protected function create_revision_for_autosave( $post, $autosave_data ) { 181 182 if ( ! wp_revisions_enabled( $post ) ) { 183 return; 184 } 185 186 $post_data = get_object_vars( $post ); 187 188 if ( $post_data['post_type'] === 'revision' ) { 189 // If the old post is a revision, need to merge it with the actual post. 190 $parent_post = $this->get_parent( $post_data['post_parent'] ); 191 foreach ( array_keys( _wp_post_revision_fields( $parent_post ) ) as $field ) { 192 if ( isset( $post_data[ $field ] ) ) { 193 $parent_post->$field = $post_data[ $field ]; 194 } 195 } 196 $post_data = get_object_vars( $parent_post ); 197 } 198 199 $old_length = strlen( $post_data['post_content'] ); 200 201 if ( $old_length > 1000 ) { 202 $difference = 250; 203 } elseif ( $old_length > 500 ) { 204 $difference = (int) $old_length * 0.2; 205 } elseif ( $old_length > 50 ) { 206 $difference = (int) $old_length * 0.3; 207 } else { 208 $difference = (int) $old_length * 0.5; 209 } 210 211 $size_diff = strlen( $autosave_data['content'] ) - $old_length; 212 $create_revision = absint( $size_diff ) > $difference; 213 $revision_id = 0; 214 215 /** 216 * Filter whether a revision is created when an autosave is made via the REST API. 217 * 218 * @since 5.0.0 219 * 220 * @param bool $create_revision Create a revision? 221 * @param array $post_data The current post data. 222 * @param int $size_diff The calculated autosave difference. 223 */ 224 if ( apply_filters( 'wp_create_revision_for_autosave', $create_revision, $post_data, $size_diff ) ) { 225 _wp_put_post_revision( $post_data ); 226 } 227 } 228 229 /** 230 * Creates, updates or deletes an autosave revision. 231 * 232 * @since 5.0.0 233 * 234 * @param WP_REST_Request $request Full details about the request. 235 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 236 */ 237 public function create_item( $request ) { 238 239 if ( ! defined( 'DOING_AUTOSAVE' ) ) { 240 define( 'DOING_AUTOSAVE', true ); 241 } 242 243 $post = get_post( $request->get_param( 'id' ) ); 244 245 if ( is_wp_error( $post ) ) { 246 return $post; 247 } 248 249 $prepared_post = $this->parent_controller->prepare_item_for_database( $request ); 250 $prepared_post->ID = $post->ID; 251 $user_id = get_current_user_id(); 252 253 if ( ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status ) && $post->post_author == $user_id ) { 254 // Optionaly create a revision if the autosave data is significantly different. 255 // This protects the user from errors when editing, accidental deletes, etc. 256 $this->create_revision_for_autosave( $post, (array) $prepared_post ); 257 258 // Draft posts for the same author: autosaving updates the post and does not create a revision. 259 // Convert the post object to an array and add slashes, wp_update_post expects escaped array. 260 $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true ); 261 } else { 262 // Non-draft posts: create or update the post autosave. 263 $autosave_id = $this->create_post_autosave( (array) $prepared_post ); 264 } 265 266 if ( is_wp_error( $autosave_id ) ) { 267 return $autosave_id; 268 } 269 270 $autosave = get_post( $autosave_id ); 271 $request->set_param( 'context', 'edit' ); 272 273 $response = $this->prepare_item_for_response( $autosave, $request ); 274 $response = rest_ensure_response( $response ); 275 276 return $response; 277 } 278 279 /** 280 * Get the autosave, if the ID is valid. 281 * 282 * @since 5.0.0 283 * 284 * @param WP_REST_Request $request Full data about the request. 285 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. 286 */ 287 public function get_item( $request ) { 288 $parent_id = (int) $request->get_param( 'parent' ); 289 290 if ( $parent_id <= 0 ) { 291 return new WP_Error( 'rest_post_invalid_id', __( 'Invalid parent post ID.' ), array( 'status' => 404 ) ); 292 } 293 294 $autosave = wp_get_post_autosave( $parent_id ); 295 296 if ( ! $autosave ) { 297 return new WP_Error( 'rest_post_no_autosave', __( 'There is no autosave revision for this post.' ), array( 'status' => 404 ) ); 298 } 299 300 $response = $this->prepare_item_for_response( $autosave, $request ); 301 return $response; 302 } 303 304 /** 305 * Gets a collection of autosaves using wp_get_post_autosave. 306 * 307 * Contains the user's autosave, for empty if it doesn't exist. 308 * 309 * @since 5.0.0 310 * 311 * @param WP_REST_Request $request Full data about the request. 312 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 313 */ 314 public function get_items( $request ) { 315 $parent = $this->get_parent( $request->get_param( 'parent' ) ); 316 if ( is_wp_error( $parent ) ) { 317 return $parent; 318 } 319 320 $response = array(); 321 $parent_id = $parent->ID; 322 $revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) ); 323 324 foreach ( $revisions as $revision ) { 325 if ( false !== strpos( $revision->post_name, "{$parent_id}-autosave" ) ) { 326 $data = $this->prepare_item_for_response( $revision, $request ); 327 $response[] = $this->prepare_response_for_collection( $data ); 328 } 329 } 330 331 return rest_ensure_response( $response ); 332 } 333 334 335 /** 336 * Retrieves the autosave's schema, conforming to JSON Schema. 337 * 338 * @since 5.0.0 339 * 340 * @return array Item schema data. 341 */ 342 public function get_item_schema() { 343 return $this->revision_controller->get_item_schema(); 344 } 345 346 /** 347 * Creates autosave for the specified post. 348 * 349 * From wp-admin/post.php. 350 * 351 * @since 5.0.0 352 * 353 * @param mixed $post_data Associative array containing the post data. 354 * @return mixed The autosave revision ID or WP_Error. 355 */ 356 public function create_post_autosave( $post_data ) { 357 358 $post_id = (int) $post_data['ID']; 359 $post = get_post( $post_id ); 360 361 if ( is_wp_error( $post ) ) { 362 return $post; 363 } 364 365 $user_id = get_current_user_id(); 366 367 // Store one autosave per author. If there is already an autosave, overwrite it. 368 $old_autosave = wp_get_post_autosave( $post_id, $user_id ); 369 370 if ( $old_autosave ) { 371 $new_autosave = _wp_post_revision_data( $post_data, true ); 372 $new_autosave['ID'] = $old_autosave->ID; 373 $new_autosave['post_author'] = $user_id; 374 375 // If the new autosave has the same content as the post, delete the autosave. 376 $autosave_is_different = false; 377 378 foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) { 379 if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) { 380 $autosave_is_different = true; 381 break; 382 } 383 } 384 385 if ( ! $autosave_is_different ) { 386 wp_delete_post_revision( $old_autosave->ID ); 387 return new WP_Error( 'rest_autosave_no_changes', __( 'There is nothing to save. The autosave and the post content are the same.' ) ); 388 } 389 390 /** 391 * This filter is documented in wp-admin/post.php. 392 */ 393 do_action( 'wp_creating_autosave', $new_autosave ); 394 395 // Optionally create a post revision if the new autosave data is significantly different. 396 $this->create_revision_for_autosave( $old_autosave, $new_autosave ); 397 398 // wp_update_post expects escaped array. 399 return wp_update_post( wp_slash( $new_autosave ) ); 400 } 401 402 // Create the new autosave as a special post revision. 403 return _wp_put_post_revision( $post_data, true ); 404 } 405 406 /** 407 * Prepares the revision for the REST response. 408 * 409 * @since 5.0.0 410 * 411 * @param WP_Post $post Post revision object. 412 * @param WP_REST_Request $request Request object. 413 * 414 * @return WP_REST_Response Response object. 415 */ 416 public function prepare_item_for_response( $post, $request ) { 417 418 $response = $this->revision_controller->prepare_item_for_response( $post, $request ); 419 420 /** 421 * Filters a revision returned from the API. 422 * 423 * Allows modification of the revision right before it is returned. 424 * 425 * @since 5.0.0 426 * 427 * @param WP_REST_Response $response The response object. 428 * @param WP_Post $post The original revision object. 429 * @param WP_REST_Request $request Request used to generate the response. 430 */ 431 return apply_filters( 'rest_prepare_autosave', $response, $post, $request ); 432 } 433 } -
src/wp-settings.php
Property changes on: src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property
230 230 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-types-controller.php' ); 231 231 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-statuses-controller.php' ); 232 232 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-revisions-controller.php' ); 233 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-autosaves-controller.php' ); 233 234 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-taxonomies-controller.php' ); 234 235 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.php' ); 235 236 require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-users-controller.php' ); -
tests/phpunit/tests/rest-api/rest-autosaves-controller.php
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 wp_set_current_user( self::$editor_id ); 224 $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 225 $request->set_param( 'force', true ); 226 $response = rest_get_server()->dispatch( $request ); 227 $this->assertEquals( 200, $response->get_status() ); 228 $this->assertNull( get_post( self::$autosave_post_id ) ); 229 } 230 231 public function test_delete_item_no_trash() { 232 wp_set_current_user( self::$editor_id ); 233 234 $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 235 $response = rest_get_server()->dispatch( $request ); 236 $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); 237 238 $request->set_param( 'force', 'false' ); 239 $response = rest_get_server()->dispatch( $request ); 240 $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501 ); 241 242 // Ensure the revision still exists 243 $this->assertNotNull( get_post( self::$autosave_post_id ) ); 244 } 245 246 public function test_delete_item_no_permission() { 247 wp_set_current_user( self::$contributor_id ); 248 $request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 249 $response = rest_get_server()->dispatch( $request ); 250 $this->assertErrorResponse( 'rest_cannot_read', $response, 403 ); 251 } 252 253 public function test_prepare_item() { 254 wp_set_current_user( self::$editor_id ); 255 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 256 $response = rest_get_server()->dispatch( $request ); 257 $this->assertEquals( 200, $response->get_status() ); 258 $this->check_get_autosave_response( $response, $this->post_autosave ); 259 } 260 261 public function test_get_item_schema() { 262 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 263 $response = rest_get_server()->dispatch( $request ); 264 $data = $response->get_data(); 265 $properties = $data['schema']['properties']; 266 $this->assertEquals( 12, count( $properties ) ); 267 $this->assertArrayHasKey( 'author', $properties ); 268 $this->assertArrayHasKey( 'content', $properties ); 269 $this->assertArrayHasKey( 'date', $properties ); 270 $this->assertArrayHasKey( 'date_gmt', $properties ); 271 $this->assertArrayHasKey( 'excerpt', $properties ); 272 $this->assertArrayHasKey( 'guid', $properties ); 273 $this->assertArrayHasKey( 'id', $properties ); 274 $this->assertArrayHasKey( 'modified', $properties ); 275 $this->assertArrayHasKey( 'modified_gmt', $properties ); 276 $this->assertArrayHasKey( 'parent', $properties ); 277 $this->assertArrayHasKey( 'slug', $properties ); 278 $this->assertArrayHasKey( 'title', $properties ); 279 } 280 281 public function test_create_item() { 282 wp_set_current_user( self::$editor_id ); 283 284 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 285 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 286 287 $params = $this->set_post_data( 288 array( 289 'id' => self::$post_id, 290 ) 291 ); 292 $request->set_body_params( $params ); 293 $response = rest_get_server()->dispatch( $request ); 294 295 $this->check_create_autosave_response( $response ); 296 } 297 298 public function test_update_item() { 299 wp_set_current_user( self::$editor_id ); 300 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 301 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 302 303 $params = $this->set_post_data( 304 array( 305 'id' => self::$post_id, 306 'author' => self::$contributor_id, 307 ) 308 ); 309 310 $request->set_body_params( $params ); 311 $response = rest_get_server()->dispatch( $request ); 312 313 $this->check_create_autosave_response( $response ); 314 } 315 316 public function test_update_item_nopriv() { 317 wp_set_current_user( self::$contributor_id ); 318 319 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 320 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 321 322 $params = $this->set_post_data( 323 array( 324 'id' => self::$post_id, 325 'author' => self::$editor_id, 326 ) 327 ); 328 329 $request->set_body_params( $params ); 330 $response = rest_get_server()->dispatch( $request ); 331 332 $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 ); 333 } 334 335 public function test_rest_autosave_published_post() { 336 wp_set_current_user( self::$editor_id ); 337 338 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 339 $request->add_header( 'content-type', 'application/json' ); 340 341 $current_post = get_post( self::$post_id ); 342 343 $autosave_data = $this->set_post_data( 344 array( 345 'id' => self::$post_id, 346 'content' => 'Updated post \ content', 347 'excerpt' => $current_post->post_excerpt, 348 'title' => $current_post->post_title, 349 ) 350 ); 351 352 $request->set_body( wp_json_encode( $autosave_data ) ); 353 $response = rest_get_server()->dispatch( $request ); 354 $new_data = $response->get_data(); 355 356 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 357 $this->assertEquals( $current_post->post_title, $new_data['title']['raw'] ); 358 $this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] ); 359 // Updated post_content 360 $this->assertNotEquals( $current_post->post_content, $new_data['content']['raw'] ); 361 362 $autosave_post = wp_get_post_autosave( self::$post_id ); 363 $this->assertEquals( $autosave_data['title'], $autosave_post->post_title ); 364 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 365 $this->assertEquals( $autosave_data['excerpt'], $autosave_post->post_excerpt ); 366 } 367 368 public function test_rest_autosave_draft_post_same_author() { 369 wp_set_current_user( self::$editor_id ); 370 371 $post_data = array( 372 'post_content' => 'Test post content', 373 'post_title' => 'Test post title', 374 'post_excerpt' => 'Test post excerpt', 375 ); 376 $post_id = wp_insert_post( $post_data ); 377 378 $autosave_data = array( 379 'id' => $post_id, 380 'content' => 'Updated post \ content', 381 'title' => 'Updated post title', 382 ); 383 384 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 385 $request->add_header( 'content-type', 'application/json' ); 386 $request->set_body( wp_json_encode( $autosave_data ) ); 387 388 $response = rest_get_server()->dispatch( $request ); 389 $new_data = $response->get_data(); 390 $post = get_post( $post_id ); 391 392 $this->assertEquals( $post_id, $new_data['id'] ); 393 // The draft post should be updated. 394 $this->assertEquals( $autosave_data['content'], $new_data['content']['raw'] ); 395 $this->assertEquals( $autosave_data['title'], $new_data['title']['raw'] ); 396 $this->assertEquals( $autosave_data['content'], $post->post_content ); 397 $this->assertEquals( $autosave_data['title'], $post->post_title ); 398 399 // Not updated. 400 $this->assertEquals( $post_data['post_excerpt'], $post->post_excerpt ); 401 402 wp_delete_post( $post_id ); 403 } 404 405 public function test_rest_autosave_draft_post_different_author() { 406 wp_set_current_user( self::$editor_id ); 407 408 $post_data = array( 409 'post_content' => 'Test post content', 410 'post_title' => 'Test post title', 411 'post_excerpt' => 'Test post excerpt', 412 'post_author' => self::$editor_id + 1, 413 ); 414 $post_id = wp_insert_post( $post_data ); 415 416 $autosave_data = array( 417 'id' => $post_id, 418 'content' => 'Updated post content', 419 'excerpt' => $post_data['post_excerpt'], 420 'title' => $post_data['post_title'], 421 ); 422 423 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 424 $request->add_header( 'content-type', 'application/json' ); 425 $request->set_body( wp_json_encode( $autosave_data ) ); 426 427 $response = rest_get_server()->dispatch( $request ); 428 $new_data = $response->get_data(); 429 $current_post = get_post( $post_id ); 430 431 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 432 433 // The draft post shouldn't change. 434 $this->assertEquals( $current_post->post_title, $post_data['post_title'] ); 435 $this->assertEquals( $current_post->post_content, $post_data['post_content'] ); 436 $this->assertEquals( $current_post->post_excerpt, $post_data['post_excerpt'] ); 437 438 $autosave_post = wp_get_post_autosave( $post_id ); 439 440 // No changes 441 $this->assertEquals( $current_post->post_title, $autosave_post->post_title ); 442 $this->assertEquals( $current_post->post_excerpt, $autosave_post->post_excerpt ); 443 444 // Has changes 445 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 446 447 wp_delete_post( $post_id ); 448 } 449 450 public function test_get_additional_field_registration() { 451 $schema = array( 452 'type' => 'integer', 453 'description' => 'Some integer of mine', 454 'enum' => array( 1, 2, 3, 4 ), 455 'context' => array( 'view', 'edit' ), 456 ); 457 458 register_rest_field( 459 'post-revision', 'my_custom_int', array( 460 'schema' => $schema, 461 'get_callback' => array( $this, 'additional_field_get_callback' ), 462 'update_callback' => array( $this, 'additional_field_update_callback' ), 463 ) 464 ); 465 466 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 467 468 $response = rest_get_server()->dispatch( $request ); 469 $data = $response->get_data(); 470 471 $this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] ); 472 $this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] ); 473 474 wp_set_current_user( 1 ); 475 476 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 477 478 $response = rest_get_server()->dispatch( $request ); 479 $this->assertArrayHasKey( 'my_custom_int', $response->data ); 480 481 global $wp_rest_additional_fields; 482 $wp_rest_additional_fields = array(); 483 } 484 485 public function additional_field_get_callback( $object ) { 486 return get_post_meta( $object['id'], 'my_custom_int', true ); 487 } 488 489 public function additional_field_update_callback( $value, $post ) { 490 update_post_meta( $post->ID, 'my_custom_int', $value ); 491 } 492 493 protected function check_get_autosave_response( $response, $autosave ) { 494 if ( $response instanceof WP_REST_Response ) { 495 $links = $response->get_links(); 496 $response = $response->get_data(); 497 } else { 498 $this->assertArrayHasKey( '_links', $response ); 499 $links = $response['_links']; 500 } 501 502 $this->assertEquals( $autosave->post_author, $response['author'] ); 503 504 $rendered_content = apply_filters( 'the_content', $autosave->post_content ); 505 $this->assertEquals( $rendered_content, $response['content']['rendered'] ); 506 507 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date ), $response['date'] ); 508 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date_gmt ), $response['date_gmt'] ); 509 510 $rendered_guid = apply_filters( 'get_the_guid', $autosave->guid, $autosave->ID ); 511 $this->assertEquals( $rendered_guid, $response['guid']['rendered'] ); 512 513 $this->assertEquals( $autosave->ID, $response['id'] ); 514 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified ), $response['modified'] ); 515 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified_gmt ), $response['modified_gmt'] ); 516 $this->assertEquals( $autosave->post_name, $response['slug'] ); 517 518 $rendered_title = get_the_title( $autosave->ID ); 519 $this->assertEquals( $rendered_title, $response['title']['rendered'] ); 520 521 $parent = get_post( $autosave->post_parent ); 522 $parent_controller = new WP_REST_Posts_Controller( $parent->post_type ); 523 $parent_object = get_post_type_object( $parent->post_type ); 524 $parent_base = ! empty( $parent_object->rest_base ) ? $parent_object->rest_base : $parent_object->name; 525 $this->assertEquals( rest_url( '/wp/v2/' . $parent_base . '/' . $autosave->post_parent ), $links['parent'][0]['href'] ); 526 } 527 528 public function test_get_item_sets_up_postdata() { 529 wp_set_current_user( self::$editor_id ); 530 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 531 rest_get_server()->dispatch( $request ); 532 533 $post = get_post(); 534 $parent_post_id = wp_is_post_revision( $post->ID ); 535 536 $this->assertEquals( $post->ID, self::$autosave_post_id ); 537 $this->assertEquals( $parent_post_id, self::$post_id ); 538 } 539 540 } -
tests/phpunit/tests/rest-api/rest-schema-setup.php
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', … … 159 163 $post_revisions = array_values( wp_get_post_revisions( $post_id ) ); 160 164 $post_revision_id = $post_revisions[ count( $post_revisions ) - 1 ]->ID; 161 165 166 // Create an autosave. 167 wp_create_post_autosave( 168 array( 169 'post_ID' => $post_id, 170 'post_content' => 'Autosave post content.', 171 'post_type' => 'post', 172 ) 173 ); 174 162 175 $page_id = $this->factory->post->create( 163 176 array( 164 177 'post_type' => 'page', … … 180 193 $page_revisions = array_values( wp_get_post_revisions( $page_id ) ); 181 194 $page_revision_id = $page_revisions[ count( $page_revisions ) - 1 ]->ID; 182 195 196 // Create an autosave. 197 wp_create_post_autosave( 198 array( 199 'post_ID' => $page_id, 200 'post_content' => 'Autosave page content.', 201 'post_type' => 'page', 202 ) 203 ); 204 183 205 $tag_id = $this->factory->tag->create( 184 206 array( 185 207 'name' => 'REST API Client Fixture: Tag', … … 272 294 'name' => 'revision', 273 295 ), 274 296 array( 297 'route' => '/wp/v2/posts/' . $post_id . '/autosaves', 298 'name' => 'postAutosaves', 299 ), 300 array( 301 'route' => '/wp/v2/posts/' . $post_id . '/autosaves/' . $post_revision_id, 302 'name' => 'autosave', 303 ), 304 array( 275 305 'route' => '/wp/v2/pages', 276 306 'name' => 'PagesCollection', 277 307 ), … … 288 318 'name' => 'pageRevision', 289 319 ), 290 320 array( 321 'route' => '/wp/v2/pages/' . $page_id . '/autosaves', 322 'name' => 'pageAutosaves', 323 ), 324 array( 325 'route' => '/wp/v2/pages/' . $page_id . '/autosaves/' . $page_revision_id, 326 'name' => 'pageAutosave', 327 ), 328 array( 291 329 'route' => '/wp/v2/media', 292 330 'name' => 'MediaCollection', 293 331 ), -
tests/qunit/fixtures/wp-api-generated.js
783 783 } 784 784 ] 785 785 }, 786 "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves": { 787 "namespace": "wp/v2", 788 "methods": [ 789 "GET", 790 "POST" 791 ], 792 "endpoints": [ 793 { 794 "methods": [ 795 "GET" 796 ], 797 "args": { 798 "parent": { 799 "required": false, 800 "description": "The ID for the parent of the object.", 801 "type": "integer" 802 }, 803 "context": { 804 "required": false, 805 "default": "view", 806 "enum": [ 807 "view", 808 "embed", 809 "edit" 810 ], 811 "description": "Scope under which the request is made; determines fields present in response.", 812 "type": "string" 813 } 814 } 815 }, 816 { 817 "methods": [ 818 "POST" 819 ], 820 "args": { 821 "parent": { 822 "required": false, 823 "description": "The ID for the parent of the object.", 824 "type": "integer" 825 }, 826 "author": { 827 "required": false, 828 "description": "The ID for the author of the object.", 829 "type": "integer" 830 }, 831 "date": { 832 "required": false, 833 "description": "The date the object was published, in the site's timezone.", 834 "type": "string" 835 }, 836 "date_gmt": { 837 "required": false, 838 "description": "The date the object was published, as GMT.", 839 "type": "string" 840 }, 841 "id": { 842 "required": false, 843 "description": "Unique identifier for the object.", 844 "type": "integer" 845 }, 846 "modified": { 847 "required": false, 848 "description": "The date the object was last modified, in the site's timezone.", 849 "type": "string" 850 }, 851 "modified_gmt": { 852 "required": false, 853 "description": "The date the object was last modified, as GMT.", 854 "type": "string" 855 }, 856 "slug": { 857 "required": false, 858 "description": "An alphanumeric identifier for the object unique to its type.", 859 "type": "string" 860 }, 861 "title": { 862 "required": false, 863 "description": "The title for the object.", 864 "type": "object" 865 }, 866 "content": { 867 "required": false, 868 "description": "The content for the object.", 869 "type": "object" 870 }, 871 "excerpt": { 872 "required": false, 873 "description": "The excerpt for the object.", 874 "type": "object" 875 } 876 } 877 } 878 ] 879 }, 880 "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 881 "namespace": "wp/v2", 882 "methods": [ 883 "GET", 884 "DELETE" 885 ], 886 "endpoints": [ 887 { 888 "methods": [ 889 "GET" 890 ], 891 "args": { 892 "parent": { 893 "required": false, 894 "description": "The ID for the parent of the object.", 895 "type": "integer" 896 }, 897 "id": { 898 "required": false, 899 "description": "The ID for the object.", 900 "type": "integer" 901 }, 902 "context": { 903 "required": false, 904 "default": "view", 905 "enum": [ 906 "view", 907 "embed", 908 "edit" 909 ], 910 "description": "Scope under which the request is made; determines fields present in response.", 911 "type": "string" 912 } 913 } 914 }, 915 { 916 "methods": [ 917 "DELETE" 918 ], 919 "args": { 920 "parent": { 921 "required": false, 922 "description": "The ID for the parent of the object.", 923 "type": "integer" 924 }, 925 "id": { 926 "required": false, 927 "description": "The ID for the object.", 928 "type": "integer" 929 }, 930 "force": { 931 "required": false, 932 "default": false, 933 "description": "Required to be true, as autosaves do not support trashing.", 934 "type": "boolean" 935 } 936 } 937 } 938 ] 939 }, 786 940 "/wp/v2/pages": { 787 941 "namespace": "wp/v2", 788 942 "methods": [ … … 1321 1475 } 1322 1476 ] 1323 1477 }, 1478 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves": { 1479 "namespace": "wp/v2", 1480 "methods": [ 1481 "GET", 1482 "POST" 1483 ], 1484 "endpoints": [ 1485 { 1486 "methods": [ 1487 "GET" 1488 ], 1489 "args": { 1490 "parent": { 1491 "required": false, 1492 "description": "The ID for the parent of the object.", 1493 "type": "integer" 1494 }, 1495 "context": { 1496 "required": false, 1497 "default": "view", 1498 "enum": [ 1499 "view", 1500 "embed", 1501 "edit" 1502 ], 1503 "description": "Scope under which the request is made; determines fields present in response.", 1504 "type": "string" 1505 } 1506 } 1507 }, 1508 { 1509 "methods": [ 1510 "POST" 1511 ], 1512 "args": { 1513 "parent": { 1514 "required": false, 1515 "description": "The ID for the parent of the object.", 1516 "type": "integer" 1517 }, 1518 "author": { 1519 "required": false, 1520 "description": "The ID for the author of the object.", 1521 "type": "integer" 1522 }, 1523 "date": { 1524 "required": false, 1525 "description": "The date the object was published, in the site's timezone.", 1526 "type": "string" 1527 }, 1528 "date_gmt": { 1529 "required": false, 1530 "description": "The date the object was published, as GMT.", 1531 "type": "string" 1532 }, 1533 "id": { 1534 "required": false, 1535 "description": "Unique identifier for the object.", 1536 "type": "integer" 1537 }, 1538 "modified": { 1539 "required": false, 1540 "description": "The date the object was last modified, in the site's timezone.", 1541 "type": "string" 1542 }, 1543 "modified_gmt": { 1544 "required": false, 1545 "description": "The date the object was last modified, as GMT.", 1546 "type": "string" 1547 }, 1548 "slug": { 1549 "required": false, 1550 "description": "An alphanumeric identifier for the object unique to its type.", 1551 "type": "string" 1552 }, 1553 "title": { 1554 "required": false, 1555 "description": "The title for the object.", 1556 "type": "object" 1557 }, 1558 "content": { 1559 "required": false, 1560 "description": "The content for the object.", 1561 "type": "object" 1562 }, 1563 "excerpt": { 1564 "required": false, 1565 "description": "The excerpt for the object.", 1566 "type": "object" 1567 } 1568 } 1569 } 1570 ] 1571 }, 1572 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 1573 "namespace": "wp/v2", 1574 "methods": [ 1575 "GET", 1576 "DELETE" 1577 ], 1578 "endpoints": [ 1579 { 1580 "methods": [ 1581 "GET" 1582 ], 1583 "args": { 1584 "parent": { 1585 "required": false, 1586 "description": "The ID for the parent of the object.", 1587 "type": "integer" 1588 }, 1589 "id": { 1590 "required": false, 1591 "description": "The ID for the object.", 1592 "type": "integer" 1593 }, 1594 "context": { 1595 "required": false, 1596 "default": "view", 1597 "enum": [ 1598 "view", 1599 "embed", 1600 "edit" 1601 ], 1602 "description": "Scope under which the request is made; determines fields present in response.", 1603 "type": "string" 1604 } 1605 } 1606 }, 1607 { 1608 "methods": [ 1609 "DELETE" 1610 ], 1611 "args": { 1612 "parent": { 1613 "required": false, 1614 "description": "The ID for the parent of the object.", 1615 "type": "integer" 1616 }, 1617 "id": { 1618 "required": false, 1619 "description": "The ID for the object.", 1620 "type": "integer" 1621 }, 1622 "force": { 1623 "required": false, 1624 "default": false, 1625 "description": "Required to be true, as autosaves do not support trashing.", 1626 "type": "boolean" 1627 } 1628 } 1629 } 1630 ] 1631 }, 1324 1632 "/wp/v2/media": { 1325 1633 "namespace": "wp/v2", 1326 1634 "methods": [ … … 3670 3978 "rendered": "http://example.org/?p=4" 3671 3979 }, 3672 3980 "title": { 3981 "rendered": "" 3982 }, 3983 "content": { 3984 "rendered": "<p>Autosave post content.</p>\n" 3985 }, 3986 "excerpt": { 3987 "rendered": "" 3988 }, 3989 "_links": { 3990 "parent": [ 3991 { 3992 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3" 3993 } 3994 ] 3995 } 3996 }, 3997 { 3998 "author": 2, 3999 "date": "2017-02-14T00:00:00", 4000 "date_gmt": "2017-02-14T00:00:00", 4001 "id": 4, 4002 "modified": "2017-02-14T00:00:00", 4003 "modified_gmt": "2017-02-14T00:00:00", 4004 "parent": 3, 4005 "slug": "3-revision-v1", 4006 "guid": { 4007 "rendered": "http://example.org/?p=4" 4008 }, 4009 "title": { 3673 4010 "rendered": "REST API Client Fixture: Post" 3674 4011 }, 3675 4012 "content": { … … 3711 4048 } 3712 4049 }; 3713 4050 4051 mockedApiResponse.postAutosaves = [ 4052 { 4053 "author": 2, 4054 "date": "2017-02-14T00:00:00", 4055 "date_gmt": "2017-02-14T00:00:00", 4056 "id": 5, 4057 "modified": "2017-02-14T00:00:00", 4058 "modified_gmt": "2017-02-14T00:00:00", 4059 "parent": 3, 4060 "slug": "3-autosave-v1", 4061 "guid": { 4062 "rendered": "http://example.org/?p=5" 4063 }, 4064 "title": { 4065 "rendered": "" 4066 }, 4067 "content": { 4068 "rendered": "<p>Autosave post content.</p>\n" 4069 }, 4070 "excerpt": { 4071 "rendered": "" 4072 }, 4073 "_links": { 4074 "parent": [ 4075 { 4076 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/3" 4077 } 4078 ] 4079 } 4080 } 4081 ]; 4082 4083 mockedApiResponse.autosave = { 4084 "author": 2, 4085 "date": "2017-02-14T00:00:00", 4086 "date_gmt": "2017-02-14T00:00:00", 4087 "id": 5, 4088 "modified": "2017-02-14T00:00:00", 4089 "modified_gmt": "2017-02-14T00:00:00", 4090 "parent": 3, 4091 "slug": "3-autosave-v1", 4092 "guid": { 4093 "rendered": "http://example.org/?p=5" 4094 }, 4095 "title": { 4096 "rendered": "" 4097 }, 4098 "content": { 4099 "rendered": "<p>Autosave post content.</p>\n" 4100 }, 4101 "excerpt": { 4102 "rendered": "" 4103 } 4104 }; 4105 3714 4106 mockedApiResponse.PagesCollection = [ 3715 4107 { 3716 4108 "id": 5, … … 3839 4231 "rendered": "http://example.org/?p=6" 3840 4232 }, 3841 4233 "title": { 4234 "rendered": "" 4235 }, 4236 "content": { 4237 "rendered": "<p>Autosave page content.</p>\n" 4238 }, 4239 "excerpt": { 4240 "rendered": "" 4241 }, 4242 "_links": { 4243 "parent": [ 4244 { 4245 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/5" 4246 } 4247 ] 4248 } 4249 }, 4250 { 4251 "author": 2, 4252 "date": "2017-02-14T00:00:00", 4253 "date_gmt": "2017-02-14T00:00:00", 4254 "id": 7, 4255 "modified": "2017-02-14T00:00:00", 4256 "modified_gmt": "2017-02-14T00:00:00", 4257 "parent": 6, 4258 "slug": "6-revision-v1", 4259 "guid": { 4260 "rendered": "http://example.org/?p=7" 4261 }, 4262 "title": { 3842 4263 "rendered": "REST API Client Fixture: Page" 3843 4264 }, 3844 4265 "content": { … … 3850 4271 "_links": { 3851 4272 "parent": [ 3852 4273 { 3853 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/ 5"4274 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6" 3854 4275 } 3855 4276 ] 3856 4277 } … … 3880 4301 } 3881 4302 }; 3882 4303 4304 mockedApiResponse.pageAutosaves = [ 4305 { 4306 "author": 2, 4307 "date": "2017-02-14T00:00:00", 4308 "date_gmt": "2017-02-14T00:00:00", 4309 "id": 8, 4310 "modified": "2017-02-14T00:00:00", 4311 "modified_gmt": "2017-02-14T00:00:00", 4312 "parent": 6, 4313 "slug": "6-autosave-v1", 4314 "guid": { 4315 "rendered": "http://example.org/?p=8" 4316 }, 4317 "title": { 4318 "rendered": "" 4319 }, 4320 "content": { 4321 "rendered": "<p>Autosave page content.</p>\n" 4322 }, 4323 "excerpt": { 4324 "rendered": "" 4325 }, 4326 "_links": { 4327 "parent": [ 4328 { 4329 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6" 4330 } 4331 ] 4332 } 4333 } 4334 ]; 4335 4336 mockedApiResponse.pageAutosave = { 4337 "author": 2, 4338 "date": "2017-02-14T00:00:00", 4339 "date_gmt": "2017-02-14T00:00:00", 4340 "id": 8, 4341 "modified": "2017-02-14T00:00:00", 4342 "modified_gmt": "2017-02-14T00:00:00", 4343 "parent": 6, 4344 "slug": "6-autosave-v1", 4345 "guid": { 4346 "rendered": "http://example.org/?p=8" 4347 }, 4348 "title": { 4349 "rendered": "" 4350 }, 4351 "content": { 4352 "rendered": "<p>Autosave page content.</p>\n" 4353 }, 4354 "excerpt": { 4355 "rendered": "" 4356 } 4357 }; 4358 3883 4359 mockedApiResponse.MediaCollection = [ 3884 4360 { 3885 4361 "id": 7,