47 * |
47 * |
48 * @param string $parent_post_type Post type of the parent. |
48 * @param string $parent_post_type Post type of the parent. |
49 */ |
49 */ |
50 public function __construct( $parent_post_type ) { |
50 public function __construct( $parent_post_type ) { |
51 $this->parent_post_type = $parent_post_type; |
51 $this->parent_post_type = $parent_post_type; |
52 $this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); |
|
53 $this->namespace = 'wp/v2'; |
52 $this->namespace = 'wp/v2'; |
54 $this->rest_base = 'revisions'; |
53 $this->rest_base = 'revisions'; |
55 $post_type_object = get_post_type_object( $parent_post_type ); |
54 $post_type_object = get_post_type_object( $parent_post_type ); |
56 $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; |
55 $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; |
57 } |
56 $this->parent_controller = $post_type_object->get_rest_controller(); |
58 |
57 |
59 /** |
58 if ( ! $this->parent_controller ) { |
60 * Registers routes for revisions based on post types supporting revisions. |
59 $this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); |
|
60 } |
|
61 } |
|
62 |
|
63 /** |
|
64 * Registers the routes for revisions based on post types supporting revisions. |
61 * |
65 * |
62 * @since 4.7.0 |
66 * @since 4.7.0 |
63 * |
67 * |
64 * @see register_rest_route() |
68 * @see register_rest_route() |
65 */ |
69 */ |
128 /** |
132 /** |
129 * Get the parent post, if the ID is valid. |
133 * Get the parent post, if the ID is valid. |
130 * |
134 * |
131 * @since 4.7.2 |
135 * @since 4.7.2 |
132 * |
136 * |
133 * @param int $id Supplied ID. |
137 * @param int $parent Supplied ID. |
134 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. |
138 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. |
135 */ |
139 */ |
136 protected function get_parent( $parent ) { |
140 protected function get_parent( $parent ) { |
137 $error = new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent ID.' ), array( 'status' => 404 ) ); |
141 $error = new WP_Error( |
|
142 'rest_post_invalid_parent', |
|
143 __( 'Invalid post parent ID.' ), |
|
144 array( 'status' => 404 ) |
|
145 ); |
138 if ( (int) $parent <= 0 ) { |
146 if ( (int) $parent <= 0 ) { |
139 return $error; |
147 return $error; |
140 } |
148 } |
141 |
149 |
142 $parent = get_post( (int) $parent ); |
150 $parent = get_post( (int) $parent ); |
150 /** |
158 /** |
151 * Checks if a given request has access to get revisions. |
159 * Checks if a given request has access to get revisions. |
152 * |
160 * |
153 * @since 4.7.0 |
161 * @since 4.7.0 |
154 * |
162 * |
155 * @param WP_REST_Request $request Full data about the request. |
163 * @param WP_REST_Request $request Full details about the request. |
156 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
164 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
157 */ |
165 */ |
158 public function get_items_permissions_check( $request ) { |
166 public function get_items_permissions_check( $request ) { |
159 $parent = $this->get_parent( $request['parent'] ); |
167 $parent = $this->get_parent( $request['parent'] ); |
160 if ( is_wp_error( $parent ) ) { |
168 if ( is_wp_error( $parent ) ) { |
161 return $parent; |
169 return $parent; |
162 } |
170 } |
163 |
171 |
164 $parent_post_type_obj = get_post_type_object( $parent->post_type ); |
172 if ( ! current_user_can( 'edit_post', $parent->ID ) ) { |
165 if ( ! current_user_can( $parent_post_type_obj->cap->edit_post, $parent->ID ) ) { |
173 return new WP_Error( |
166 return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to view revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) ); |
174 'rest_cannot_read', |
|
175 __( 'Sorry, you are not allowed to view revisions of this post.' ), |
|
176 array( 'status' => rest_authorization_required_code() ) |
|
177 ); |
167 } |
178 } |
168 |
179 |
169 return true; |
180 return true; |
170 } |
181 } |
171 |
182 |
176 * |
187 * |
177 * @param int $id Supplied ID. |
188 * @param int $id Supplied ID. |
178 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. |
189 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. |
179 */ |
190 */ |
180 protected function get_revision( $id ) { |
191 protected function get_revision( $id ) { |
181 $error = new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision ID.' ), array( 'status' => 404 ) ); |
192 $error = new WP_Error( |
|
193 'rest_post_invalid_id', |
|
194 __( 'Invalid revision ID.' ), |
|
195 array( 'status' => 404 ) |
|
196 ); |
|
197 |
182 if ( (int) $id <= 0 ) { |
198 if ( (int) $id <= 0 ) { |
183 return $error; |
199 return $error; |
184 } |
200 } |
185 |
201 |
186 $revision = get_post( (int) $id ); |
202 $revision = get_post( (int) $id ); |
194 /** |
210 /** |
195 * Gets a collection of revisions. |
211 * Gets a collection of revisions. |
196 * |
212 * |
197 * @since 4.7.0 |
213 * @since 4.7.0 |
198 * |
214 * |
199 * @param WP_REST_Request $request Full data about the request. |
215 * @param WP_REST_Request $request Full details about the request. |
200 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
216 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
201 */ |
217 */ |
202 public function get_items( $request ) { |
218 public function get_items( $request ) { |
203 $parent = $this->get_parent( $request['parent'] ); |
219 $parent = $this->get_parent( $request['parent'] ); |
204 if ( is_wp_error( $parent ) ) { |
220 if ( is_wp_error( $parent ) ) { |
205 return $parent; |
221 return $parent; |
206 } |
222 } |
207 |
223 |
208 // Ensure a search string is set in case the orderby is set to 'relevance'. |
224 // Ensure a search string is set in case the orderby is set to 'relevance'. |
209 if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) { |
225 if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) { |
210 return new WP_Error( 'rest_no_search_term_defined', __( 'You need to define a search term to order by relevance.' ), array( 'status' => 400 ) ); |
226 return new WP_Error( |
|
227 'rest_no_search_term_defined', |
|
228 __( 'You need to define a search term to order by relevance.' ), |
|
229 array( 'status' => 400 ) |
|
230 ); |
211 } |
231 } |
212 |
232 |
213 // Ensure an include parameter is set in case the orderby is set to 'include'. |
233 // Ensure an include parameter is set in case the orderby is set to 'include'. |
214 if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) { |
234 if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) { |
215 return new WP_Error( 'rest_orderby_include_missing_include', __( 'You need to define an include parameter to order by include.' ), array( 'status' => 400 ) ); |
235 return new WP_Error( |
|
236 'rest_orderby_include_missing_include', |
|
237 __( 'You need to define an include parameter to order by include.' ), |
|
238 array( 'status' => 400 ) |
|
239 ); |
216 } |
240 } |
217 |
241 |
218 if ( wp_revisions_enabled( $parent ) ) { |
242 if ( wp_revisions_enabled( $parent ) ) { |
219 $registered = $this->get_collection_params(); |
243 $registered = $this->get_collection_params(); |
220 $args = array( |
244 $args = array( |
275 $max_pages = $total_revisions > 0 ? 1 : 0; |
299 $max_pages = $total_revisions > 0 ? 1 : 0; |
276 } |
300 } |
277 |
301 |
278 if ( $total_revisions > 0 ) { |
302 if ( $total_revisions > 0 ) { |
279 if ( $offset >= $total_revisions ) { |
303 if ( $offset >= $total_revisions ) { |
280 return new WP_Error( 'rest_revision_invalid_offset_number', __( 'The offset number requested is larger than or equal to the number of available revisions.' ), array( 'status' => 400 ) ); |
304 return new WP_Error( |
|
305 'rest_revision_invalid_offset_number', |
|
306 __( 'The offset number requested is larger than or equal to the number of available revisions.' ), |
|
307 array( 'status' => 400 ) |
|
308 ); |
281 } elseif ( ! $offset && $page > $max_pages ) { |
309 } elseif ( ! $offset && $page > $max_pages ) { |
282 return new WP_Error( 'rest_revision_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); |
310 return new WP_Error( |
|
311 'rest_revision_invalid_page_number', |
|
312 __( 'The page number requested is larger than the number of pages available.' ), |
|
313 array( 'status' => 400 ) |
|
314 ); |
283 } |
315 } |
284 } |
316 } |
285 } else { |
317 } else { |
286 $revisions = array(); |
318 $revisions = array(); |
287 $total_revisions = 0; |
319 $total_revisions = 0; |
288 $max_pages = 0; |
320 $max_pages = 0; |
289 $page = (int) $request['page']; |
321 $page = (int) $request['page']; |
290 } |
322 } |
291 |
323 |
292 $response = array(); |
324 $response = array(); |
|
325 |
293 foreach ( $revisions as $revision ) { |
326 foreach ( $revisions as $revision ) { |
294 $data = $this->prepare_item_for_response( $revision, $request ); |
327 $data = $this->prepare_item_for_response( $revision, $request ); |
295 $response[] = $this->prepare_response_for_collection( $data ); |
328 $response[] = $this->prepare_response_for_collection( $data ); |
296 } |
329 } |
297 |
330 |
326 /** |
359 /** |
327 * Checks if a given request has access to get a specific revision. |
360 * Checks if a given request has access to get a specific revision. |
328 * |
361 * |
329 * @since 4.7.0 |
362 * @since 4.7.0 |
330 * |
363 * |
331 * @param WP_REST_Request $request Full data about the request. |
364 * @param WP_REST_Request $request Full details about the request. |
332 * @return bool|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
365 * @return bool|WP_Error True if the request has read access for the item, WP_Error object otherwise. |
333 */ |
366 */ |
334 public function get_item_permissions_check( $request ) { |
367 public function get_item_permissions_check( $request ) { |
335 return $this->get_items_permissions_check( $request ); |
368 return $this->get_items_permissions_check( $request ); |
336 } |
369 } |
338 /** |
371 /** |
339 * Retrieves one revision from the collection. |
372 * Retrieves one revision from the collection. |
340 * |
373 * |
341 * @since 4.7.0 |
374 * @since 4.7.0 |
342 * |
375 * |
343 * @param WP_REST_Request $request Full data about the request. |
376 * @param WP_REST_Request $request Full details about the request. |
344 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
377 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
345 */ |
378 */ |
346 public function get_item( $request ) { |
379 public function get_item( $request ) { |
347 $parent = $this->get_parent( $request['parent'] ); |
380 $parent = $this->get_parent( $request['parent'] ); |
348 if ( is_wp_error( $parent ) ) { |
381 if ( is_wp_error( $parent ) ) { |
361 /** |
394 /** |
362 * Checks if a given request has access to delete a revision. |
395 * Checks if a given request has access to delete a revision. |
363 * |
396 * |
364 * @since 4.7.0 |
397 * @since 4.7.0 |
365 * |
398 * |
366 * @param WP_REST_Request $request Full details about the request. |
399 * @param WP_REST_Request $request Full details about the request. |
367 * @return bool|WP_Error True if the request has access to delete the item, WP_Error object otherwise. |
400 * @return bool|WP_Error True if the request has access to delete the item, WP_Error object otherwise. |
368 */ |
401 */ |
369 public function delete_item_permissions_check( $request ) { |
402 public function delete_item_permissions_check( $request ) { |
370 $parent = $this->get_parent( $request['parent'] ); |
403 $parent = $this->get_parent( $request['parent'] ); |
371 if ( is_wp_error( $parent ) ) { |
404 if ( is_wp_error( $parent ) ) { |
372 return $parent; |
405 return $parent; |
373 } |
406 } |
374 |
407 |
|
408 $parent_post_type = get_post_type_object( $parent->post_type ); |
|
409 |
|
410 if ( ! current_user_can( 'delete_post', $parent->ID ) ) { |
|
411 return new WP_Error( |
|
412 'rest_cannot_delete', |
|
413 __( 'Sorry, you are not allowed to delete revisions of this post.' ), |
|
414 array( 'status' => rest_authorization_required_code() ) |
|
415 ); |
|
416 } |
|
417 |
375 $revision = $this->get_revision( $request['id'] ); |
418 $revision = $this->get_revision( $request['id'] ); |
376 if ( is_wp_error( $revision ) ) { |
419 if ( is_wp_error( $revision ) ) { |
377 return $revision; |
420 return $revision; |
378 } |
421 } |
379 |
422 |
380 $response = $this->get_items_permissions_check( $request ); |
423 $response = $this->get_items_permissions_check( $request ); |
381 if ( ! $response || is_wp_error( $response ) ) { |
424 if ( ! $response || is_wp_error( $response ) ) { |
382 return $response; |
425 return $response; |
383 } |
426 } |
384 |
427 |
385 $post_type = get_post_type_object( 'revision' ); |
428 if ( ! current_user_can( 'delete_post', $revision->ID ) ) { |
386 return current_user_can( $post_type->cap->delete_post, $revision->ID ); |
429 return new WP_Error( |
|
430 'rest_cannot_delete', |
|
431 __( 'Sorry, you are not allowed to delete this revision.' ), |
|
432 array( 'status' => rest_authorization_required_code() ) |
|
433 ); |
|
434 } |
|
435 |
|
436 return true; |
387 } |
437 } |
388 |
438 |
389 /** |
439 /** |
390 * Deletes a single revision. |
440 * Deletes a single revision. |
391 * |
441 * |
392 * @since 4.7.0 |
442 * @since 4.7.0 |
393 * |
443 * |
394 * @param WP_REST_Request $request Full details about the request. |
444 * @param WP_REST_Request $request Full details about the request. |
395 * @return true|WP_Error True on success, or WP_Error object on failure. |
445 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
396 */ |
446 */ |
397 public function delete_item( $request ) { |
447 public function delete_item( $request ) { |
398 $revision = $this->get_revision( $request['id'] ); |
448 $revision = $this->get_revision( $request['id'] ); |
399 if ( is_wp_error( $revision ) ) { |
449 if ( is_wp_error( $revision ) ) { |
400 return $revision; |
450 return $revision; |
402 |
452 |
403 $force = isset( $request['force'] ) ? (bool) $request['force'] : false; |
453 $force = isset( $request['force'] ) ? (bool) $request['force'] : false; |
404 |
454 |
405 // We don't support trashing for revisions. |
455 // We don't support trashing for revisions. |
406 if ( ! $force ) { |
456 if ( ! $force ) { |
407 /* translators: %s: force=true */ |
457 return new WP_Error( |
408 return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); |
458 'rest_trash_not_supported', |
|
459 /* translators: %s: force=true */ |
|
460 sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ), |
|
461 array( 'status' => 501 ) |
|
462 ); |
409 } |
463 } |
410 |
464 |
411 $previous = $this->prepare_item_for_response( $revision, $request ); |
465 $previous = $this->prepare_item_for_response( $revision, $request ); |
412 |
466 |
413 $result = wp_delete_post( $request['id'], true ); |
467 $result = wp_delete_post( $request['id'], true ); |
415 /** |
469 /** |
416 * Fires after a revision is deleted via the REST API. |
470 * Fires after a revision is deleted via the REST API. |
417 * |
471 * |
418 * @since 4.7.0 |
472 * @since 4.7.0 |
419 * |
473 * |
420 * @param (mixed) $result The revision object (if it was deleted or moved to the trash successfully) |
474 * @param WP_Post|false|null $result The revision object (if it was deleted or moved to the Trash successfully) |
421 * or false (failure). If the revision was moved to the trash, $result represents |
475 * or false or null (failure). If the revision was moved to the Trash, $result represents |
422 * its new state; if it was deleted, $result represents its state before deletion. |
476 * its new state; if it was deleted, $result represents its state before deletion. |
423 * @param WP_REST_Request $request The request sent to the API. |
477 * @param WP_REST_Request $request The request sent to the API. |
424 */ |
478 */ |
425 do_action( 'rest_delete_revision', $result, $request ); |
479 do_action( 'rest_delete_revision', $result, $request ); |
426 |
480 |
427 if ( ! $result ) { |
481 if ( ! $result ) { |
428 return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) ); |
482 return new WP_Error( |
|
483 'rest_cannot_delete', |
|
484 __( 'The post cannot be deleted.' ), |
|
485 array( 'status' => 500 ) |
|
486 ); |
429 } |
487 } |
430 |
488 |
431 $response = new WP_REST_Response(); |
489 $response = new WP_REST_Response(); |
432 $response->set_data( |
490 $response->set_data( |
433 array( |
491 array( |
604 * @since 4.7.0 |
662 * @since 4.7.0 |
605 * |
663 * |
606 * @return array Item schema data. |
664 * @return array Item schema data. |
607 */ |
665 */ |
608 public function get_item_schema() { |
666 public function get_item_schema() { |
|
667 if ( $this->schema ) { |
|
668 return $this->add_additional_fields_schema( $this->schema ); |
|
669 } |
|
670 |
609 $schema = array( |
671 $schema = array( |
610 '$schema' => 'http://json-schema.org/draft-04/schema#', |
672 '$schema' => 'http://json-schema.org/draft-04/schema#', |
611 'title' => "{$this->parent_post_type}-revision", |
673 'title' => "{$this->parent_post_type}-revision", |
612 'type' => 'object', |
674 'type' => 'object', |
613 // Base properties for every Revision. |
675 // Base properties for every Revision. |