[ 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          $this->namespace = 'wp/v2';
  37          $obj             = get_post_type_object( $post_type );
  38          $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name;
  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              '/' . $this->rest_base . '/(?P<id>[\/\w-]+)',
  72              array(
  73                  array(
  74                      'methods'             => WP_REST_Server::READABLE,
  75                      'callback'            => array( $this, 'get_item' ),
  76                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
  77                      'args'                => array(
  78                          'id' => array(
  79                              'description' => __( 'The id of a template' ),
  80                              'type'        => 'string',
  81                          ),
  82                      ),
  83                  ),
  84                  array(
  85                      'methods'             => WP_REST_Server::EDITABLE,
  86                      'callback'            => array( $this, 'update_item' ),
  87                      'permission_callback' => array( $this, 'update_item_permissions_check' ),
  88                      'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
  89                  ),
  90                  array(
  91                      'methods'             => WP_REST_Server::DELETABLE,
  92                      'callback'            => array( $this, 'delete_item' ),
  93                      'permission_callback' => array( $this, 'delete_item_permissions_check' ),
  94                      'args'                => array(
  95                          'force' => array(
  96                              'type'        => 'boolean',
  97                              'default'     => false,
  98                              'description' => __( 'Whether to bypass Trash and force deletion.' ),
  99                          ),
 100                      ),
 101                  ),
 102                  'schema' => array( $this, 'get_public_item_schema' ),
 103              )
 104          );
 105      }
 106  
 107      /**
 108       * Checks if the user has permissions to make the request.
 109       *
 110       * @since 5.8.0
 111       *
 112       * @param WP_REST_Request $request Full details about the request.
 113       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 114       */
 115  	protected function permissions_check( $request ) {
 116          // Verify if the current user has edit_theme_options capability.
 117          // This capability is required to edit/view/delete templates.
 118          if ( ! current_user_can( 'edit_theme_options' ) ) {
 119              return new WP_Error(
 120                  'rest_cannot_manage_templates',
 121                  __( 'Sorry, you are not allowed to access the templates on this site.' ),
 122                  array(
 123                      'status' => rest_authorization_required_code(),
 124                  )
 125              );
 126          }
 127  
 128          return true;
 129      }
 130  
 131      /**
 132       * Checks if a given request has access to read templates.
 133       *
 134       * @since 5.8.0
 135       *
 136       * @param WP_REST_Request $request Full details about the request.
 137       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
 138       */
 139  	public function get_items_permissions_check( $request ) {
 140          return $this->permissions_check( $request );
 141      }
 142  
 143      /**
 144       * Returns a list of templates.
 145       *
 146       * @since 5.8.0
 147       *
 148       * @param WP_REST_Request $request The request instance.
 149       * @return WP_REST_Response
 150       */
 151  	public function get_items( $request ) {
 152          $query = array();
 153          if ( isset( $request['wp_id'] ) ) {
 154              $query['wp_id'] = $request['wp_id'];
 155          }
 156          if ( isset( $request['area'] ) ) {
 157              $query['area'] = $request['area'];
 158          }
 159  
 160          $templates = array();
 161          foreach ( get_block_templates( $query, $this->post_type ) as $template ) {
 162              $data        = $this->prepare_item_for_response( $template, $request );
 163              $templates[] = $this->prepare_response_for_collection( $data );
 164          }
 165  
 166          return rest_ensure_response( $templates );
 167      }
 168  
 169      /**
 170       * Checks if a given request has access to read a single template.
 171       *
 172       * @since 5.8.0
 173       *
 174       * @param WP_REST_Request $request Full details about the request.
 175       * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
 176       */
 177  	public function get_item_permissions_check( $request ) {
 178          return $this->permissions_check( $request );
 179      }
 180  
 181      /**
 182       * Returns the given template
 183       *
 184       * @since 5.8.0
 185       *
 186       * @param WP_REST_Request $request The request instance.
 187       * @return WP_REST_Response|WP_Error
 188       */
 189  	public function get_item( $request ) {
 190          $template = get_block_template( $request['id'], $this->post_type );
 191  
 192          if ( ! $template ) {
 193              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 194          }
 195  
 196          return $this->prepare_item_for_response( $template, $request );
 197      }
 198  
 199      /**
 200       * Checks if a given request has access to write a single template.
 201       *
 202       * @since 5.8.0
 203       *
 204       * @param WP_REST_Request $request Full details about the request.
 205       * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
 206       */
 207  	public function update_item_permissions_check( $request ) {
 208          return $this->permissions_check( $request );
 209      }
 210  
 211      /**
 212       * Updates a single template.
 213       *
 214       * @since 5.8.0
 215       *
 216       * @param WP_REST_Request $request Full details about the request.
 217       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 218       */
 219  	public function update_item( $request ) {
 220          $template = get_block_template( $request['id'], $this->post_type );
 221          if ( ! $template ) {
 222              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 223          }
 224  
 225          $changes = $this->prepare_item_for_database( $request );
 226  
 227          if ( 'custom' === $template->source ) {
 228              $result = wp_update_post( wp_slash( (array) $changes ), true );
 229          } else {
 230              $result = wp_insert_post( wp_slash( (array) $changes ), true );
 231          }
 232          if ( is_wp_error( $result ) ) {
 233              return $result;
 234          }
 235  
 236          $template      = get_block_template( $request['id'], $this->post_type );
 237          $fields_update = $this->update_additional_fields_for_object( $template, $request );
 238          if ( is_wp_error( $fields_update ) ) {
 239              return $fields_update;
 240          }
 241  
 242          return $this->prepare_item_for_response(
 243              get_block_template( $request['id'], $this->post_type ),
 244              $request
 245          );
 246      }
 247  
 248      /**
 249       * Checks if a given request has access to create a template.
 250       *
 251       * @since 5.8.0
 252       *
 253       * @param WP_REST_Request $request Full details about the request.
 254       * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise.
 255       */
 256  	public function create_item_permissions_check( $request ) {
 257          return $this->permissions_check( $request );
 258      }
 259  
 260      /**
 261       * Creates a single template.
 262       *
 263       * @since 5.8.0
 264       *
 265       * @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.
 267       */
 268  	public function create_item( $request ) {
 269          $changes            = $this->prepare_item_for_database( $request );
 270          $changes->post_name = $request['slug'];
 271          $result             = wp_insert_post( wp_slash( (array) $changes ), true );
 272          if ( is_wp_error( $result ) ) {
 273              return $result;
 274          }
 275          $posts = get_block_templates( array( 'wp_id' => $result ), $this->post_type );
 276          if ( ! count( $posts ) ) {
 277              return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ) );
 278          }
 279          $id            = $posts[0]->id;
 280          $template      = get_block_template( $id, $this->post_type );
 281          $fields_update = $this->update_additional_fields_for_object( $template, $request );
 282          if ( is_wp_error( $fields_update ) ) {
 283              return $fields_update;
 284          }
 285  
 286          return $this->prepare_item_for_response(
 287              get_block_template( $id, $this->post_type ),
 288              $request
 289          );
 290      }
 291  
 292      /**
 293       * Checks if a given request has access to delete a single template.
 294       *
 295       * @since 5.8.0
 296       *
 297       * @param WP_REST_Request $request Full details about the request.
 298       * @return true|WP_Error True if the request has delete access for the item, WP_Error object otherwise.
 299       */
 300  	public function delete_item_permissions_check( $request ) {
 301          return $this->permissions_check( $request );
 302      }
 303  
 304      /**
 305       * Deletes a single template.
 306       *
 307       * @since 5.8.0
 308       *
 309       * @param WP_REST_Request $request Full details about the request.
 310       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 311       */
 312  	public function delete_item( $request ) {
 313          $template = get_block_template( $request['id'], $this->post_type );
 314          if ( ! $template ) {
 315              return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) );
 316          }
 317          if ( 'custom' !== $template->source ) {
 318              return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.' ), array( 'status' => 400 ) );
 319          }
 320  
 321          $id    = $template->wp_id;
 322          $force = (bool) $request['force'];
 323  
 324          // If we're forcing, then delete permanently.
 325          if ( $force ) {
 326              $previous = $this->prepare_item_for_response( $template, $request );
 327              wp_delete_post( $id, true );
 328              $response = new WP_REST_Response();
 329              $response->set_data(
 330                  array(
 331                      'deleted'  => true,
 332                      'previous' => $previous->get_data(),
 333                  )
 334              );
 335  
 336              return $response;
 337          }
 338  
 339          // Otherwise, only trash if we haven't already.
 340          if ( 'trash' === $template->status ) {
 341              return new WP_Error(
 342                  'rest_template_already_trashed',
 343                  __( 'The template has already been deleted.' ),
 344                  array( 'status' => 410 )
 345              );
 346          }
 347  
 348          wp_trash_post( $id );
 349          $template->status = 'trash';
 350          return $this->prepare_item_for_response( $template, $request );
 351      }
 352  
 353      /**
 354       * Prepares a single template for create or update.
 355       *
 356       * @since 5.8.0
 357       *
 358       * @param WP_REST_Request $request Request object.
 359       * @return stdClass Changes to pass to wp_update_post.
 360       */
 361  	protected function prepare_item_for_database( $request ) {
 362          $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null;
 363          $changes  = new stdClass();
 364          if ( null === $template ) {
 365              $changes->post_type   = $this->post_type;
 366              $changes->post_status = 'publish';
 367              $changes->tax_input   = array(
 368                  'wp_theme' => isset( $request['theme'] ) ? $request['theme'] : wp_get_theme()->get_stylesheet(),
 369              );
 370          } elseif ( 'custom' !== $template->source ) {
 371              $changes->post_name   = $template->slug;
 372              $changes->post_type   = $this->post_type;
 373              $changes->post_status = 'publish';
 374              $changes->tax_input   = array(
 375                  'wp_theme' => $template->theme,
 376              );
 377          } else {
 378              $changes->post_name   = $template->slug;
 379              $changes->ID          = $template->wp_id;
 380              $changes->post_status = 'publish';
 381          }
 382          if ( isset( $request['content'] ) ) {
 383              $changes->post_content = $request['content'];
 384          } elseif ( null !== $template && 'custom' !== $template->source ) {
 385              $changes->post_content = $template->content;
 386          }
 387          if ( isset( $request['title'] ) ) {
 388              $changes->post_title = $request['title'];
 389          } elseif ( null !== $template && 'custom' !== $template->source ) {
 390              $changes->post_title = $template->title;
 391          }
 392          if ( isset( $request['description'] ) ) {
 393              $changes->post_excerpt = $request['description'];
 394          } elseif ( null !== $template && 'custom' !== $template->source ) {
 395              $changes->post_excerpt = $template->description;
 396          }
 397  
 398          return $changes;
 399      }
 400  
 401      /**
 402       * Prepare a single template output for response
 403       *
 404       * @since 5.8.0
 405       * @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support.
 406       *
 407       * @param WP_Block_Template $item    Template instance.
 408       * @param WP_REST_Request   $request Request object.
 409       * @return WP_REST_Response $data
 410       */
 411  	public function prepare_item_for_response( $item, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
 412          // Restores the more descriptive, specific name for use within this method.
 413          $template = $item;
 414          $result   = array(
 415              'id'             => $template->id,
 416              'theme'          => $template->theme,
 417              'content'        => array( 'raw' => $template->content ),
 418              'slug'           => $template->slug,
 419              'source'         => $template->source,
 420              'type'           => $template->type,
 421              'description'    => $template->description,
 422              'title'          => array(
 423                  'raw'      => $template->title,
 424                  'rendered' => $template->title,
 425              ),
 426              'status'         => $template->status,
 427              'wp_id'          => $template->wp_id,
 428              'has_theme_file' => $template->has_theme_file,
 429          );
 430  
 431          if ( 'wp_template_part' === $template->type ) {
 432              $result['area'] = $template->area;
 433          }
 434  
 435          $result = $this->add_additional_fields_to_object( $result, $request );
 436  
 437          $response = rest_ensure_response( $result );
 438          $links    = $this->prepare_links( $template->id );
 439          $response->add_links( $links );
 440          if ( ! empty( $links['self']['href'] ) ) {
 441              $actions = $this->get_available_actions();
 442              $self    = $links['self']['href'];
 443              foreach ( $actions as $rel ) {
 444                  $response->add_link( $rel, $self );
 445              }
 446          }
 447  
 448          return $response;
 449      }
 450  
 451  
 452      /**
 453       * Prepares links for the request.
 454       *
 455       * @since 5.8.0
 456       *
 457       * @param integer $id ID.
 458       * @return array Links for the given post.
 459       */
 460  	protected function prepare_links( $id ) {
 461          $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
 462  
 463          $links = array(
 464              'self'       => array(
 465                  'href' => rest_url( trailingslashit( $base ) . $id ),
 466              ),
 467              'collection' => array(
 468                  'href' => rest_url( $base ),
 469              ),
 470              'about'      => array(
 471                  'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
 472              ),
 473          );
 474  
 475          return $links;
 476      }
 477  
 478      /**
 479       * Get the link relations available for the post and current user.
 480       *
 481       * @since 5.8.0
 482       *
 483       * @return string[] List of link relations.
 484       */
 485  	protected function get_available_actions() {
 486          $rels = array();
 487  
 488          $post_type = get_post_type_object( $this->post_type );
 489  
 490          if ( current_user_can( $post_type->cap->publish_posts ) ) {
 491              $rels[] = 'https://api.w.org/action-publish';
 492          }
 493  
 494          if ( current_user_can( 'unfiltered_html' ) ) {
 495              $rels[] = 'https://api.w.org/action-unfiltered-html';
 496          }
 497  
 498          return $rels;
 499      }
 500  
 501      /**
 502       * Retrieves the query params for the posts collection.
 503       *
 504       * @since 5.8.0
 505       *
 506       * @return array Collection parameters.
 507       */
 508  	public function get_collection_params() {
 509          return array(
 510              'context' => $this->get_context_param(),
 511              'wp_id'   => array(
 512                  'description' => __( 'Limit to the specified post id.' ),
 513                  'type'        => 'integer',
 514              ),
 515          );
 516      }
 517  
 518      /**
 519       * Retrieves the block type' schema, conforming to JSON Schema.
 520       *
 521       * @since 5.8.0
 522       *
 523       * @return array Item schema data.
 524       */
 525  	public function get_item_schema() {
 526          if ( $this->schema ) {
 527              return $this->add_additional_fields_schema( $this->schema );
 528          }
 529  
 530          $schema = array(
 531              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 532              'title'      => $this->post_type,
 533              'type'       => 'object',
 534              'properties' => array(
 535                  'id'             => array(
 536                      'description' => __( 'ID of template.' ),
 537                      'type'        => 'string',
 538                      'context'     => array( 'embed', 'view', 'edit' ),
 539                      'readonly'    => true,
 540                  ),
 541                  'slug'           => array(
 542                      'description' => __( 'Unique slug identifying the template.' ),
 543                      'type'        => 'string',
 544                      'context'     => array( 'embed', 'view', 'edit' ),
 545                      'required'    => true,
 546                      'minLength'   => 1,
 547                      'pattern'     => '[a-zA-Z_\-]+',
 548                  ),
 549                  'theme'          => array(
 550                      'description' => __( 'Theme identifier for the template.' ),
 551                      'type'        => 'string',
 552                      'context'     => array( 'embed', 'view', 'edit' ),
 553                  ),
 554                  'source'         => array(
 555                      'description' => __( 'Source of template' ),
 556                      'type'        => 'string',
 557                      'context'     => array( 'embed', 'view', 'edit' ),
 558                      'readonly'    => true,
 559                  ),
 560                  'content'        => array(
 561                      'description' => __( 'Content of template.' ),
 562                      'type'        => array( 'object', 'string' ),
 563                      'default'     => '',
 564                      'context'     => array( 'embed', 'view', 'edit' ),
 565                  ),
 566                  'title'          => array(
 567                      'description' => __( 'Title of template.' ),
 568                      'type'        => array( 'object', 'string' ),
 569                      'default'     => '',
 570                      'context'     => array( 'embed', 'view', 'edit' ),
 571                  ),
 572                  'description'    => array(
 573                      'description' => __( 'Description of template.' ),
 574                      'type'        => 'string',
 575                      'default'     => '',
 576                      'context'     => array( 'embed', 'view', 'edit' ),
 577                  ),
 578                  'status'         => array(
 579                      'description' => __( 'Status of template.' ),
 580                      'type'        => 'string',
 581                      'default'     => 'publish',
 582                      'context'     => array( 'embed', 'view', 'edit' ),
 583                  ),
 584                  'wp_id'          => array(
 585                      'description' => __( 'Post ID.' ),
 586                      'type'        => 'integer',
 587                      'context'     => array( 'embed', 'view', 'edit' ),
 588                      'readonly'    => true,
 589                  ),
 590                  'has_theme_file' => array(
 591                      'description' => __( 'Theme file exists.' ),
 592                      'type'        => 'bool',
 593                      'context'     => array( 'embed', 'view', 'edit' ),
 594                      'readonly'    => true,
 595                  ),
 596              ),
 597          );
 598  
 599          $this->schema = $schema;
 600  
 601          return $this->add_additional_fields_schema( $this->schema );
 602      }
 603  }


Generated: Sun Oct 17 01:00:03 2021 Cross-referenced by PHPXref 0.7.1