[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-templates-controller.php (source)

   1  <?php
   2  /**
   3   * REST API: WP_REST_Templates_Controller class
   4   *
   5   * @package    WordPress
   6   * @subpackage REST_API
   7   * @since 5.8.0
   8   */
   9  
  10  /**
  11   * Base Templates REST API Controller.
  12   *
  13   * @since 5.8.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Templates_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * Post type.
  21       *
  22       * @since 5.8.0
  23       * @var string
  24       */
  25      protected $post_type;
  26  
  27      /**
  28       * Constructor.
  29       *
  30       * @since 5.8.0
  31       *
  32       * @param string $post_type Post type.
  33       */
  34  	public function __construct( $post_type ) {
  35          $this->post_type = $post_type;
  36          $obj             = get_post_type_object( $post_type );
  37          $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name;
  38          $this->namespace = ! empty( $obj->rest_namespace ) ? $obj->rest_namespace : 'wp/v2';
  39      }
  40  
  41      /**
  42       * Registers the controllers routes.
  43       *
  44       * @since 5.8.0
  45       */
  46  	public function register_routes() {
  47          // Lists all templates.
  48          register_rest_route(
  49              $this->namespace,
  50              '/' . $this->rest_base,
  51              array(
  52                  array(
  53                      'methods'             => WP_REST_Server::READABLE,
  54                      'callback'            => array( $this, 'get_items' ),
  55                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  56                      'args'                => $this->get_collection_params(),
  57                  ),
  58                  array(
  59                      'methods'             => WP_REST_Server::CREATABLE,
  60                      'callback'            => array( $this, 'create_item' ),
  61                      'permission_callback' => array( $this, 'create_item_permissions_check' ),
  62                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
  63                  ),
  64                  'schema' => array( $this, 'get_public_item_schema' ),
  65              )
  66          );
  67  
  68          // Lists/updates a single template based on the given id.
  69          register_rest_route(
  70              $this->namespace,
  71              // The route.
  72              sprintf(
  73                  '/%s/(?P<id>%s%s)',
  74                  $this->rest_base,
  75                  // Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
  76                  // Excludes invalid directory name characters: `/:<>*?"|`.
  77                  '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
  78                  // Matches the template name.
  79                  '[\/\w-]+'
  80              ),
  81              array(
  82                  'args'   => array(
  83                      'id' => array(
  84                          'description'       => __( 'The id of a template' ),
  85                          'type'              => 'string',
  86                          'sanitize_callback' => array( $this, '_sanitize_template_id' ),
  87                      ),
  88                  ),
  89                  array(
  90                      'methods'             => WP_REST_Server::READABLE,
  91                      'callback'            => array( $this, 'get_item' ),
  92                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
  93                      'args'                => array(
  94                          'context' => $this->get_context_param( array( 'default' => 'view' ) ),
  95                      ),
  96                  ),
  97                  array(
  98                      'methods'             => WP_REST_Server::EDITABLE,
  99                      'callback'            => array( $this, 'update_item' ),
 100                      'permission_callback' => array( $this, 'update_item_permissions_check' ),
 101                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
 102                  ),
 103                  array(
 104                      'methods'             => WP_REST_Server::DELETABLE,
 105                      'callback'            => array( $this, 'delete_item' ),
 106                      'permission_callback' => array( $this, 'delete_item_permissions_check' ),
 107                      'args'                => array(
 108                          'force' => array(
 109                              'type'        => 'boolean',
 110                              'default'     => false,
 111                              'description' => __( 'Whether to bypass Trash and force deletion.' ),
 112                          ),
 113                      ),
 114                  ),
 115                  'schema' => array( $this, 'get_public_item_schema' ),
 116              )
 117          );
 118      }
 119  
 120      /**
 121       * Checks if the user has permissions to make the request.
 122       *
 123       * @since 5.8.0
 124       *
 125       * @param WP_REST_Request $request Full details about the request.
 126       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 127       */
 128  	protected function permissions_check( $request ) {
 129          // Verify if the current user has edit_theme_options capability.
 130          // This capability is required to edit/view/delete templates.
 131          if ( ! current_user_can( 'edit_theme_options' ) ) {
 132              return new WP_Error(
 133                  'rest_cannot_manage_templates',
 134                  __( 'Sorry, you are not allowed to access the templates on this site.' ),
 135                  array(
 136                      'status' => rest_authorization_required_code(),
 137                  )
 138              );
 139          }
 140  
 141          return true;
 142      }
 143  
 144      /**
 145       * Requesting this endpoint for a template like 'twentytwentytwo//home'
 146       * requires using a path like /wp/v2/templates/twentytwentytwo//home. There
 147       * are special cases when WordPress routing corrects the name to contain
 148       * only a single slash like 'twentytwentytwo/home'.
 149       *
 150       * This method doubles the last slash if it's not already doubled. It relies
 151       * on the template ID format {theme_name}//{template_slug} and the fact that
 152       * slugs cannot contain slashes.
 153       *
 154       * @since 5.9.0
 155       * @see https://core.trac.wordpress.org/ticket/54507
 156       *
 157       * @param string $id Template ID.
 158       * @return string Sanitized template ID.
 159       */
 160  	public function _sanitize_template_id( $id ) {
 161          $id = urldecode( $id );
 162  
 163          $last_slash_pos = strrpos( $id, '/' );
 164          if ( false === $last_slash_pos ) {
 165              return $id;
 166          }
 167  
 168          $is_double_slashed = substr( $id, $last_slash_pos - 1, 1 ) === '/';
 169          if ( $is_double_slashed ) {
 170              return $id;
 171          }
 172          return (
 173              substr( $id, 0, $last_slash_pos )
 174              . '/'
 175              . substr( $id, $last_slash_pos )
 176          );
 177      }
 178  
 179      /**
 180       * Checks if a given request has access to read templates.
 181       *
 182       * @since 5.8.0
 183       *
 184       * @param WP_REST_Request $request Full details about the request.
 185       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 186       */
 187  	public function get_items_permissions_check( $request ) {
 188          return $this->permissions_check( $request );
 189      }
 190  
 191      /**
 192       * Returns a list of templates.
 193       *
 194       * @since 5.8.0
 195       *
 196       * @param WP_REST_Request $request The request instance.
 197       * @return WP_REST_Response
 198       */
 199  	public function get_items( $request ) {
 200          $query = array();
 201          if ( isset( $request['wp_id'] ) ) {
 202              $query['wp_id'] = $request['wp_id'];
 203          }
 204          if ( isset( $request['area'] ) ) {
 205              $query['area'] = $request['area'];
 206          }
 207          if ( isset( $request['post_type'] ) ) {
 208              $query['post_type'] = $request['post_type'];
 209          }
 210  
 211          $templates = array();
 212          foreach ( get_block_templates( $query, $this->post_type ) as $template ) {
 213              $data        = $this->prepare_item_for_response( $template, $request );
 214              $templates[] = $this->prepare_response_for_collection( $data );
 215          }
 216  
 217          return rest_ensure_response( $templates );
 218      }
 219  
 220      /**
 221       * Checks if a given request has access to read a single template.
 222       *
 223       * @since 5.8.0
 224       *
 225       * @param WP_REST_Request $request Full details about the request.
 226       * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
 227       */
 228  	public function get_item_permissions_check( $request ) {
 229          return $this->permissions_check( $request );
 230      }
 231  
 232      /**
 233       * Returns the given template
 234       *
 235       * @since 5.8.0
 236       *
 237       * @param WP_REST_Request $request The request instance.
 238       * @return WP_REST_Response|WP_Error
 239       */
 240  	public function get_item( $request ) {
 241          if ( isset( $request['source'] ) && 'theme' === $request['source'] ) {
 242              $template = get_block_file_template( $request['id'], $this->post_type );
 243          } else {
 244              $template = get_block_template( $request['id'], $this->post_type );
 245          }
 246  
 247          if ( ! $template ) {
 248              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 249          }
 250  
 251          return $this->prepare_item_for_response( $template, $request );
 252      }
 253  
 254      /**
 255       * Checks if a given request has access to write a single template.
 256       *
 257       * @since 5.8.0
 258       *
 259       * @param WP_REST_Request $request Full details about the request.
 260       * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
 261       */
 262  	public function update_item_permissions_check( $request ) {
 263          return $this->permissions_check( $request );
 264      }
 265  
 266      /**
 267       * Updates a single template.
 268       *
 269       * @since 5.8.0
 270       *
 271       * @param WP_REST_Request $request Full details about the request.
 272       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 273       */
 274  	public function update_item( $request ) {
 275          $template = get_block_template( $request['id'], $this->post_type );
 276          if ( ! $template ) {
 277              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 278          }
 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  
 292          $changes = $this->prepare_item_for_database( $request );
 293  
 294          if ( is_wp_error( $changes ) ) {
 295              return $changes;
 296          }
 297  
 298          if ( 'custom' === $template->source ) {
 299              $update = true;
 300              $result = wp_update_post( wp_slash( (array) $changes ), false );
 301          } else {
 302              $update      = false;
 303              $post_before = null;
 304              $result      = wp_insert_post( wp_slash( (array) $changes ), false );
 305          }
 306  
 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              }
 313              return $result;
 314          }
 315  
 316          $template      = get_block_template( $request['id'], $this->post_type );
 317          $fields_update = $this->update_additional_fields_for_object( $template, $request );
 318          if ( is_wp_error( $fields_update ) ) {
 319              return $fields_update;
 320          }
 321  
 322          $request->set_param( 'context', 'edit' );
 323  
 324          $post = get_post( $template->wp_id );
 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 );
 333      }
 334  
 335      /**
 336       * Checks if a given request has access to create a template.
 337       *
 338       * @since 5.8.0
 339       *
 340       * @param WP_REST_Request $request Full details about the request.
 341       * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
 342       */
 343  	public function create_item_permissions_check( $request ) {
 344          return $this->permissions_check( $request );
 345      }
 346  
 347      /**
 348       * Creates a single template.
 349       *
 350       * @since 5.8.0
 351       *
 352       * @param WP_REST_Request $request Full details about the request.
 353       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 354       */
 355  	public function create_item( $request ) {
 356          $prepared_post = $this->prepare_item_for_database( $request );
 357  
 358          if ( is_wp_error( $prepared_post ) ) {
 359              return $prepared_post;
 360          }
 361  
 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 );
 374          if ( ! count( $posts ) ) {
 375              return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ), array( 'status' => 400 ) );
 376          }
 377          $id            = $posts[0]->id;
 378          $post          = get_post( $post_id );
 379          $template      = get_block_template( $id, $this->post_type );
 380          $fields_update = $this->update_additional_fields_for_object( $template, $request );
 381          if ( is_wp_error( $fields_update ) ) {
 382              return $fields_update;
 383          }
 384  
 385          /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */
 386          do_action( "rest_after_insert_{$this->post_type}", $post, $request, true );
 387  
 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;
 397      }
 398  
 399      /**
 400       * Checks if a given request has access to delete a single template.
 401       *
 402       * @since 5.8.0
 403       *
 404       * @param WP_REST_Request $request Full details about the request.
 405       * @return true|WP_Error True if the request has delete access for the item, WP_Error object otherwise.
 406       */
 407  	public function delete_item_permissions_check( $request ) {
 408          return $this->permissions_check( $request );
 409      }
 410  
 411      /**
 412       * Deletes a single template.
 413       *
 414       * @since 5.8.0
 415       *
 416       * @param WP_REST_Request $request Full details about the request.
 417       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 418       */
 419  	public function delete_item( $request ) {
 420          $template = get_block_template( $request['id'], $this->post_type );
 421          if ( ! $template ) {
 422              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 423          }
 424          if ( 'custom' !== $template->source ) {
 425              return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.' ), array( 'status' => 400 ) );
 426          }
 427  
 428          $id    = $template->wp_id;
 429          $force = (bool) $request['force'];
 430  
 431          $request->set_param( 'context', 'edit' );
 432  
 433          // If we're forcing, then delete permanently.
 434          if ( $force ) {
 435              $previous = $this->prepare_item_for_response( $template, $request );
 436              $result   = wp_delete_post( $id, true );
 437              $response = new WP_REST_Response();
 438              $response->set_data(
 439                  array(
 440                      'deleted'  => true,
 441                      'previous' => $previous->get_data(),
 442                  )
 443              );
 444          } else {
 445              // Otherwise, only trash if we haven't already.
 446              if ( 'trash' === $template->status ) {
 447                  return new WP_Error(
 448                      'rest_template_already_trashed',
 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 ) {
 462              return new WP_Error(
 463                  'rest_cannot_delete',
 464                  __( 'The template cannot be deleted.' ),
 465                  array( 'status' => 500 )
 466              );
 467          }
 468  
 469          return $response;
 470      }
 471  
 472      /**
 473       * Prepares a single template for create or update.
 474       *
 475       * @since 5.8.0
 476       *
 477       * @param WP_REST_Request $request Request object.
 478       * @return stdClass Changes to pass to wp_update_post.
 479       */
 480  	protected function prepare_item_for_database( $request ) {
 481          $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null;
 482          $changes  = new stdClass();
 483          if ( null === $template ) {
 484              $changes->post_type   = $this->post_type;
 485              $changes->post_status = 'publish';
 486              $changes->tax_input   = array(
 487                  'wp_theme' => isset( $request['theme'] ) ? $request['theme'] : wp_get_theme()->get_stylesheet(),
 488              );
 489          } elseif ( 'custom' !== $template->source ) {
 490              $changes->post_name   = $template->slug;
 491              $changes->post_type   = $this->post_type;
 492              $changes->post_status = 'publish';
 493              $changes->tax_input   = array(
 494                  'wp_theme' => $template->theme,
 495              );
 496              $changes->meta_input  = array(
 497                  'origin' => $template->source,
 498              );
 499          } else {
 500              $changes->post_name   = $template->slug;
 501              $changes->ID          = $template->wp_id;
 502              $changes->post_status = 'publish';
 503          }
 504          if ( isset( $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              }
 510          } elseif ( null !== $template && 'custom' !== $template->source ) {
 511              $changes->post_content = $template->content;
 512          }
 513          if ( isset( $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              }
 519          } elseif ( null !== $template && 'custom' !== $template->source ) {
 520              $changes->post_title = $template->title;
 521          }
 522          if ( isset( $request['description'] ) ) {
 523              $changes->post_excerpt = $request['description'];
 524          } elseif ( null !== $template && 'custom' !== $template->source ) {
 525              $changes->post_excerpt = $template->description;
 526          }
 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  
 556          return $changes;
 557      }
 558  
 559      /**
 560       * Prepare a single template output for response
 561       *
 562       * @since 5.8.0
 563       * @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support.
 564       *
 565       * @param WP_Block_Template $item    Template instance.
 566       * @param WP_REST_Request   $request Request object.
 567       * @return WP_REST_Response Response object.
 568       */
 569  	public function prepare_item_for_response( $item, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
 570          // Restores the more descriptive, specific name for use within this method.
 571          $template = $item;
 572  
 573          $fields = $this->get_fields_for_response( $request );
 574  
 575          // Base fields for every template.
 576          $data = array();
 577  
 578          if ( rest_is_field_included( 'id', $fields ) ) {
 579              $data['id'] = $template->id;
 580          }
 581  
 582          if ( rest_is_field_included( 'theme', $fields ) ) {
 583              $data['theme'] = $template->theme;
 584          }
 585  
 586          if ( rest_is_field_included( 'content', $fields ) ) {
 587              $data['content'] = array();
 588          }
 589          if ( rest_is_field_included( 'content.raw', $fields ) ) {
 590              $data['content']['raw'] = $template->content;
 591          }
 592  
 593          if ( rest_is_field_included( 'content.block_version', $fields ) ) {
 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 );
 666          $response->add_links( $links );
 667          if ( ! empty( $links['self']['href'] ) ) {
 668              $actions = $this->get_available_actions();
 669              $self    = $links['self']['href'];
 670              foreach ( $actions as $rel ) {
 671                  $response->add_link( $rel, $self );
 672              }
 673          }
 674  
 675          return $response;
 676      }
 677  
 678  
 679      /**
 680       * Prepares links for the request.
 681       *
 682       * @since 5.8.0
 683       *
 684       * @param integer $id ID.
 685       * @return array Links for the given post.
 686       */
 687  	protected function prepare_links( $id ) {
 688          $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
 689  
 690          $links = array(
 691              'self'       => array(
 692                  'href' => rest_url( trailingslashit( $base ) . $id ),
 693              ),
 694              'collection' => array(
 695                  'href' => rest_url( $base ),
 696              ),
 697              'about'      => array(
 698                  'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
 699              ),
 700          );
 701  
 702          return $links;
 703      }
 704  
 705      /**
 706       * Get the link relations available for the post and current user.
 707       *
 708       * @since 5.8.0
 709       *
 710       * @return string[] List of link relations.
 711       */
 712  	protected function get_available_actions() {
 713          $rels = array();
 714  
 715          $post_type = get_post_type_object( $this->post_type );
 716  
 717          if ( current_user_can( $post_type->cap->publish_posts ) ) {
 718              $rels[] = 'https://api.w.org/action-publish';
 719          }
 720  
 721          if ( current_user_can( 'unfiltered_html' ) ) {
 722              $rels[] = 'https://api.w.org/action-unfiltered-html';
 723          }
 724  
 725          return $rels;
 726      }
 727  
 728      /**
 729       * Retrieves the query params for the posts collection.
 730       *
 731       * @since 5.8.0
 732       * @since 5.9.0 Added `'area'` and `'post_type'`.
 733       *
 734       * @return array Collection parameters.
 735       */
 736  	public function get_collection_params() {
 737          return array(
 738              'context'   => $this->get_context_param( array( 'default' => 'view' ) ),
 739              'wp_id'     => array(
 740                  'description' => __( 'Limit to the specified post id.' ),
 741                  'type'        => 'integer',
 742              ),
 743              'area'      => array(
 744                  'description' => __( 'Limit to the specified template part area.' ),
 745                  'type'        => 'string',
 746              ),
 747              'post_type' => array(
 748                  'description' => __( 'Post type to get the templates for.' ),
 749                  'type'        => 'string',
 750              ),
 751          );
 752      }
 753  
 754      /**
 755       * Retrieves the block type' schema, conforming to JSON Schema.
 756       *
 757       * @since 5.8.0
 758       * @since 5.9.0 Added `'area'`.
 759       *
 760       * @return array Item schema data.
 761       */
 762  	public function get_item_schema() {
 763          if ( $this->schema ) {
 764              return $this->add_additional_fields_schema( $this->schema );
 765          }
 766  
 767          $schema = array(
 768              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 769              'title'      => $this->post_type,
 770              'type'       => 'object',
 771              'properties' => array(
 772                  'id'             => array(
 773                      'description' => __( 'ID of template.' ),
 774                      'type'        => 'string',
 775                      'context'     => array( 'embed', 'view', 'edit' ),
 776                      'readonly'    => true,
 777                  ),
 778                  'slug'           => array(
 779                      'description' => __( 'Unique slug identifying the template.' ),
 780                      'type'        => 'string',
 781                      'context'     => array( 'embed', 'view', 'edit' ),
 782                      'required'    => true,
 783                      'minLength'   => 1,
 784                      'pattern'     => '[a-zA-Z0-9_\-]+',
 785                  ),
 786                  'theme'          => array(
 787                      'description' => __( 'Theme identifier for the template.' ),
 788                      'type'        => 'string',
 789                      'context'     => array( 'embed', 'view', 'edit' ),
 790                  ),
 791                  'type'           => array(
 792                      'description' => __( 'Type of template.' ),
 793                      'type'        => 'string',
 794                      'context'     => array( 'embed', 'view', 'edit' ),
 795                  ),
 796                  'source'         => array(
 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' ),
 804                      'type'        => 'string',
 805                      'context'     => array( 'embed', 'view', 'edit' ),
 806                      'readonly'    => true,
 807                  ),
 808                  'content'        => array(
 809                      'description' => __( 'Content of template.' ),
 810                      'type'        => array( 'object', 'string' ),
 811                      'default'     => '',
 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                      ),
 826                  ),
 827                  'title'          => array(
 828                      'description' => __( 'Title of template.' ),
 829                      'type'        => array( 'object', 'string' ),
 830                      'default'     => '',
 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                      ),
 845                  ),
 846                  'description'    => array(
 847                      'description' => __( 'Description of template.' ),
 848                      'type'        => 'string',
 849                      'default'     => '',
 850                      'context'     => array( 'embed', 'view', 'edit' ),
 851                  ),
 852                  'status'         => array(
 853                      'description' => __( 'Status of template.' ),
 854                      'type'        => 'string',
 855                      'enum'        => array_keys( get_post_stati( array( 'internal' => false ) ) ),
 856                      'default'     => 'publish',
 857                      'context'     => array( 'embed', 'view', 'edit' ),
 858                  ),
 859                  'wp_id'          => array(
 860                      'description' => __( 'Post ID.' ),
 861                      'type'        => 'integer',
 862                      'context'     => array( 'embed', 'view', 'edit' ),
 863                      'readonly'    => true,
 864                  ),
 865                  'has_theme_file' => array(
 866                      'description' => __( 'Theme file exists.' ),
 867                      'type'        => 'bool',
 868                      'context'     => array( 'embed', 'view', 'edit' ),
 869                      'readonly'    => true,
 870                  ),
 871                  'author'         => array(
 872                      'description' => __( 'The ID for the author of the template.' ),
 873                      'type'        => 'integer',
 874                      'context'     => array( 'view', 'edit', 'embed' ),
 875                  ),
 876              ),
 877          );
 878  
 879          if ( 'wp_template' === $this->post_type ) {
 880              $schema['properties']['is_custom'] = array(
 881                  'description' => __( 'Whether a template is a custom template.' ),
 882                  'type'        => 'bool',
 883                  'context'     => array( 'embed', 'view', 'edit' ),
 884                  'readonly'    => true,
 885              );
 886          }
 887  
 888          if ( 'wp_template_part' === $this->post_type ) {
 889              $schema['properties']['area'] = array(
 890                  'description' => __( 'Where the template part is intended for use (header, footer, etc.)' ),
 891                  'type'        => 'string',
 892                  'context'     => array( 'embed', 'view', 'edit' ),
 893              );
 894          }
 895  
 896          $this->schema = $schema;
 897  
 898          return $this->add_additional_fields_schema( $this->schema );
 899      }
 900  }


Generated: Thu Nov 21 01:00:03 2024 Cross-referenced by PHPXref 0.7.1