Ticket #43316: 43316.22.diff
File 43316.22.diff, 60.9 KB (added by , 6 years ago) |
---|
-
phpunit.xml.dist
diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f81a85e516..1d894aaa8f 100644
a b 6 6 > 7 7 <testsuites> 8 8 <!-- Default test suite to run all tests --> 9 <testsuite >9 <testsuite name="default"> 10 10 <directory suffix=".php">tests/phpunit/tests</directory> 11 11 <exclude>tests/phpunit/tests/actions/closures.php</exclude> 12 12 <exclude>tests/phpunit/tests/image/editor.php</exclude> 13 13 <exclude>tests/phpunit/tests/image/editorGd.php</exclude> 14 14 <exclude>tests/phpunit/tests/image/editorImagick.php</exclude> 15 15 <exclude>tests/phpunit/tests/oembed/headers.php</exclude> 16 <exclude>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</exclude> 16 17 <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file> 17 18 <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file> 18 19 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file> 19 20 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file> 20 21 <file phpVersion="5.3.0">tests/phpunit/tests/oembed/headers.php</file> 21 22 </testsuite> 23 <!-- Sets the DOING_AUTOSAVE constant, so needs to be run last --> 24 <testsuite name="restapi-autosave"> 25 <file>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</file> 26 </testsuite> 22 27 </testsuites> 23 28 <groups> 24 29 <exclude> -
src/wp-includes/rest-api.php
diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 72ee1b696e..ebc3d9a053 100644
a b function create_initial_rest_routes() { 193 193 $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name ); 194 194 $revisions_controller->register_routes(); 195 195 } 196 197 if ( 'attachment' !== $post_type->name ) { 198 $autosaves_controller = new WP_REST_Autosaves_Controller( $post_type->name ); 199 $autosaves_controller->register_routes(); 200 } 201 196 202 } 197 203 198 204 // Post types. -
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..79529213c3
- + 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.' ), 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.' ), 113 'type' => 'integer', 114 ), 115 'id' => array( 116 'description' => __( 'The ID for the object.' ), 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.' ), 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.' ), 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.' ), 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.' ), 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.' ), 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 $fields = $this->get_fields_for_response( $request ); 361 362 if ( in_array( 'preview_link', $fields, true ) ) { 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->add_additional_fields_to_object( $response->data, $request ); 377 $response->data = $this->filter_response_by_context( $response->data, $context ); 378 379 /** 380 * Filters a revision returned from the API. 381 * 382 * Allows modification of the revision right before it is returned. 383 * 384 * @since 5.0.0 385 * 386 * @param WP_REST_Response $response The response object. 387 * @param WP_Post $post The original revision object. 388 * @param WP_REST_Request $request Request used to generate the response. 389 */ 390 return apply_filters( 'rest_prepare_autosave', $response, $post, $request ); 391 } 392 } -
src/wp-settings.php
diff --git a/src/wp-settings.php b/src/wp-settings.php index c0f0816130..f711b9167b 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..ede81c5f25
- + 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 107 // Collection. 108 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 109 $response = rest_get_server()->dispatch( $request ); 110 $data = $response->get_data(); 111 $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] ); 112 $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] ); 113 114 // Single. 115 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 116 $response = rest_get_server()->dispatch( $request ); 117 $data = $response->get_data(); 118 $this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] ); 119 $this->assertEqualSets( array( 'view', 'edit', 'embed' ), $data['endpoints'][0]['args']['context']['enum'] ); 120 } 121 122 public function test_get_items() { 123 wp_set_current_user( self::$editor_id ); 124 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 125 $response = rest_get_server()->dispatch( $request ); 126 $data = $response->get_data(); 127 $this->assertEquals( 200, $response->get_status() ); 128 $this->assertCount( 1, $data ); 129 130 $this->assertEquals( self::$autosave_post_id, $data[0]['id'] ); 131 132 $this->check_get_autosave_response( $data[0], $this->post_autosave ); 133 } 134 135 public function test_get_items_no_permission() { 136 wp_set_current_user( 0 ); 137 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 138 $response = rest_get_server()->dispatch( $request ); 139 $this->assertErrorResponse( 'rest_cannot_read', $response, 401 ); 140 wp_set_current_user( self::$contributor_id ); 141 $response = rest_get_server()->dispatch( $request ); 142 $this->assertErrorResponse( 'rest_cannot_read', $response, 403 ); 143 } 144 145 public function test_get_items_missing_parent() { 146 wp_set_current_user( self::$editor_id ); 147 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves' ); 148 $response = rest_get_server()->dispatch( $request ); 149 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 150 } 151 152 public function test_get_items_invalid_parent_post_type() { 153 wp_set_current_user( self::$editor_id ); 154 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' ); 155 $response = rest_get_server()->dispatch( $request ); 156 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 157 } 158 159 public function test_get_item() { 160 wp_set_current_user( self::$editor_id ); 161 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 162 $response = rest_get_server()->dispatch( $request ); 163 $this->assertEquals( 200, $response->get_status() ); 164 $data = $response->get_data(); 165 166 $this->check_get_autosave_response( $response, $this->post_autosave ); 167 $fields = array( 168 'author', 169 'date', 170 'date_gmt', 171 'modified', 172 'modified_gmt', 173 'guid', 174 'id', 175 'parent', 176 'slug', 177 'title', 178 'excerpt', 179 'content', 180 ); 181 $this->assertEqualSets( $fields, array_keys( $data ) ); 182 $this->assertSame( self::$editor_id, $data['author'] ); 183 } 184 185 public function test_get_item_embed_context() { 186 wp_set_current_user( self::$editor_id ); 187 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 188 $request->set_param( 'context', 'embed' ); 189 $response = rest_get_server()->dispatch( $request ); 190 $fields = array( 191 'author', 192 'date', 193 'id', 194 'parent', 195 'slug', 196 'title', 197 'excerpt', 198 ); 199 $data = $response->get_data(); 200 $this->assertEqualSets( $fields, array_keys( $data ) ); 201 } 202 203 public function test_get_item_no_permission() { 204 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 205 wp_set_current_user( self::$contributor_id ); 206 $response = rest_get_server()->dispatch( $request ); 207 $this->assertErrorResponse( 'rest_cannot_read', $response, 403 ); 208 } 209 210 public function test_get_item_missing_parent() { 211 wp_set_current_user( self::$editor_id ); 212 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/autosaves/' . self::$autosave_post_id ); 213 $response = rest_get_server()->dispatch( $request ); 214 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 215 216 } 217 218 public function test_get_item_invalid_parent_post_type() { 219 wp_set_current_user( self::$editor_id ); 220 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$page_id . '/autosaves' ); 221 $response = rest_get_server()->dispatch( $request ); 222 $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 ); 223 } 224 225 public function test_delete_item() { 226 // Doesn't exist. 227 } 228 229 public function test_prepare_item() { 230 wp_set_current_user( self::$editor_id ); 231 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 232 $response = rest_get_server()->dispatch( $request ); 233 $this->assertEquals( 200, $response->get_status() ); 234 $this->check_get_autosave_response( $response, $this->post_autosave ); 235 } 236 237 public function test_get_item_schema() { 238 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 239 $response = rest_get_server()->dispatch( $request ); 240 $data = $response->get_data(); 241 $properties = $data['schema']['properties']; 242 $this->assertEquals( 13, count( $properties ) ); 243 $this->assertArrayHasKey( 'author', $properties ); 244 $this->assertArrayHasKey( 'content', $properties ); 245 $this->assertArrayHasKey( 'date', $properties ); 246 $this->assertArrayHasKey( 'date_gmt', $properties ); 247 $this->assertArrayHasKey( 'excerpt', $properties ); 248 $this->assertArrayHasKey( 'guid', $properties ); 249 $this->assertArrayHasKey( 'id', $properties ); 250 $this->assertArrayHasKey( 'modified', $properties ); 251 $this->assertArrayHasKey( 'modified_gmt', $properties ); 252 $this->assertArrayHasKey( 'parent', $properties ); 253 $this->assertArrayHasKey( 'slug', $properties ); 254 $this->assertArrayHasKey( 'title', $properties ); 255 $this->assertArrayHasKey( 'preview_link', $properties ); 256 } 257 258 public function test_create_item() { 259 wp_set_current_user( self::$editor_id ); 260 261 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 262 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 263 264 $params = $this->set_post_data( 265 array( 266 'id' => self::$post_id, 267 ) 268 ); 269 $request->set_body_params( $params ); 270 $response = rest_get_server()->dispatch( $request ); 271 272 $this->check_create_autosave_response( $response ); 273 } 274 275 public function test_update_item() { 276 wp_set_current_user( self::$editor_id ); 277 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 278 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 279 280 $params = $this->set_post_data( 281 array( 282 'id' => self::$post_id, 283 'author' => self::$contributor_id, 284 ) 285 ); 286 287 $request->set_body_params( $params ); 288 $response = rest_get_server()->dispatch( $request ); 289 290 $this->check_create_autosave_response( $response ); 291 } 292 293 public function test_update_item_nopriv() { 294 wp_set_current_user( self::$contributor_id ); 295 296 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 297 $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); 298 299 $params = $this->set_post_data( 300 array( 301 'id' => self::$post_id, 302 'author' => self::$editor_id, 303 ) 304 ); 305 306 $request->set_body_params( $params ); 307 $response = rest_get_server()->dispatch( $request ); 308 309 $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 ); 310 } 311 312 public function test_rest_autosave_published_post() { 313 wp_set_current_user( self::$editor_id ); 314 315 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 316 $request->add_header( 'content-type', 'application/json' ); 317 318 $current_post = get_post( self::$post_id ); 319 320 $autosave_data = $this->set_post_data( 321 array( 322 'id' => self::$post_id, 323 'content' => 'Updated post \ content', 324 'excerpt' => $current_post->post_excerpt, 325 'title' => $current_post->post_title, 326 ) 327 ); 328 329 $request->set_body( wp_json_encode( $autosave_data ) ); 330 $response = rest_get_server()->dispatch( $request ); 331 $new_data = $response->get_data(); 332 333 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 334 $this->assertEquals( $current_post->post_title, $new_data['title']['raw'] ); 335 $this->assertEquals( $current_post->post_excerpt, $new_data['excerpt']['raw'] ); 336 337 // Updated post_content. 338 $this->assertNotEquals( $current_post->post_content, $new_data['content']['raw'] ); 339 340 $autosave_post = wp_get_post_autosave( self::$post_id ); 341 $this->assertEquals( $autosave_data['title'], $autosave_post->post_title ); 342 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 343 $this->assertEquals( $autosave_data['excerpt'], $autosave_post->post_excerpt ); 344 } 345 346 public function test_rest_autosave_draft_post_same_author() { 347 wp_set_current_user( self::$editor_id ); 348 349 $post_data = array( 350 'post_content' => 'Test post content', 351 'post_title' => 'Test post title', 352 'post_excerpt' => 'Test post excerpt', 353 ); 354 $post_id = wp_insert_post( $post_data ); 355 356 $autosave_data = array( 357 'id' => $post_id, 358 'content' => 'Updated post \ content', 359 'title' => 'Updated post title', 360 ); 361 362 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 363 $request->add_header( 'content-type', 'application/json' ); 364 $request->set_body( wp_json_encode( $autosave_data ) ); 365 366 $response = rest_get_server()->dispatch( $request ); 367 $new_data = $response->get_data(); 368 $post = get_post( $post_id ); 369 370 $this->assertEquals( $post_id, $new_data['id'] ); 371 // The draft post should be updated. 372 $this->assertEquals( $autosave_data['content'], $new_data['content']['raw'] ); 373 $this->assertEquals( $autosave_data['title'], $new_data['title']['raw'] ); 374 $this->assertEquals( $autosave_data['content'], $post->post_content ); 375 $this->assertEquals( $autosave_data['title'], $post->post_title ); 376 377 // Not updated. 378 $this->assertEquals( $post_data['post_excerpt'], $post->post_excerpt ); 379 380 wp_delete_post( $post_id ); 381 } 382 383 public function test_rest_autosave_draft_post_different_author() { 384 wp_set_current_user( self::$editor_id ); 385 386 $post_data = array( 387 'post_content' => 'Test post content', 388 'post_title' => 'Test post title', 389 'post_excerpt' => 'Test post excerpt', 390 'post_author' => self::$editor_id + 1, 391 ); 392 $post_id = wp_insert_post( $post_data ); 393 394 $autosave_data = array( 395 'id' => $post_id, 396 'content' => 'Updated post content', 397 'excerpt' => $post_data['post_excerpt'], 398 'title' => $post_data['post_title'], 399 ); 400 401 $request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 402 $request->add_header( 'content-type', 'application/json' ); 403 $request->set_body( wp_json_encode( $autosave_data ) ); 404 405 $response = rest_get_server()->dispatch( $request ); 406 $new_data = $response->get_data(); 407 $current_post = get_post( $post_id ); 408 409 $this->assertEquals( $current_post->ID, $new_data['parent'] ); 410 411 // The draft post shouldn't change. 412 $this->assertEquals( $current_post->post_title, $post_data['post_title'] ); 413 $this->assertEquals( $current_post->post_content, $post_data['post_content'] ); 414 $this->assertEquals( $current_post->post_excerpt, $post_data['post_excerpt'] ); 415 416 $autosave_post = wp_get_post_autosave( $post_id ); 417 418 // No changes. 419 $this->assertEquals( $current_post->post_title, $autosave_post->post_title ); 420 $this->assertEquals( $current_post->post_excerpt, $autosave_post->post_excerpt ); 421 422 // Has changes. 423 $this->assertEquals( $autosave_data['content'], $autosave_post->post_content ); 424 425 wp_delete_post( $post_id ); 426 } 427 428 public function test_get_additional_field_registration() { 429 $schema = array( 430 'type' => 'integer', 431 'description' => 'Some integer of mine', 432 'enum' => array( 1, 2, 3, 4 ), 433 'context' => array( 'view', 'edit' ), 434 ); 435 436 register_rest_field( 437 'post-revision', 438 'my_custom_int', 439 array( 440 'schema' => $schema, 441 'get_callback' => array( $this, 'additional_field_get_callback' ), 442 'update_callback' => array( $this, 'additional_field_update_callback' ), 443 ) 444 ); 445 446 $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id . '/autosaves' ); 447 448 $response = rest_get_server()->dispatch( $request ); 449 $data = $response->get_data(); 450 451 $this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] ); 452 $this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] ); 453 454 wp_set_current_user( 1 ); 455 456 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 457 458 $response = rest_get_server()->dispatch( $request ); 459 $this->assertArrayHasKey( 'my_custom_int', $response->data ); 460 461 global $wp_rest_additional_fields; 462 $wp_rest_additional_fields = array(); 463 } 464 465 public function additional_field_get_callback( $object ) { 466 return get_post_meta( $object['id'], 'my_custom_int', true ); 467 } 468 469 public function additional_field_update_callback( $value, $post ) { 470 update_post_meta( $post->ID, 'my_custom_int', $value ); 471 } 472 473 protected function check_get_autosave_response( $response, $autosave ) { 474 if ( $response instanceof WP_REST_Response ) { 475 $links = $response->get_links(); 476 $response = $response->get_data(); 477 } else { 478 $this->assertArrayHasKey( '_links', $response ); 479 $links = $response['_links']; 480 } 481 482 $this->assertEquals( $autosave->post_author, $response['author'] ); 483 484 $rendered_content = apply_filters( 'the_content', $autosave->post_content ); 485 $this->assertEquals( $rendered_content, $response['content']['rendered'] ); 486 487 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date ), $response['date'] ); //@codingStandardsIgnoreLine 488 $this->assertEquals( mysql_to_rfc3339( $autosave->post_date_gmt ), $response['date_gmt'] ); //@codingStandardsIgnoreLine 489 490 $rendered_guid = apply_filters( 'get_the_guid', $autosave->guid, $autosave->ID ); 491 $this->assertEquals( $rendered_guid, $response['guid']['rendered'] ); 492 493 $this->assertEquals( $autosave->ID, $response['id'] ); 494 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified ), $response['modified'] ); //@codingStandardsIgnoreLine 495 $this->assertEquals( mysql_to_rfc3339( $autosave->post_modified_gmt ), $response['modified_gmt'] ); //@codingStandardsIgnoreLine 496 $this->assertEquals( $autosave->post_name, $response['slug'] ); 497 498 $rendered_title = get_the_title( $autosave->ID ); 499 $this->assertEquals( $rendered_title, $response['title']['rendered'] ); 500 501 $parent = get_post( $autosave->post_parent ); 502 $parent_controller = new WP_REST_Posts_Controller( $parent->post_type ); 503 $parent_object = get_post_type_object( $parent->post_type ); 504 $parent_base = ! empty( $parent_object->rest_base ) ? $parent_object->rest_base : $parent_object->name; 505 $this->assertEquals( rest_url( '/wp/v2/' . $parent_base . '/' . $autosave->post_parent ), $links['parent'][0]['href'] ); 506 } 507 508 public function test_get_item_sets_up_postdata() { 509 wp_set_current_user( self::$editor_id ); 510 $request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id . '/autosaves/' . self::$autosave_post_id ); 511 rest_get_server()->dispatch( $request ); 512 513 $post = get_post(); 514 $parent_post_id = wp_is_post_revision( $post->ID ); 515 516 $this->assertEquals( $post->ID, self::$autosave_post_id ); 517 $this->assertEquals( $parent_post_id, self::$post_id ); 518 } 519 520 } -
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 1b868316f0..70330b7f03 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 { 155 159 $post_revisions = array_values( wp_get_post_revisions( $post_id ) ); 156 160 $post_revision_id = $post_revisions[ count( $post_revisions ) - 1 ]->ID; 157 161 162 // Create an autosave. 163 wp_create_post_autosave( 164 array( 165 'post_ID' => $post_id, 166 'post_content' => 'Autosave post content.', 167 'post_type' => 'post', 168 ) 169 ); 170 171 158 172 $page_id = $this->factory->post->create( array( 159 173 'post_type' => 'page', 160 174 'post_name' => 'restapi-client-fixture-page', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 172 186 $page_revisions = array_values( wp_get_post_revisions( $page_id ) ); 173 187 $page_revision_id = $page_revisions[ count( $page_revisions ) - 1 ]->ID; 174 188 189 // Create an autosave. 190 wp_create_post_autosave( 191 array( 192 'post_ID' => $page_id, 193 'post_content' => 'Autosave page content.', 194 'post_type' => 'page', 195 ) 196 ); 197 175 198 $tag_id = $this->factory->tag->create( array( 176 199 'name' => 'REST API Client Fixture: Tag', 177 200 'slug' => 'restapi-client-fixture-tag', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 257 280 'route' => '/wp/v2/posts/' . $post_id . '/revisions/' . $post_revision_id, 258 281 'name' => 'revision', 259 282 ), 283 array( 284 'route' => '/wp/v2/posts/' . $post_id . '/autosaves', 285 'name' => 'postAutosaves', 286 ), 287 array( 288 'route' => '/wp/v2/posts/' . $post_id . '/autosaves/' . $post_revision_id, 289 'name' => 'autosave', 290 ), 260 291 array( 261 292 'route' => '/wp/v2/pages', 262 293 'name' => 'PagesCollection', … … class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase { 273 304 'route' => '/wp/v2/pages/'. $page_id . '/revisions/' . $page_revision_id, 274 305 'name' => 'pageRevision', 275 306 ), 307 array( 308 'route' => '/wp/v2/pages/' . $page_id . '/autosaves', 309 'name' => 'pageAutosaves', 310 ), 311 array( 312 'route' => '/wp/v2/pages/' . $page_id . '/autosaves/' . $page_revision_id, 313 'name' => 'pageAutosave', 314 ), 276 315 array( 277 316 'route' => '/wp/v2/media', 278 317 '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 5f3875ca04..42cd329df9 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 "page": { 882 "required": false, 883 "default": 1, 884 "description": "Current page of the collection.", 885 "type": "integer" 886 }, 887 "per_page": { 888 "required": false, 889 "description": "Maximum number of items to be returned in result set.", 890 "type": "integer" 891 }, 892 "search": { 893 "required": false, 894 "description": "Limit results to those matching a string.", 895 "type": "string" 896 }, 897 "exclude": { 898 "required": false, 899 "default": [], 900 "description": "Ensure result set excludes specific IDs.", 901 "type": "array", 902 "items": { 903 "type": "integer" 904 } 905 }, 906 "include": { 907 "required": false, 908 "default": [], 909 "description": "Limit result set to specific IDs.", 910 "type": "array", 911 "items": { 912 "type": "integer" 913 } 914 }, 915 "offset": { 916 "required": false, 917 "description": "Offset the result set by a specific number of items.", 918 "type": "integer" 919 }, 920 "order": { 921 "required": false, 922 "default": "desc", 923 "enum": [ 924 "asc", 925 "desc" 926 ], 927 "description": "Order sort attribute ascending or descending.", 928 "type": "string" 929 }, 930 "orderby": { 931 "required": false, 932 "default": "date", 933 "enum": [ 934 "date", 935 "id", 936 "include", 937 "relevance", 938 "slug", 939 "include_slugs", 940 "title" 941 ], 942 "description": "Sort collection by object attribute.", 943 "type": "string" 944 } 945 } 946 }, 947 { 948 "methods": [ 949 "POST" 950 ], 951 "args": { 952 "parent": { 953 "required": false, 954 "description": "The ID for the parent of the object.", 955 "type": "integer" 956 }, 957 "author": { 958 "required": false, 959 "description": "The ID for the author of the object.", 960 "type": "integer" 961 }, 962 "date": { 963 "required": false, 964 "description": "The date the object was published, in the site's timezone.", 965 "type": "string" 966 }, 967 "date_gmt": { 968 "required": false, 969 "description": "The date the object was published, as GMT.", 970 "type": "string" 971 }, 972 "id": { 973 "required": false, 974 "description": "Unique identifier for the object.", 975 "type": "integer" 976 }, 977 "modified": { 978 "required": false, 979 "description": "The date the object was last modified, in the site's timezone.", 980 "type": "string" 981 }, 982 "modified_gmt": { 983 "required": false, 984 "description": "The date the object was last modified, as GMT.", 985 "type": "string" 986 }, 987 "slug": { 988 "required": false, 989 "description": "An alphanumeric identifier for the object unique to its type.", 990 "type": "string" 991 }, 992 "title": { 993 "required": false, 994 "description": "The title for the object.", 995 "type": "object" 996 }, 997 "content": { 998 "required": false, 999 "description": "The content for the object.", 1000 "type": "object" 1001 }, 1002 "excerpt": { 1003 "required": false, 1004 "description": "The excerpt for the object.", 1005 "type": "object" 1006 } 1007 } 1008 } 1009 ] 1010 }, 1011 "/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 1012 "namespace": "wp/v2", 1013 "methods": [ 1014 "GET" 1015 ], 1016 "endpoints": [ 1017 { 1018 "methods": [ 1019 "GET" 1020 ], 1021 "args": { 1022 "parent": { 1023 "required": false, 1024 "description": "The ID for the parent of the object.", 1025 "type": "integer" 1026 }, 1027 "id": { 1028 "required": false, 1029 "description": "The ID for the object.", 1030 "type": "integer" 1031 }, 1032 "context": { 1033 "required": false, 1034 "default": "view", 1035 "enum": [ 1036 "view", 1037 "embed", 1038 "edit" 1039 ], 1040 "description": "Scope under which the request is made; determines fields present in response.", 1041 "type": "string" 1042 } 1043 } 1044 } 1045 ] 1046 }, 853 1047 "/wp/v2/pages": { 854 1048 "namespace": "wp/v2", 855 1049 "methods": [ … … mockedApiResponse.Schema = { 1456 1650 } 1457 1651 ] 1458 1652 }, 1653 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves": { 1654 "namespace": "wp/v2", 1655 "methods": [ 1656 "GET", 1657 "POST" 1658 ], 1659 "endpoints": [ 1660 { 1661 "methods": [ 1662 "GET" 1663 ], 1664 "args": { 1665 "parent": { 1666 "required": false, 1667 "description": "The ID for the parent of the object.", 1668 "type": "integer" 1669 }, 1670 "context": { 1671 "required": false, 1672 "default": "view", 1673 "enum": [ 1674 "view", 1675 "embed", 1676 "edit" 1677 ], 1678 "description": "Scope under which the request is made; determines fields present in response.", 1679 "type": "string" 1680 }, 1681 "page": { 1682 "required": false, 1683 "default": 1, 1684 "description": "Current page of the collection.", 1685 "type": "integer" 1686 }, 1687 "per_page": { 1688 "required": false, 1689 "description": "Maximum number of items to be returned in result set.", 1690 "type": "integer" 1691 }, 1692 "search": { 1693 "required": false, 1694 "description": "Limit results to those matching a string.", 1695 "type": "string" 1696 }, 1697 "exclude": { 1698 "required": false, 1699 "default": [], 1700 "description": "Ensure result set excludes specific IDs.", 1701 "type": "array", 1702 "items": { 1703 "type": "integer" 1704 } 1705 }, 1706 "include": { 1707 "required": false, 1708 "default": [], 1709 "description": "Limit result set to specific IDs.", 1710 "type": "array", 1711 "items": { 1712 "type": "integer" 1713 } 1714 }, 1715 "offset": { 1716 "required": false, 1717 "description": "Offset the result set by a specific number of items.", 1718 "type": "integer" 1719 }, 1720 "order": { 1721 "required": false, 1722 "default": "desc", 1723 "enum": [ 1724 "asc", 1725 "desc" 1726 ], 1727 "description": "Order sort attribute ascending or descending.", 1728 "type": "string" 1729 }, 1730 "orderby": { 1731 "required": false, 1732 "default": "date", 1733 "enum": [ 1734 "date", 1735 "id", 1736 "include", 1737 "relevance", 1738 "slug", 1739 "include_slugs", 1740 "title" 1741 ], 1742 "description": "Sort collection by object attribute.", 1743 "type": "string" 1744 } 1745 } 1746 }, 1747 { 1748 "methods": [ 1749 "POST" 1750 ], 1751 "args": { 1752 "parent": { 1753 "required": false, 1754 "description": "The ID for the parent of the object.", 1755 "type": "integer" 1756 }, 1757 "author": { 1758 "required": false, 1759 "description": "The ID for the author of the object.", 1760 "type": "integer" 1761 }, 1762 "date": { 1763 "required": false, 1764 "description": "The date the object was published, in the site's timezone.", 1765 "type": "string" 1766 }, 1767 "date_gmt": { 1768 "required": false, 1769 "description": "The date the object was published, as GMT.", 1770 "type": "string" 1771 }, 1772 "id": { 1773 "required": false, 1774 "description": "Unique identifier for the object.", 1775 "type": "integer" 1776 }, 1777 "modified": { 1778 "required": false, 1779 "description": "The date the object was last modified, in the site's timezone.", 1780 "type": "string" 1781 }, 1782 "modified_gmt": { 1783 "required": false, 1784 "description": "The date the object was last modified, as GMT.", 1785 "type": "string" 1786 }, 1787 "slug": { 1788 "required": false, 1789 "description": "An alphanumeric identifier for the object unique to its type.", 1790 "type": "string" 1791 }, 1792 "title": { 1793 "required": false, 1794 "description": "The title for the object.", 1795 "type": "object" 1796 }, 1797 "content": { 1798 "required": false, 1799 "description": "The content for the object.", 1800 "type": "object" 1801 }, 1802 "excerpt": { 1803 "required": false, 1804 "description": "The excerpt for the object.", 1805 "type": "object" 1806 } 1807 } 1808 } 1809 ] 1810 }, 1811 "/wp/v2/pages/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)": { 1812 "namespace": "wp/v2", 1813 "methods": [ 1814 "GET" 1815 ], 1816 "endpoints": [ 1817 { 1818 "methods": [ 1819 "GET" 1820 ], 1821 "args": { 1822 "parent": { 1823 "required": false, 1824 "description": "The ID for the parent of the object.", 1825 "type": "integer" 1826 }, 1827 "id": { 1828 "required": false, 1829 "description": "The ID for the object.", 1830 "type": "integer" 1831 }, 1832 "context": { 1833 "required": false, 1834 "default": "view", 1835 "enum": [ 1836 "view", 1837 "embed", 1838 "edit" 1839 ], 1840 "description": "Scope under which the request is made; determines fields present in response.", 1841 "type": "string" 1842 } 1843 } 1844 } 1845 ] 1846 }, 1459 1847 "/wp/v2/media": { 1460 1848 "namespace": "wp/v2", 1461 1849 "methods": [ … … mockedApiResponse.PostsCollection = [ 3842 4230 ], 3843 4231 "version-history": [ 3844 4232 { 3845 "count": 1,4233 "count": 2, 3846 4234 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/4/revisions" 3847 4235 } 3848 4236 ], … … mockedApiResponse.postRevisions = [ 3933 4321 "guid": { 3934 4322 "rendered": "http://example.org/?p=5" 3935 4323 }, 4324 "title": { 4325 "rendered": "" 4326 }, 4327 "content": { 4328 "rendered": "<p>Autosave post content.</p>\n" 4329 }, 4330 "excerpt": { 4331 "rendered": "" 4332 }, 4333 "_links": { 4334 "parent": [ 4335 { 4336 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/4" 4337 } 4338 ] 4339 } 4340 }, 4341 { 4342 "author": 389, 4343 "date": "2017-02-14T00:00:00", 4344 "date_gmt": "2017-02-14T00:00:00", 4345 "id": 36707, 4346 "modified": "2017-02-14T00:00:00", 4347 "modified_gmt": "2017-02-14T00:00:00", 4348 "parent": 36706, 4349 "slug": "36706-revision-v1", 4350 "guid": { 4351 "rendered": "http://example.org/?p=36707" 4352 }, 3936 4353 "title": { 3937 4354 "rendered": "REST API Client Fixture: Post" 3938 4355 }, … … mockedApiResponse.postRevisions = [ 3945 4362 "_links": { 3946 4363 "parent": [ 3947 4364 { 3948 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/ 4"4365 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36706" 3949 4366 } 3950 4367 ] 3951 4368 } … … mockedApiResponse.revision = { 3975 4392 } 3976 4393 }; 3977 4394 4395 mockedApiResponse.postAutosaves = [ 4396 { 4397 "author": 389, 4398 "date": "2017-02-14T00:00:00", 4399 "date_gmt": "2017-02-14T00:00:00", 4400 "id": 36708, 4401 "modified": "2017-02-14T00:00:00", 4402 "modified_gmt": "2017-02-14T00:00:00", 4403 "parent": 36706, 4404 "slug": "36706-autosave-v1", 4405 "guid": { 4406 "rendered": "http://example.org/?p=36708" 4407 }, 4408 "title": { 4409 "rendered": "" 4410 }, 4411 "content": { 4412 "rendered": "<p>Autosave post content.</p>\n" 4413 }, 4414 "excerpt": { 4415 "rendered": "" 4416 }, 4417 "_links": { 4418 "parent": [ 4419 { 4420 "href": "http://example.org/index.php?rest_route=/wp/v2/posts/36706" 4421 } 4422 ] 4423 } 4424 } 4425 ]; 4426 4427 mockedApiResponse.autosave = { 4428 "author": 389, 4429 "date": "2017-02-14T00:00:00", 4430 "date_gmt": "2017-02-14T00:00:00", 4431 "id": 36708, 4432 "modified": "2017-02-14T00:00:00", 4433 "modified_gmt": "2017-02-14T00:00:00", 4434 "parent": 36706, 4435 "slug": "36706-autosave-v1", 4436 "guid": { 4437 "rendered": "http://example.org/?p=36708" 4438 }, 4439 "title": { 4440 "rendered": "" 4441 }, 4442 "content": { 4443 "rendered": "<p>Autosave post content.</p>\n" 4444 }, 4445 "excerpt": { 4446 "rendered": "" 4447 } 4448 }; 4449 3978 4450 mockedApiResponse.PagesCollection = [ 3979 4451 { 3980 4452 "id": 6, … … mockedApiResponse.PagesCollection = [ 4034 4506 ], 4035 4507 "version-history": [ 4036 4508 { 4037 "count": 1,4509 "count": 2, 4038 4510 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6/revisions" 4039 4511 } 4040 4512 ], … … mockedApiResponse.pageRevisions = [ 4109 4581 "guid": { 4110 4582 "rendered": "http://example.org/?p=7" 4111 4583 }, 4584 "title": { 4585 "rendered": "" 4586 }, 4587 "content": { 4588 "rendered": "<p>Autosave page content.</p>\n" 4589 }, 4590 "excerpt": { 4591 "rendered": "" 4592 }, 4593 "_links": { 4594 "parent": [ 4595 { 4596 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/6" 4597 } 4598 ] 4599 } 4600 }, 4601 { 4602 "author": 389, 4603 "date": "2017-02-14T00:00:00", 4604 "date_gmt": "2017-02-14T00:00:00", 4605 "id": 36710, 4606 "modified": "2017-02-14T00:00:00", 4607 "modified_gmt": "2017-02-14T00:00:00", 4608 "parent": 36709, 4609 "slug": "36709-revision-v1", 4610 "guid": { 4611 "rendered": "http://example.org/?p=36710" 4612 }, 4112 4613 "title": { 4113 4614 "rendered": "REST API Client Fixture: Page" 4114 4615 }, … … mockedApiResponse.pageRevisions = [ 4121 4622 "_links": { 4122 4623 "parent": [ 4123 4624 { 4124 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/ 6"4625 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36709" 4125 4626 } 4126 4627 ] 4127 4628 } … … mockedApiResponse.pageRevision = { 4151 4652 } 4152 4653 }; 4153 4654 4655 mockedApiResponse.pageAutosaves = [ 4656 { 4657 "author": 389, 4658 "date": "2017-02-14T00:00:00", 4659 "date_gmt": "2017-02-14T00:00:00", 4660 "id": 36711, 4661 "modified": "2017-02-14T00:00:00", 4662 "modified_gmt": "2017-02-14T00:00:00", 4663 "parent": 36709, 4664 "slug": "36709-autosave-v1", 4665 "guid": { 4666 "rendered": "http://example.org/?p=36711" 4667 }, 4668 "title": { 4669 "rendered": "" 4670 }, 4671 "content": { 4672 "rendered": "<p>Autosave page content.</p>\n" 4673 }, 4674 "excerpt": { 4675 "rendered": "" 4676 }, 4677 "_links": { 4678 "parent": [ 4679 { 4680 "href": "http://example.org/index.php?rest_route=/wp/v2/pages/36709" 4681 } 4682 ] 4683 } 4684 } 4685 ]; 4686 4687 mockedApiResponse.pageAutosave = { 4688 "author": 389, 4689 "date": "2017-02-14T00:00:00", 4690 "date_gmt": "2017-02-14T00:00:00", 4691 "id": 36711, 4692 "modified": "2017-02-14T00:00:00", 4693 "modified_gmt": "2017-02-14T00:00:00", 4694 "parent": 36709, 4695 "slug": "36709-autosave-v1", 4696 "guid": { 4697 "rendered": "http://example.org/?p=36711" 4698 }, 4699 "title": { 4700 "rendered": "" 4701 }, 4702 "content": { 4703 "rendered": "<p>Autosave page content.</p>\n" 4704 }, 4705 "excerpt": { 4706 "rendered": "" 4707 } 4708 }; 4709 4154 4710 mockedApiResponse.MediaCollection = [ 4155 4711 { 4156 4712 "id": 8,