| | 276 | /** |
| | 277 | * Checks if a given request has access to create an autosave revision. |
| | 278 | * |
| | 279 | * Autosave revisions inherit permissions from the parent post, |
| | 280 | * check if the current user has permission to edit the post. |
| | 281 | * |
| | 282 | * @since 5.0.0 |
| | 283 | * |
| | 284 | * @param WP_REST_Request $request Full details about the request. |
| | 285 | * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. |
| | 286 | */ |
| | 287 | public function create_item_permissions_check( $request ) { |
| | 288 | if ( empty( $request->get_param( 'parent' ) ) ) { |
| | 289 | return new WP_Error( 'rest_post_invalid_id', __( 'Invalid item ID.' ), array( 'status' => 404 ) ); |
| | 290 | } |
| | 291 | |
| | 292 | // Set request ID for the permission check. |
| | 293 | $dummy_request = clone $request; |
| | 294 | $dummy_request['id'] = $request['parent']; |
| | 295 | |
| | 296 | return $this->parent_controller->update_item_permissions_check( $dummy_request ); |
| | 297 | } |
| | 298 | |
| | 299 | /** |
| | 300 | * Creates, updates or deletes an autosave revision. |
| | 301 | * |
| | 302 | * @since 5.0.0 |
| | 303 | * |
| | 304 | * @param WP_REST_Request $request Full details about the request. |
| | 305 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
| | 306 | */ |
| | 307 | public function create_item( $request ) { |
| | 308 | if ( ! defined( 'DOING_AUTOSAVE' ) ) { |
| | 309 | define( 'DOING_AUTOSAVE', true ); |
| | 310 | } |
| | 311 | |
| | 312 | $post = get_post( $request->get_param( 'parent' ) ); |
| | 313 | |
| | 314 | if ( is_wp_error( $post ) ) { |
| | 315 | return $post; |
| | 316 | } |
| | 317 | |
| | 318 | $user_id = get_current_user_id(); |
| | 319 | $old_autosave = wp_get_post_autosave( $post->ID, $user_id ); |
| | 320 | if ( $old_autosave ) { |
| | 321 | return new WP_Error( |
| | 322 | 'rest_revision_existing_autosave', |
| | 323 | __( 'An autosave already exists for this user.' ), |
| | 324 | array( |
| | 325 | 'status' => WP_Http::CONFLICT, |
| | 326 | 'id' => $old_autosave->ID, |
| | 327 | ) |
| | 328 | ); |
| | 329 | } |
| | 330 | |
| | 331 | $prepared_post = $this->prepare_item_for_database( $request ); |
| | 332 | $prepared_post->ID = $post->ID; |
| | 333 | |
| | 334 | if ( 'draft' === $post->post_status || 'auto-draft' === $post->post_status ) { |
| | 335 | return new WP_Error( |
| | 336 | 'rest_cannot_create_for_draft', |
| | 337 | __( 'Draft posts may not have autosaves.' ), |
| | 338 | array( |
| | 339 | 'status' => WP_Http::BAD_REQUEST, |
| | 340 | ) |
| | 341 | ); |
| | 342 | } |
| | 343 | |
| | 344 | // Non-draft posts: create or update the post autosave. |
| | 345 | $autosave_id = _wp_put_post_revision( (array) $prepared_post, true ); |
| | 346 | if ( is_wp_error( $autosave_id ) ) { |
| | 347 | return $autosave_id; |
| | 348 | } |
| | 349 | |
| | 350 | $autosave = get_post( $autosave_id ); |
| | 351 | $fields_update = $this->update_additional_fields_for_object( $autosave, $request ); |
| | 352 | |
| | 353 | if ( is_wp_error( $fields_update ) ) { |
| | 354 | return $fields_update; |
| | 355 | } |
| | 356 | |
| | 357 | $request->set_param( 'context', 'edit' ); |
| | 358 | |
| | 359 | $response = $this->prepare_item_for_response( $autosave, $request ); |
| | 360 | $response = rest_ensure_response( $response ); |
| | 361 | |
| | 362 | return $response; |
| | 363 | } |
| | 364 | |
| | 365 | /** |
| | 366 | * Checks if a given request has access to create an autosave revision. |
| | 367 | * |
| | 368 | * Autosave revisions inherit permissions from the parent post, |
| | 369 | * check if the current user has permission to edit the post. |
| | 370 | * |
| | 371 | * @since 5.0.0 |
| | 372 | * |
| | 373 | * @param WP_REST_Request $request Full details about the request. |
| | 374 | * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. |
| | 375 | */ |
| | 376 | public function update_item_permissions_check( $request ) { |
| | 377 | if ( empty( $request->get_param( 'parent' ) ) ) { |
| | 378 | return new WP_Error( 'rest_post_invalid_id', __( 'Invalid item ID.' ), array( 'status' => 404 ) ); |
| | 379 | } |
| | 380 | |
| | 381 | $autosave = $this->get_revision( $request['id'] ); |
| | 382 | if ( is_wp_error( $revision ) ) { |
| | 383 | return $revision; |
| | 384 | } |
| | 385 | |
| | 386 | if ( ! wp_is_post_autosave( $autosave ) ) { |
| | 387 | return new WP_Error( |
| | 388 | 'rest_revision_cannot_update', |
| | 389 | __( 'Only autosave revisions may be updated.' ), |
| | 390 | array( 'status' => WP_Http::BAD_REQUEST ) |
| | 391 | ); |
| | 392 | } |
| | 393 | |
| | 394 | // Set request ID for the permission check. |
| | 395 | $dummy_request = clone $request; |
| | 396 | $dummy_request['id'] = $request['parent']; |
| | 397 | |
| | 398 | return $this->parent_controller->update_item_permissions_check( $dummy_request ); |
| | 399 | } |
| | 400 | |
| | 401 | /** |
| | 402 | * Updates a single revision. |
| | 403 | * |
| | 404 | * Only allows updating autosave revisions. |
| | 405 | * |
| | 406 | * @since 4.7.0 |
| | 407 | * |
| | 408 | * @param WP_REST_Request $request Full details about the request. |
| | 409 | * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
| | 410 | */ |
| | 411 | public function update_item( $request ) { |
| | 412 | $valid_check = $this->get_parent( $request['parent'] ); |
| | 413 | if ( is_wp_error( $valid_check ) ) { |
| | 414 | return $valid_check; |
| | 415 | } |
| | 416 | |
| | 417 | $post = $this->prepare_item_for_database( $request ); |
| | 418 | |
| | 419 | if ( is_wp_error( $post ) ) { |
| | 420 | return $post; |
| | 421 | } |
| | 422 | |
| | 423 | // convert the post object to an array, otherwise wp_update_post will expect non-escaped input. |
| | 424 | $post_id = wp_update_post( wp_slash( (array) $post ), true ); |
| | 425 | |
| | 426 | if ( is_wp_error( $post_id ) ) { |
| | 427 | if ( 'db_update_error' === $post_id->get_error_code() ) { |
| | 428 | $post_id->add_data( array( 'status' => 500 ) ); |
| | 429 | } else { |
| | 430 | $post_id->add_data( array( 'status' => 400 ) ); |
| | 431 | } |
| | 432 | return $post_id; |
| | 433 | } |
| | 434 | |
| | 435 | $post = get_post( $post_id ); |
| | 436 | |
| | 437 | /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ |
| | 438 | do_action( "rest_insert_{$this->post_type}", $post, $request, false ); |
| | 439 | |
| | 440 | $schema = $this->get_item_schema(); |
| | 441 | |
| | 442 | $post = get_post( $post_id ); |
| | 443 | $fields_update = $this->update_additional_fields_for_object( $post, $request ); |
| | 444 | |
| | 445 | if ( is_wp_error( $fields_update ) ) { |
| | 446 | return $fields_update; |
| | 447 | } |
| | 448 | |
| | 449 | $request->set_param( 'context', 'edit' ); |
| | 450 | |
| | 451 | $response = $this->prepare_item_for_response( $post, $request ); |
| | 452 | |
| | 453 | return rest_ensure_response( $response ); |
| | 454 | } |
| | 455 | |
| | 536 | /** |
| | 537 | * Prepares a single post for create or update. |
| | 538 | * |
| | 539 | * @since 4.7.0 |
| | 540 | * |
| | 541 | * @param WP_REST_Request $request Request object. |
| | 542 | * @return stdClass|WP_Error Post object or WP_Error. |
| | 543 | */ |
| | 544 | protected function prepare_item_for_database( $request ) { |
| | 545 | $prepared_post = new stdClass; |
| | 546 | |
| | 547 | // Post ID. |
| | 548 | if ( isset( $request['id'] ) ) { |
| | 549 | $existing_post = $this->get_revision( $request['id'] ); |
| | 550 | if ( is_wp_error( $existing_post ) ) { |
| | 551 | return $existing_post; |
| | 552 | } |
| | 553 | |
| | 554 | $prepared_post->ID = $existing_post->ID; |
| | 555 | } |
| | 556 | |
| | 557 | $schema = $this->get_item_schema(); |
| | 558 | |
| | 559 | // Post title. |
| | 560 | if ( ! empty( $schema['properties']['title'] ) && isset( $request['title'] ) ) { |
| | 561 | if ( is_string( $request['title'] ) ) { |
| | 562 | $prepared_post->post_title = $request['title']; |
| | 563 | } elseif ( ! empty( $request['title']['raw'] ) ) { |
| | 564 | $prepared_post->post_title = $request['title']['raw']; |
| | 565 | } |
| | 566 | } |
| | 567 | |
| | 568 | // Post content. |
| | 569 | if ( ! empty( $schema['properties']['content'] ) && isset( $request['content'] ) ) { |
| | 570 | if ( is_string( $request['content'] ) ) { |
| | 571 | $prepared_post->post_content = $request['content']; |
| | 572 | } elseif ( isset( $request['content']['raw'] ) ) { |
| | 573 | $prepared_post->post_content = $request['content']['raw']; |
| | 574 | } |
| | 575 | } |
| | 576 | |
| | 577 | // Post excerpt. |
| | 578 | if ( ! empty( $schema['properties']['excerpt'] ) && isset( $request['excerpt'] ) ) { |
| | 579 | if ( is_string( $request['excerpt'] ) ) { |
| | 580 | $prepared_post->post_excerpt = $request['excerpt']; |
| | 581 | } elseif ( isset( $request['excerpt']['raw'] ) ) { |
| | 582 | $prepared_post->post_excerpt = $request['excerpt']['raw']; |
| | 583 | } |
| | 584 | } |
| | 585 | |
| | 586 | /** |
| | 587 | * Filters a post before it is inserted via the REST API. |
| | 588 | * |
| | 589 | * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
| | 590 | * |
| | 591 | * @since 4.7.0 |
| | 592 | * |
| | 593 | * @param stdClass $prepared_post An object representing a single post prepared |
| | 594 | * for inserting or updating the database. |
| | 595 | * @param WP_REST_Request $request Request object. |
| | 596 | */ |
| | 597 | return apply_filters( "rest_pre_insert_{$this->post_type}", $prepared_post, $request ); |
| | 598 | |
| | 599 | } |
| | 600 | |