220 $template = get_block_template( $request['id'], $this->post_type ); |
275 $template = get_block_template( $request['id'], $this->post_type ); |
221 if ( ! $template ) { |
276 if ( ! $template ) { |
222 return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); |
277 return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); |
223 } |
278 } |
224 |
279 |
|
280 $post_before = get_post( $template->wp_id ); |
|
281 |
|
282 if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { |
|
283 wp_delete_post( $template->wp_id, true ); |
|
284 $request->set_param( 'context', 'edit' ); |
|
285 |
|
286 $template = get_block_template( $request['id'], $this->post_type ); |
|
287 $response = $this->prepare_item_for_response( $template, $request ); |
|
288 |
|
289 return rest_ensure_response( $response ); |
|
290 } |
|
291 |
225 $changes = $this->prepare_item_for_database( $request ); |
292 $changes = $this->prepare_item_for_database( $request ); |
226 |
293 |
|
294 if ( is_wp_error( $changes ) ) { |
|
295 return $changes; |
|
296 } |
|
297 |
227 if ( 'custom' === $template->source ) { |
298 if ( 'custom' === $template->source ) { |
228 $result = wp_update_post( wp_slash( (array) $changes ), true ); |
299 $update = true; |
|
300 $result = wp_update_post( wp_slash( (array) $changes ), false ); |
229 } else { |
301 } else { |
230 $result = wp_insert_post( wp_slash( (array) $changes ), true ); |
302 $update = false; |
231 } |
303 $post_before = null; |
|
304 $result = wp_insert_post( wp_slash( (array) $changes ), false ); |
|
305 } |
|
306 |
232 if ( is_wp_error( $result ) ) { |
307 if ( is_wp_error( $result ) ) { |
|
308 if ( 'db_update_error' === $result->get_error_code() ) { |
|
309 $result->add_data( array( 'status' => 500 ) ); |
|
310 } else { |
|
311 $result->add_data( array( 'status' => 400 ) ); |
|
312 } |
233 return $result; |
313 return $result; |
234 } |
314 } |
235 |
315 |
236 $template = get_block_template( $request['id'], $this->post_type ); |
316 $template = get_block_template( $request['id'], $this->post_type ); |
237 $fields_update = $this->update_additional_fields_for_object( $template, $request ); |
317 $fields_update = $this->update_additional_fields_for_object( $template, $request ); |
238 if ( is_wp_error( $fields_update ) ) { |
318 if ( is_wp_error( $fields_update ) ) { |
239 return $fields_update; |
319 return $fields_update; |
240 } |
320 } |
241 |
321 |
242 return $this->prepare_item_for_response( |
322 $request->set_param( 'context', 'edit' ); |
243 get_block_template( $request['id'], $this->post_type ), |
323 |
244 $request |
324 $post = get_post( $template->wp_id ); |
245 ); |
325 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ |
|
326 do_action( "rest_after_insert_{$this->post_type}", $post, $request, false ); |
|
327 |
|
328 wp_after_insert_post( $post, $update, $post_before ); |
|
329 |
|
330 $response = $this->prepare_item_for_response( $template, $request ); |
|
331 |
|
332 return rest_ensure_response( $response ); |
246 } |
333 } |
247 |
334 |
248 /** |
335 /** |
249 * Checks if a given request has access to create a template. |
336 * Checks if a given request has access to create a template. |
250 * |
337 * |
264 * |
351 * |
265 * @param WP_REST_Request $request Full details about the request. |
352 * @param WP_REST_Request $request Full details about the request. |
266 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
353 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. |
267 */ |
354 */ |
268 public function create_item( $request ) { |
355 public function create_item( $request ) { |
269 $changes = $this->prepare_item_for_database( $request ); |
356 $prepared_post = $this->prepare_item_for_database( $request ); |
270 $changes->post_name = $request['slug']; |
357 |
271 $result = wp_insert_post( wp_slash( (array) $changes ), true ); |
358 if ( is_wp_error( $prepared_post ) ) { |
272 if ( is_wp_error( $result ) ) { |
359 return $prepared_post; |
273 return $result; |
360 } |
274 } |
361 |
275 $posts = get_block_templates( array( 'wp_id' => $result ), $this->post_type ); |
362 $prepared_post->post_name = $request['slug']; |
|
363 $post_id = wp_insert_post( wp_slash( (array) $prepared_post ), true ); |
|
364 if ( is_wp_error( $post_id ) ) { |
|
365 if ( 'db_insert_error' === $post_id->get_error_code() ) { |
|
366 $post_id->add_data( array( 'status' => 500 ) ); |
|
367 } else { |
|
368 $post_id->add_data( array( 'status' => 400 ) ); |
|
369 } |
|
370 |
|
371 return $post_id; |
|
372 } |
|
373 $posts = get_block_templates( array( 'wp_id' => $post_id ), $this->post_type ); |
276 if ( ! count( $posts ) ) { |
374 if ( ! count( $posts ) ) { |
277 return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ) ); |
375 return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ), array( 'status' => 400 ) ); |
278 } |
376 } |
279 $id = $posts[0]->id; |
377 $id = $posts[0]->id; |
|
378 $post = get_post( $post_id ); |
280 $template = get_block_template( $id, $this->post_type ); |
379 $template = get_block_template( $id, $this->post_type ); |
281 $fields_update = $this->update_additional_fields_for_object( $template, $request ); |
380 $fields_update = $this->update_additional_fields_for_object( $template, $request ); |
282 if ( is_wp_error( $fields_update ) ) { |
381 if ( is_wp_error( $fields_update ) ) { |
283 return $fields_update; |
382 return $fields_update; |
284 } |
383 } |
285 |
384 |
286 return $this->prepare_item_for_response( |
385 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ |
287 get_block_template( $id, $this->post_type ), |
386 do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); |
288 $request |
387 |
289 ); |
388 wp_after_insert_post( $post, false, null ); |
|
389 |
|
390 $response = $this->prepare_item_for_response( $template, $request ); |
|
391 $response = rest_ensure_response( $response ); |
|
392 |
|
393 $response->set_status( 201 ); |
|
394 $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $template->id ) ) ); |
|
395 |
|
396 return $response; |
290 } |
397 } |
291 |
398 |
292 /** |
399 /** |
293 * Checks if a given request has access to delete a single template. |
400 * Checks if a given request has access to delete a single template. |
294 * |
401 * |
319 } |
426 } |
320 |
427 |
321 $id = $template->wp_id; |
428 $id = $template->wp_id; |
322 $force = (bool) $request['force']; |
429 $force = (bool) $request['force']; |
323 |
430 |
|
431 $request->set_param( 'context', 'edit' ); |
|
432 |
324 // If we're forcing, then delete permanently. |
433 // If we're forcing, then delete permanently. |
325 if ( $force ) { |
434 if ( $force ) { |
326 $previous = $this->prepare_item_for_response( $template, $request ); |
435 $previous = $this->prepare_item_for_response( $template, $request ); |
327 wp_delete_post( $id, true ); |
436 $result = wp_delete_post( $id, true ); |
328 $response = new WP_REST_Response(); |
437 $response = new WP_REST_Response(); |
329 $response->set_data( |
438 $response->set_data( |
330 array( |
439 array( |
331 'deleted' => true, |
440 'deleted' => true, |
332 'previous' => $previous->get_data(), |
441 'previous' => $previous->get_data(), |
333 ) |
442 ) |
334 ); |
443 ); |
335 |
444 } else { |
336 return $response; |
445 // Otherwise, only trash if we haven't already. |
337 } |
446 if ( 'trash' === $template->status ) { |
338 |
447 return new WP_Error( |
339 // Otherwise, only trash if we haven't already. |
448 'rest_template_already_trashed', |
340 if ( 'trash' === $template->status ) { |
449 __( 'The template has already been deleted.' ), |
|
450 array( 'status' => 410 ) |
|
451 ); |
|
452 } |
|
453 |
|
454 // (Note that internally this falls through to `wp_delete_post()` |
|
455 // if the Trash is disabled.) |
|
456 $result = wp_trash_post( $id ); |
|
457 $template->status = 'trash'; |
|
458 $response = $this->prepare_item_for_response( $template, $request ); |
|
459 } |
|
460 |
|
461 if ( ! $result ) { |
341 return new WP_Error( |
462 return new WP_Error( |
342 'rest_template_already_trashed', |
463 'rest_cannot_delete', |
343 __( 'The template has already been deleted.' ), |
464 __( 'The template cannot be deleted.' ), |
344 array( 'status' => 410 ) |
465 array( 'status' => 500 ) |
345 ); |
466 ); |
346 } |
467 } |
347 |
468 |
348 wp_trash_post( $id ); |
469 return $response; |
349 $template->status = 'trash'; |
|
350 return $this->prepare_item_for_response( $template, $request ); |
|
351 } |
470 } |
352 |
471 |
353 /** |
472 /** |
354 * Prepares a single template for create or update. |
473 * Prepares a single template for create or update. |
355 * |
474 * |
372 $changes->post_type = $this->post_type; |
491 $changes->post_type = $this->post_type; |
373 $changes->post_status = 'publish'; |
492 $changes->post_status = 'publish'; |
374 $changes->tax_input = array( |
493 $changes->tax_input = array( |
375 'wp_theme' => $template->theme, |
494 'wp_theme' => $template->theme, |
376 ); |
495 ); |
|
496 $changes->meta_input = array( |
|
497 'origin' => $template->source, |
|
498 ); |
377 } else { |
499 } else { |
378 $changes->post_name = $template->slug; |
500 $changes->post_name = $template->slug; |
379 $changes->ID = $template->wp_id; |
501 $changes->ID = $template->wp_id; |
380 $changes->post_status = 'publish'; |
502 $changes->post_status = 'publish'; |
381 } |
503 } |
382 if ( isset( $request['content'] ) ) { |
504 if ( isset( $request['content'] ) ) { |
383 $changes->post_content = $request['content']; |
505 if ( is_string( $request['content'] ) ) { |
|
506 $changes->post_content = $request['content']; |
|
507 } elseif ( isset( $request['content']['raw'] ) ) { |
|
508 $changes->post_content = $request['content']['raw']; |
|
509 } |
384 } elseif ( null !== $template && 'custom' !== $template->source ) { |
510 } elseif ( null !== $template && 'custom' !== $template->source ) { |
385 $changes->post_content = $template->content; |
511 $changes->post_content = $template->content; |
386 } |
512 } |
387 if ( isset( $request['title'] ) ) { |
513 if ( isset( $request['title'] ) ) { |
388 $changes->post_title = $request['title']; |
514 if ( is_string( $request['title'] ) ) { |
|
515 $changes->post_title = $request['title']; |
|
516 } elseif ( ! empty( $request['title']['raw'] ) ) { |
|
517 $changes->post_title = $request['title']['raw']; |
|
518 } |
389 } elseif ( null !== $template && 'custom' !== $template->source ) { |
519 } elseif ( null !== $template && 'custom' !== $template->source ) { |
390 $changes->post_title = $template->title; |
520 $changes->post_title = $template->title; |
391 } |
521 } |
392 if ( isset( $request['description'] ) ) { |
522 if ( isset( $request['description'] ) ) { |
393 $changes->post_excerpt = $request['description']; |
523 $changes->post_excerpt = $request['description']; |
394 } elseif ( null !== $template && 'custom' !== $template->source ) { |
524 } elseif ( null !== $template && 'custom' !== $template->source ) { |
395 $changes->post_excerpt = $template->description; |
525 $changes->post_excerpt = $template->description; |
396 } |
526 } |
397 |
527 |
|
528 if ( 'wp_template_part' === $this->post_type ) { |
|
529 if ( isset( $request['area'] ) ) { |
|
530 $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] ); |
|
531 } elseif ( null !== $template && 'custom' !== $template->source && $template->area ) { |
|
532 $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $template->area ); |
|
533 } elseif ( ! $template->area ) { |
|
534 $changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; |
|
535 } |
|
536 } |
|
537 |
|
538 if ( ! empty( $request['author'] ) ) { |
|
539 $post_author = (int) $request['author']; |
|
540 |
|
541 if ( get_current_user_id() !== $post_author ) { |
|
542 $user_obj = get_userdata( $post_author ); |
|
543 |
|
544 if ( ! $user_obj ) { |
|
545 return new WP_Error( |
|
546 'rest_invalid_author', |
|
547 __( 'Invalid author ID.' ), |
|
548 array( 'status' => 400 ) |
|
549 ); |
|
550 } |
|
551 } |
|
552 |
|
553 $changes->post_author = $post_author; |
|
554 } |
|
555 |
398 return $changes; |
556 return $changes; |
399 } |
557 } |
400 |
558 |
401 /** |
559 /** |
402 * Prepare a single template output for response |
560 * Prepare a single template output for response |
403 * |
561 * |
404 * @since 5.8.0 |
562 * @since 5.8.0 |
405 * |
563 * @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support. |
406 * @param WP_Block_Template $template Template instance. |
564 * |
|
565 * @param WP_Block_Template $item Template instance. |
407 * @param WP_REST_Request $request Request object. |
566 * @param WP_REST_Request $request Request object. |
408 * @return WP_REST_Response $data |
567 * @return WP_REST_Response Response object. |
409 */ |
568 */ |
410 public function prepare_item_for_response( $template, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
569 public function prepare_item_for_response( $item, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable |
411 $result = array( |
570 // Restores the more descriptive, specific name for use within this method. |
412 'id' => $template->id, |
571 $template = $item; |
413 'theme' => $template->theme, |
572 |
414 'content' => array( 'raw' => $template->content ), |
573 $fields = $this->get_fields_for_response( $request ); |
415 'slug' => $template->slug, |
574 |
416 'source' => $template->source, |
575 // Base fields for every template. |
417 'type' => $template->type, |
576 $data = array(); |
418 'description' => $template->description, |
577 |
419 'title' => array( |
578 if ( rest_is_field_included( 'id', $fields ) ) { |
420 'raw' => $template->title, |
579 $data['id'] = $template->id; |
421 'rendered' => $template->title, |
580 } |
422 ), |
581 |
423 'status' => $template->status, |
582 if ( rest_is_field_included( 'theme', $fields ) ) { |
424 'wp_id' => $template->wp_id, |
583 $data['theme'] = $template->theme; |
425 'has_theme_file' => $template->has_theme_file, |
584 } |
426 ); |
585 |
427 |
586 if ( rest_is_field_included( 'content', $fields ) ) { |
428 if ( 'wp_template_part' === $template->type ) { |
587 $data['content'] = array(); |
429 $result['area'] = $template->area; |
588 } |
430 } |
589 if ( rest_is_field_included( 'content.raw', $fields ) ) { |
431 |
590 $data['content']['raw'] = $template->content; |
432 $result = $this->add_additional_fields_to_object( $result, $request ); |
591 } |
433 |
592 |
434 $response = rest_ensure_response( $result ); |
593 if ( rest_is_field_included( 'content.block_version', $fields ) ) { |
435 $links = $this->prepare_links( $template->id ); |
594 $data['content']['block_version'] = block_version( $template->content ); |
|
595 } |
|
596 |
|
597 if ( rest_is_field_included( 'slug', $fields ) ) { |
|
598 $data['slug'] = $template->slug; |
|
599 } |
|
600 |
|
601 if ( rest_is_field_included( 'source', $fields ) ) { |
|
602 $data['source'] = $template->source; |
|
603 } |
|
604 |
|
605 if ( rest_is_field_included( 'origin', $fields ) ) { |
|
606 $data['origin'] = $template->origin; |
|
607 } |
|
608 |
|
609 if ( rest_is_field_included( 'type', $fields ) ) { |
|
610 $data['type'] = $template->type; |
|
611 } |
|
612 |
|
613 if ( rest_is_field_included( 'description', $fields ) ) { |
|
614 $data['description'] = $template->description; |
|
615 } |
|
616 |
|
617 if ( rest_is_field_included( 'title', $fields ) ) { |
|
618 $data['title'] = array(); |
|
619 } |
|
620 |
|
621 if ( rest_is_field_included( 'title.raw', $fields ) ) { |
|
622 $data['title']['raw'] = $template->title; |
|
623 } |
|
624 |
|
625 if ( rest_is_field_included( 'title.rendered', $fields ) ) { |
|
626 if ( $template->wp_id ) { |
|
627 /** This filter is documented in wp-includes/post-template.php */ |
|
628 $data['title']['rendered'] = apply_filters( 'the_title', $template->title, $template->wp_id ); |
|
629 } else { |
|
630 $data['title']['rendered'] = $template->title; |
|
631 } |
|
632 } |
|
633 |
|
634 if ( rest_is_field_included( 'status', $fields ) ) { |
|
635 $data['status'] = $template->status; |
|
636 } |
|
637 |
|
638 if ( rest_is_field_included( 'wp_id', $fields ) ) { |
|
639 $data['wp_id'] = (int) $template->wp_id; |
|
640 } |
|
641 |
|
642 if ( rest_is_field_included( 'has_theme_file', $fields ) ) { |
|
643 $data['has_theme_file'] = (bool) $template->has_theme_file; |
|
644 } |
|
645 |
|
646 if ( rest_is_field_included( 'is_custom', $fields ) && 'wp_template' === $template->type ) { |
|
647 $data['is_custom'] = $template->is_custom; |
|
648 } |
|
649 |
|
650 if ( rest_is_field_included( 'author', $fields ) ) { |
|
651 $data['author'] = (int) $template->author; |
|
652 } |
|
653 |
|
654 if ( rest_is_field_included( 'area', $fields ) && 'wp_template_part' === $template->type ) { |
|
655 $data['area'] = $template->area; |
|
656 } |
|
657 |
|
658 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
|
659 $data = $this->add_additional_fields_to_object( $data, $request ); |
|
660 $data = $this->filter_response_by_context( $data, $context ); |
|
661 |
|
662 // Wrap the data in a response object. |
|
663 $response = rest_ensure_response( $data ); |
|
664 |
|
665 $links = $this->prepare_links( $template->id ); |
436 $response->add_links( $links ); |
666 $response->add_links( $links ); |
437 if ( ! empty( $links['self']['href'] ) ) { |
667 if ( ! empty( $links['self']['href'] ) ) { |
438 $actions = $this->get_available_actions(); |
668 $actions = $this->get_available_actions(); |
439 $self = $links['self']['href']; |
669 $self = $links['self']['href']; |
440 foreach ( $actions as $rel ) { |
670 foreach ( $actions as $rel ) { |
539 'description' => __( 'Unique slug identifying the template.' ), |
779 'description' => __( 'Unique slug identifying the template.' ), |
540 'type' => 'string', |
780 'type' => 'string', |
541 'context' => array( 'embed', 'view', 'edit' ), |
781 'context' => array( 'embed', 'view', 'edit' ), |
542 'required' => true, |
782 'required' => true, |
543 'minLength' => 1, |
783 'minLength' => 1, |
544 'pattern' => '[a-zA-Z_\-]+', |
784 'pattern' => '[a-zA-Z0-9_\-]+', |
545 ), |
785 ), |
546 'theme' => array( |
786 'theme' => array( |
547 'description' => __( 'Theme identifier for the template.' ), |
787 'description' => __( 'Theme identifier for the template.' ), |
548 'type' => 'string', |
788 'type' => 'string', |
549 'context' => array( 'embed', 'view', 'edit' ), |
789 'context' => array( 'embed', 'view', 'edit' ), |
550 ), |
790 ), |
|
791 'type' => array( |
|
792 'description' => __( 'Type of template.' ), |
|
793 'type' => 'string', |
|
794 'context' => array( 'embed', 'view', 'edit' ), |
|
795 ), |
551 'source' => array( |
796 'source' => array( |
552 'description' => __( 'Source of template' ), |
797 'description' => __( 'Source of template' ), |
|
798 'type' => 'string', |
|
799 'context' => array( 'embed', 'view', 'edit' ), |
|
800 'readonly' => true, |
|
801 ), |
|
802 'origin' => array( |
|
803 'description' => __( 'Source of a customized template' ), |
553 'type' => 'string', |
804 'type' => 'string', |
554 'context' => array( 'embed', 'view', 'edit' ), |
805 'context' => array( 'embed', 'view', 'edit' ), |
555 'readonly' => true, |
806 'readonly' => true, |
556 ), |
807 ), |
557 'content' => array( |
808 'content' => array( |
558 'description' => __( 'Content of template.' ), |
809 'description' => __( 'Content of template.' ), |
559 'type' => array( 'object', 'string' ), |
810 'type' => array( 'object', 'string' ), |
560 'default' => '', |
811 'default' => '', |
561 'context' => array( 'embed', 'view', 'edit' ), |
812 'context' => array( 'embed', 'view', 'edit' ), |
|
813 'properties' => array( |
|
814 'raw' => array( |
|
815 'description' => __( 'Content for the template, as it exists in the database.' ), |
|
816 'type' => 'string', |
|
817 'context' => array( 'view', 'edit' ), |
|
818 ), |
|
819 'block_version' => array( |
|
820 'description' => __( 'Version of the content block format used by the template.' ), |
|
821 'type' => 'integer', |
|
822 'context' => array( 'edit' ), |
|
823 'readonly' => true, |
|
824 ), |
|
825 ), |
562 ), |
826 ), |
563 'title' => array( |
827 'title' => array( |
564 'description' => __( 'Title of template.' ), |
828 'description' => __( 'Title of template.' ), |
565 'type' => array( 'object', 'string' ), |
829 'type' => array( 'object', 'string' ), |
566 'default' => '', |
830 'default' => '', |
567 'context' => array( 'embed', 'view', 'edit' ), |
831 'context' => array( 'embed', 'view', 'edit' ), |
|
832 'properties' => array( |
|
833 'raw' => array( |
|
834 'description' => __( 'Title for the template, as it exists in the database.' ), |
|
835 'type' => 'string', |
|
836 'context' => array( 'view', 'edit', 'embed' ), |
|
837 ), |
|
838 'rendered' => array( |
|
839 'description' => __( 'HTML title for the template, transformed for display.' ), |
|
840 'type' => 'string', |
|
841 'context' => array( 'view', 'edit', 'embed' ), |
|
842 'readonly' => true, |
|
843 ), |
|
844 ), |
568 ), |
845 ), |
569 'description' => array( |
846 'description' => array( |
570 'description' => __( 'Description of template.' ), |
847 'description' => __( 'Description of template.' ), |
571 'type' => 'string', |
848 'type' => 'string', |
572 'default' => '', |
849 'default' => '', |
573 'context' => array( 'embed', 'view', 'edit' ), |
850 'context' => array( 'embed', 'view', 'edit' ), |
574 ), |
851 ), |
575 'status' => array( |
852 'status' => array( |
576 'description' => __( 'Status of template.' ), |
853 'description' => __( 'Status of template.' ), |
577 'type' => 'string', |
854 'type' => 'string', |
|
855 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), |
578 'default' => 'publish', |
856 'default' => 'publish', |
579 'context' => array( 'embed', 'view', 'edit' ), |
857 'context' => array( 'embed', 'view', 'edit' ), |
580 ), |
858 ), |
581 'wp_id' => array( |
859 'wp_id' => array( |
582 'description' => __( 'Post ID.' ), |
860 'description' => __( 'Post ID.' ), |