[ 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       *
 406       * @param WP_Block_Template $template Template instance.
 407       * @param WP_REST_Request   $request Request object.
 408       * @return WP_REST_Response $data
 409       */
 410  	public function prepare_item_for_response( $template, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
 411          $result = array(
 412              'id'             => $template->id,
 413              'theme'          => $template->theme,
 414              'content'        => array( 'raw' => $template->content ),
 415              'slug'           => $template->slug,
 416              'source'         => $template->source,
 417              'type'           => $template->type,
 418              'description'    => $template->description,
 419              'title'          => array(
 420                  'raw'      => $template->title,
 421                  'rendered' => $template->title,
 422              ),
 423              'status'         => $template->status,
 424              'wp_id'          => $template->wp_id,
 425              'has_theme_file' => $template->has_theme_file,
 426          );
 427  
 428          if ( 'wp_template_part' === $template->type ) {
 429              $result['area'] = $template->area;
 430          }
 431  
 432          $result = $this->add_additional_fields_to_object( $result, $request );
 433  
 434          $response = rest_ensure_response( $result );
 435          $links    = $this->prepare_links( $template->id );
 436          $response->add_links( $links );
 437          if ( ! empty( $links['self']['href'] ) ) {
 438              $actions = $this->get_available_actions();
 439              $self    = $links['self']['href'];
 440              foreach ( $actions as $rel ) {
 441                  $response->add_link( $rel, $self );
 442              }
 443          }
 444  
 445          return $response;
 446      }
 447  
 448  
 449      /**
 450       * Prepares links for the request.
 451       *
 452       * @since 5.8.0
 453       *
 454       * @param integer $id ID.
 455       * @return array Links for the given post.
 456       */
 457  	protected function prepare_links( $id ) {
 458          $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
 459  
 460          $links = array(
 461              'self'       => array(
 462                  'href' => rest_url( trailingslashit( $base ) . $id ),
 463              ),
 464              'collection' => array(
 465                  'href' => rest_url( $base ),
 466              ),
 467              'about'      => array(
 468                  'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
 469              ),
 470          );
 471  
 472          return $links;
 473      }
 474  
 475      /**
 476       * Get the link relations available for the post and current user.
 477       *
 478       * @since 5.8.0
 479       *
 480       * @return string[] List of link relations.
 481       */
 482  	protected function get_available_actions() {
 483          $rels = array();
 484  
 485          $post_type = get_post_type_object( $this->post_type );
 486  
 487          if ( current_user_can( $post_type->cap->publish_posts ) ) {
 488              $rels[] = 'https://api.w.org/action-publish';
 489          }
 490  
 491          if ( current_user_can( 'unfiltered_html' ) ) {
 492              $rels[] = 'https://api.w.org/action-unfiltered-html';
 493          }
 494  
 495          return $rels;
 496      }
 497  
 498      /**
 499       * Retrieves the query params for the posts collection.
 500       *
 501       * @since 5.8.0
 502       *
 503       * @return array Collection parameters.
 504       */
 505  	public function get_collection_params() {
 506          return array(
 507              'context' => $this->get_context_param(),
 508              'wp_id'   => array(
 509                  'description' => __( 'Limit to the specified post id.' ),
 510                  'type'        => 'integer',
 511              ),
 512          );
 513      }
 514  
 515      /**
 516       * Retrieves the block type' schema, conforming to JSON Schema.
 517       *
 518       * @since 5.8.0
 519       *
 520       * @return array Item schema data.
 521       */
 522  	public function get_item_schema() {
 523          if ( $this->schema ) {
 524              return $this->add_additional_fields_schema( $this->schema );
 525          }
 526  
 527          $schema = array(
 528              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 529              'title'      => $this->post_type,
 530              'type'       => 'object',
 531              'properties' => array(
 532                  'id'             => array(
 533                      'description' => __( 'ID of template.' ),
 534                      'type'        => 'string',
 535                      'context'     => array( 'embed', 'view', 'edit' ),
 536                      'readonly'    => true,
 537                  ),
 538                  'slug'           => array(
 539                      'description' => __( 'Unique slug identifying the template.' ),
 540                      'type'        => 'string',
 541                      'context'     => array( 'embed', 'view', 'edit' ),
 542                      'required'    => true,
 543                      'minLength'   => 1,
 544                      'pattern'     => '[a-zA-Z_\-]+',
 545                  ),
 546                  'theme'          => array(
 547                      'description' => __( 'Theme identifier for the template.' ),
 548                      'type'        => 'string',
 549                      'context'     => array( 'embed', 'view', 'edit' ),
 550                  ),
 551                  'source'         => array(
 552                      'description' => __( 'Source of template' ),
 553                      'type'        => 'string',
 554                      'context'     => array( 'embed', 'view', 'edit' ),
 555                      'readonly'    => true,
 556                  ),
 557                  'content'        => array(
 558                      'description' => __( 'Content of template.' ),
 559                      'type'        => array( 'object', 'string' ),
 560                      'default'     => '',
 561                      'context'     => array( 'embed', 'view', 'edit' ),
 562                  ),
 563                  'title'          => array(
 564                      'description' => __( 'Title of template.' ),
 565                      'type'        => array( 'object', 'string' ),
 566                      'default'     => '',
 567                      'context'     => array( 'embed', 'view', 'edit' ),
 568                  ),
 569                  'description'    => array(
 570                      'description' => __( 'Description of template.' ),
 571                      'type'        => 'string',
 572                      'default'     => '',
 573                      'context'     => array( 'embed', 'view', 'edit' ),
 574                  ),
 575                  'status'         => array(
 576                      'description' => __( 'Status of template.' ),
 577                      'type'        => 'string',
 578                      'default'     => 'publish',
 579                      'context'     => array( 'embed', 'view', 'edit' ),
 580                  ),
 581                  'wp_id'          => array(
 582                      'description' => __( 'Post ID.' ),
 583                      'type'        => 'integer',
 584                      'context'     => array( 'embed', 'view', 'edit' ),
 585                      'readonly'    => true,
 586                  ),
 587                  'has_theme_file' => array(
 588                      'description' => __( 'Theme file exists.' ),
 589                      'type'        => 'bool',
 590                      'context'     => array( 'embed', 'view', 'edit' ),
 591                      'readonly'    => true,
 592                  ),
 593              ),
 594          );
 595  
 596          $this->schema = $schema;
 597  
 598          return $this->add_additional_fields_schema( $this->schema );
 599      }
 600  }


Generated: Sun Aug 1 01:00:05 2021 Cross-referenced by PHPXref 0.7.1