wp/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php
changeset 21 48c4eec2b7e6
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
       
     1 <?php
       
     2 /**
       
     3  * REST API: WP_REST_Template_Revisions_Controller class
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage REST_API
       
     7  * @since 6.4.0
       
     8  */
       
     9 
       
    10 /**
       
    11  * Core class used to access template revisions via the REST API.
       
    12  *
       
    13  * @since 6.4.0
       
    14  *
       
    15  * @see WP_REST_Controller
       
    16  */
       
    17 class WP_REST_Template_Revisions_Controller extends WP_REST_Revisions_Controller {
       
    18 	/**
       
    19 	 * Parent post type.
       
    20 	 *
       
    21 	 * @since 6.4.0
       
    22 	 * @var string
       
    23 	 */
       
    24 	private $parent_post_type;
       
    25 
       
    26 	/**
       
    27 	 * Parent controller.
       
    28 	 *
       
    29 	 * @since 6.4.0
       
    30 	 * @var WP_REST_Controller
       
    31 	 */
       
    32 	private $parent_controller;
       
    33 
       
    34 	/**
       
    35 	 * The base of the parent controller's route.
       
    36 	 *
       
    37 	 * @since 6.4.0
       
    38 	 * @var string
       
    39 	 */
       
    40 	private $parent_base;
       
    41 
       
    42 	/**
       
    43 	 * Constructor.
       
    44 	 *
       
    45 	 * @since 6.4.0
       
    46 	 *
       
    47 	 * @param string $parent_post_type Post type of the parent.
       
    48 	 */
       
    49 	public function __construct( $parent_post_type ) {
       
    50 		parent::__construct( $parent_post_type );
       
    51 		$this->parent_post_type = $parent_post_type;
       
    52 		$post_type_object       = get_post_type_object( $parent_post_type );
       
    53 		$parent_controller      = $post_type_object->get_rest_controller();
       
    54 
       
    55 		if ( ! $parent_controller ) {
       
    56 			$parent_controller = new WP_REST_Templates_Controller( $parent_post_type );
       
    57 		}
       
    58 
       
    59 		$this->parent_controller = $parent_controller;
       
    60 		$this->rest_base         = 'revisions';
       
    61 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
       
    62 		$this->namespace         = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
       
    63 	}
       
    64 
       
    65 	/**
       
    66 	 * Registers the routes for revisions based on post types supporting revisions.
       
    67 	 *
       
    68 	 * @since 6.4.0
       
    69 	 *
       
    70 	 * @see register_rest_route()
       
    71 	 */
       
    72 	public function register_routes() {
       
    73 
       
    74 		register_rest_route(
       
    75 			$this->namespace,
       
    76 			sprintf(
       
    77 				'/%s/(?P<parent>%s%s)/%s',
       
    78 				$this->parent_base,
       
    79 				/*
       
    80 				 * Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
       
    81 				 * Excludes invalid directory name characters: `/:<>*?"|`.
       
    82 				 */
       
    83 				'([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
       
    84 				// Matches the template name.
       
    85 				'[\/\w%-]+',
       
    86 				$this->rest_base
       
    87 			),
       
    88 			array(
       
    89 				'args'   => array(
       
    90 					'parent' => array(
       
    91 						'description'       => __( 'The id of a template' ),
       
    92 						'type'              => 'string',
       
    93 						'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ),
       
    94 					),
       
    95 				),
       
    96 				array(
       
    97 					'methods'             => WP_REST_Server::READABLE,
       
    98 					'callback'            => array( $this, 'get_items' ),
       
    99 					'permission_callback' => array( $this, 'get_items_permissions_check' ),
       
   100 					'args'                => $this->get_collection_params(),
       
   101 				),
       
   102 				'schema' => array( $this, 'get_public_item_schema' ),
       
   103 			)
       
   104 		);
       
   105 
       
   106 		register_rest_route(
       
   107 			$this->namespace,
       
   108 			sprintf(
       
   109 				'/%s/(?P<parent>%s%s)/%s/%s',
       
   110 				$this->parent_base,
       
   111 				/*
       
   112 				 * Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
       
   113 				 * Excludes invalid directory name characters: `/:<>*?"|`.
       
   114 				 */
       
   115 				'([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
       
   116 				// Matches the template name.
       
   117 				'[\/\w%-]+',
       
   118 				$this->rest_base,
       
   119 				'(?P<id>[\d]+)'
       
   120 			),
       
   121 			array(
       
   122 				'args'   => array(
       
   123 					'parent' => array(
       
   124 						'description'       => __( 'The id of a template' ),
       
   125 						'type'              => 'string',
       
   126 						'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ),
       
   127 					),
       
   128 					'id'     => array(
       
   129 						'description' => __( 'Unique identifier for the revision.' ),
       
   130 						'type'        => 'integer',
       
   131 					),
       
   132 				),
       
   133 				array(
       
   134 					'methods'             => WP_REST_Server::READABLE,
       
   135 					'callback'            => array( $this, 'get_item' ),
       
   136 					'permission_callback' => array( $this, 'get_item_permissions_check' ),
       
   137 					'args'                => array(
       
   138 						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
       
   139 					),
       
   140 				),
       
   141 				array(
       
   142 					'methods'             => WP_REST_Server::DELETABLE,
       
   143 					'callback'            => array( $this, 'delete_item' ),
       
   144 					'permission_callback' => array( $this, 'delete_item_permissions_check' ),
       
   145 					'args'                => array(
       
   146 						'force' => array(
       
   147 							'type'        => 'boolean',
       
   148 							'default'     => false,
       
   149 							'description' => __( 'Required to be true, as revisions do not support trashing.' ),
       
   150 						),
       
   151 					),
       
   152 				),
       
   153 				'schema' => array( $this, 'get_public_item_schema' ),
       
   154 			)
       
   155 		);
       
   156 	}
       
   157 
       
   158 	/**
       
   159 	 * Gets the parent post, if the template ID is valid.
       
   160 	 *
       
   161 	 * @since 6.4.0
       
   162 	 *
       
   163 	 * @param string $parent_template_id Supplied ID.
       
   164 	 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
       
   165 	 */
       
   166 	protected function get_parent( $parent_template_id ) {
       
   167 		$template = get_block_template( $parent_template_id, $this->parent_post_type );
       
   168 
       
   169 		if ( ! $template ) {
       
   170 			return new WP_Error(
       
   171 				'rest_post_invalid_parent',
       
   172 				__( 'Invalid template parent ID.' ),
       
   173 				array( 'status' => 404 )
       
   174 			);
       
   175 		}
       
   176 
       
   177 		return get_post( $template->wp_id );
       
   178 	}
       
   179 
       
   180 	/**
       
   181 	 * Prepares the item for the REST response.
       
   182 	 *
       
   183 	 * @since 6.4.0
       
   184 	 *
       
   185 	 * @param WP_Post         $item    Post revision object.
       
   186 	 * @param WP_REST_Request $request Request object.
       
   187 	 * @return WP_REST_Response Response object.
       
   188 	 */
       
   189 	public function prepare_item_for_response( $item, $request ) {
       
   190 		$template = _build_block_template_result_from_post( $item );
       
   191 		$response = $this->parent_controller->prepare_item_for_response( $template, $request );
       
   192 
       
   193 		$fields = $this->get_fields_for_response( $request );
       
   194 		$data   = $response->get_data();
       
   195 
       
   196 		if ( in_array( 'parent', $fields, true ) ) {
       
   197 			$data['parent'] = (int) $item->post_parent;
       
   198 		}
       
   199 
       
   200 		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
       
   201 		$data    = $this->filter_response_by_context( $data, $context );
       
   202 
       
   203 		// Wrap the data in a response object.
       
   204 		$response = new WP_REST_Response( $data );
       
   205 
       
   206 		if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
       
   207 			$links = $this->prepare_links( $template );
       
   208 			$response->add_links( $links );
       
   209 		}
       
   210 
       
   211 		return $response;
       
   212 	}
       
   213 
       
   214 	/**
       
   215 	 * Checks if a given request has access to delete a revision.
       
   216 	 *
       
   217 	 * @since 6.4.0
       
   218 	 *
       
   219 	 * @param WP_REST_Request $request Full details about the request.
       
   220 	 * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
       
   221 	 */
       
   222 	public function delete_item_permissions_check( $request ) {
       
   223 		$parent = $this->get_parent( $request['parent'] );
       
   224 		if ( is_wp_error( $parent ) ) {
       
   225 			return $parent;
       
   226 		}
       
   227 
       
   228 		if ( ! current_user_can( 'delete_post', $parent->ID ) ) {
       
   229 			return new WP_Error(
       
   230 				'rest_cannot_delete',
       
   231 				__( 'Sorry, you are not allowed to delete revisions of this post.' ),
       
   232 				array( 'status' => rest_authorization_required_code() )
       
   233 			);
       
   234 		}
       
   235 
       
   236 		$revision = $this->get_revision( $request['id'] );
       
   237 		if ( is_wp_error( $revision ) ) {
       
   238 			return $revision;
       
   239 		}
       
   240 
       
   241 		if ( ! current_user_can( 'edit_theme_options' ) ) {
       
   242 			return new WP_Error(
       
   243 				'rest_cannot_delete',
       
   244 				__( 'Sorry, you are not allowed to delete this revision.' ),
       
   245 				array( 'status' => rest_authorization_required_code() )
       
   246 			);
       
   247 		}
       
   248 
       
   249 		return true;
       
   250 	}
       
   251 
       
   252 	/**
       
   253 	 * Prepares links for the request.
       
   254 	 *
       
   255 	 * @since 6.4.0
       
   256 	 *
       
   257 	 * @param WP_Block_Template $template Template.
       
   258 	 * @return array Links for the given post.
       
   259 	 */
       
   260 	protected function prepare_links( $template ) {
       
   261 		$links = array(
       
   262 			'self'   => array(
       
   263 				'href' => rest_url( sprintf( '/%s/%s/%s/%s/%d', $this->namespace, $this->parent_base, $template->id, $this->rest_base, $template->wp_id ) ),
       
   264 			),
       
   265 			'parent' => array(
       
   266 				'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->parent_base, $template->id ) ),
       
   267 			),
       
   268 		);
       
   269 
       
   270 		return $links;
       
   271 	}
       
   272 
       
   273 	/**
       
   274 	 * Retrieves the item's schema, conforming to JSON Schema.
       
   275 	 *
       
   276 	 * @since 6.4.0
       
   277 	 *
       
   278 	 * @return array Item schema data.
       
   279 	 */
       
   280 	public function get_item_schema() {
       
   281 		if ( $this->schema ) {
       
   282 			return $this->add_additional_fields_schema( $this->schema );
       
   283 		}
       
   284 
       
   285 		$schema = $this->parent_controller->get_item_schema();
       
   286 
       
   287 		$schema['properties']['parent'] = array(
       
   288 			'description' => __( 'The ID for the parent of the revision.' ),
       
   289 			'type'        => 'integer',
       
   290 			'context'     => array( 'view', 'edit', 'embed' ),
       
   291 		);
       
   292 
       
   293 		$this->schema = $schema;
       
   294 
       
   295 		return $this->add_additional_fields_schema( $this->schema );
       
   296 	}
       
   297 }