wp/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    47 	 *
    47 	 *
    48 	 * @param string $parent_post_type Post type of the parent.
    48 	 * @param string $parent_post_type Post type of the parent.
    49 	 */
    49 	 */
    50 	public function __construct( $parent_post_type ) {
    50 	public function __construct( $parent_post_type ) {
    51 		$this->parent_post_type  = $parent_post_type;
    51 		$this->parent_post_type  = $parent_post_type;
    52 		$this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
       
    53 		$this->namespace         = 'wp/v2';
    52 		$this->namespace         = 'wp/v2';
    54 		$this->rest_base         = 'revisions';
    53 		$this->rest_base         = 'revisions';
    55 		$post_type_object        = get_post_type_object( $parent_post_type );
    54 		$post_type_object        = get_post_type_object( $parent_post_type );
    56 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
    55 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
    57 	}
    56 		$this->parent_controller = $post_type_object->get_rest_controller();
    58 
    57 
    59 	/**
    58 		if ( ! $this->parent_controller ) {
    60 	 * Registers routes for revisions based on post types supporting revisions.
    59 			$this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
       
    60 		}
       
    61 	}
       
    62 
       
    63 	/**
       
    64 	 * Registers the routes for revisions based on post types supporting revisions.
    61 	 *
    65 	 *
    62 	 * @since 4.7.0
    66 	 * @since 4.7.0
    63 	 *
    67 	 *
    64 	 * @see register_rest_route()
    68 	 * @see register_rest_route()
    65 	 */
    69 	 */
   128 	/**
   132 	/**
   129 	 * Get the parent post, if the ID is valid.
   133 	 * Get the parent post, if the ID is valid.
   130 	 *
   134 	 *
   131 	 * @since 4.7.2
   135 	 * @since 4.7.2
   132 	 *
   136 	 *
   133 	 * @param int $id Supplied ID.
   137 	 * @param int $parent Supplied ID.
   134 	 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
   138 	 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
   135 	 */
   139 	 */
   136 	protected function get_parent( $parent ) {
   140 	protected function get_parent( $parent ) {
   137 		$error = new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent ID.' ), array( 'status' => 404 ) );
   141 		$error = new WP_Error(
       
   142 			'rest_post_invalid_parent',
       
   143 			__( 'Invalid post parent ID.' ),
       
   144 			array( 'status' => 404 )
       
   145 		);
   138 		if ( (int) $parent <= 0 ) {
   146 		if ( (int) $parent <= 0 ) {
   139 			return $error;
   147 			return $error;
   140 		}
   148 		}
   141 
   149 
   142 		$parent = get_post( (int) $parent );
   150 		$parent = get_post( (int) $parent );
   150 	/**
   158 	/**
   151 	 * Checks if a given request has access to get revisions.
   159 	 * Checks if a given request has access to get revisions.
   152 	 *
   160 	 *
   153 	 * @since 4.7.0
   161 	 * @since 4.7.0
   154 	 *
   162 	 *
   155 	 * @param WP_REST_Request $request Full data about the request.
   163 	 * @param WP_REST_Request $request Full details about the request.
   156 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
   164 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
   157 	 */
   165 	 */
   158 	public function get_items_permissions_check( $request ) {
   166 	public function get_items_permissions_check( $request ) {
   159 		$parent = $this->get_parent( $request['parent'] );
   167 		$parent = $this->get_parent( $request['parent'] );
   160 		if ( is_wp_error( $parent ) ) {
   168 		if ( is_wp_error( $parent ) ) {
   161 			return $parent;
   169 			return $parent;
   162 		}
   170 		}
   163 
   171 
   164 		$parent_post_type_obj = get_post_type_object( $parent->post_type );
   172 		if ( ! current_user_can( 'edit_post', $parent->ID ) ) {
   165 		if ( ! current_user_can( $parent_post_type_obj->cap->edit_post, $parent->ID ) ) {
   173 			return new WP_Error(
   166 			return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to view revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) );
   174 				'rest_cannot_read',
       
   175 				__( 'Sorry, you are not allowed to view revisions of this post.' ),
       
   176 				array( 'status' => rest_authorization_required_code() )
       
   177 			);
   167 		}
   178 		}
   168 
   179 
   169 		return true;
   180 		return true;
   170 	}
   181 	}
   171 
   182 
   176 	 *
   187 	 *
   177 	 * @param int $id Supplied ID.
   188 	 * @param int $id Supplied ID.
   178 	 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise.
   189 	 * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise.
   179 	 */
   190 	 */
   180 	protected function get_revision( $id ) {
   191 	protected function get_revision( $id ) {
   181 		$error = new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision ID.' ), array( 'status' => 404 ) );
   192 		$error = new WP_Error(
       
   193 			'rest_post_invalid_id',
       
   194 			__( 'Invalid revision ID.' ),
       
   195 			array( 'status' => 404 )
       
   196 		);
       
   197 
   182 		if ( (int) $id <= 0 ) {
   198 		if ( (int) $id <= 0 ) {
   183 			return $error;
   199 			return $error;
   184 		}
   200 		}
   185 
   201 
   186 		$revision = get_post( (int) $id );
   202 		$revision = get_post( (int) $id );
   194 	/**
   210 	/**
   195 	 * Gets a collection of revisions.
   211 	 * Gets a collection of revisions.
   196 	 *
   212 	 *
   197 	 * @since 4.7.0
   213 	 * @since 4.7.0
   198 	 *
   214 	 *
   199 	 * @param WP_REST_Request $request Full data about the request.
   215 	 * @param WP_REST_Request $request Full details about the request.
   200 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   216 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   201 	 */
   217 	 */
   202 	public function get_items( $request ) {
   218 	public function get_items( $request ) {
   203 		$parent = $this->get_parent( $request['parent'] );
   219 		$parent = $this->get_parent( $request['parent'] );
   204 		if ( is_wp_error( $parent ) ) {
   220 		if ( is_wp_error( $parent ) ) {
   205 			return $parent;
   221 			return $parent;
   206 		}
   222 		}
   207 
   223 
   208 		// Ensure a search string is set in case the orderby is set to 'relevance'.
   224 		// Ensure a search string is set in case the orderby is set to 'relevance'.
   209 		if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) {
   225 		if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) {
   210 			return new WP_Error( 'rest_no_search_term_defined', __( 'You need to define a search term to order by relevance.' ), array( 'status' => 400 ) );
   226 			return new WP_Error(
       
   227 				'rest_no_search_term_defined',
       
   228 				__( 'You need to define a search term to order by relevance.' ),
       
   229 				array( 'status' => 400 )
       
   230 			);
   211 		}
   231 		}
   212 
   232 
   213 		// Ensure an include parameter is set in case the orderby is set to 'include'.
   233 		// Ensure an include parameter is set in case the orderby is set to 'include'.
   214 		if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) {
   234 		if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) {
   215 			return new WP_Error( 'rest_orderby_include_missing_include', __( 'You need to define an include parameter to order by include.' ), array( 'status' => 400 ) );
   235 			return new WP_Error(
       
   236 				'rest_orderby_include_missing_include',
       
   237 				__( 'You need to define an include parameter to order by include.' ),
       
   238 				array( 'status' => 400 )
       
   239 			);
   216 		}
   240 		}
   217 
   241 
   218 		if ( wp_revisions_enabled( $parent ) ) {
   242 		if ( wp_revisions_enabled( $parent ) ) {
   219 			$registered = $this->get_collection_params();
   243 			$registered = $this->get_collection_params();
   220 			$args       = array(
   244 			$args       = array(
   275 				$max_pages = $total_revisions > 0 ? 1 : 0;
   299 				$max_pages = $total_revisions > 0 ? 1 : 0;
   276 			}
   300 			}
   277 
   301 
   278 			if ( $total_revisions > 0 ) {
   302 			if ( $total_revisions > 0 ) {
   279 				if ( $offset >= $total_revisions ) {
   303 				if ( $offset >= $total_revisions ) {
   280 					return new WP_Error( 'rest_revision_invalid_offset_number', __( 'The offset number requested is larger than or equal to the number of available revisions.' ), array( 'status' => 400 ) );
   304 					return new WP_Error(
       
   305 						'rest_revision_invalid_offset_number',
       
   306 						__( 'The offset number requested is larger than or equal to the number of available revisions.' ),
       
   307 						array( 'status' => 400 )
       
   308 					);
   281 				} elseif ( ! $offset && $page > $max_pages ) {
   309 				} elseif ( ! $offset && $page > $max_pages ) {
   282 					return new WP_Error( 'rest_revision_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) );
   310 					return new WP_Error(
       
   311 						'rest_revision_invalid_page_number',
       
   312 						__( 'The page number requested is larger than the number of pages available.' ),
       
   313 						array( 'status' => 400 )
       
   314 					);
   283 				}
   315 				}
   284 			}
   316 			}
   285 		} else {
   317 		} else {
   286 			$revisions       = array();
   318 			$revisions       = array();
   287 			$total_revisions = 0;
   319 			$total_revisions = 0;
   288 			$max_pages       = 0;
   320 			$max_pages       = 0;
   289 			$page            = (int) $request['page'];
   321 			$page            = (int) $request['page'];
   290 		}
   322 		}
   291 
   323 
   292 		$response = array();
   324 		$response = array();
       
   325 
   293 		foreach ( $revisions as $revision ) {
   326 		foreach ( $revisions as $revision ) {
   294 			$data       = $this->prepare_item_for_response( $revision, $request );
   327 			$data       = $this->prepare_item_for_response( $revision, $request );
   295 			$response[] = $this->prepare_response_for_collection( $data );
   328 			$response[] = $this->prepare_response_for_collection( $data );
   296 		}
   329 		}
   297 
   330 
   326 	/**
   359 	/**
   327 	 * Checks if a given request has access to get a specific revision.
   360 	 * Checks if a given request has access to get a specific revision.
   328 	 *
   361 	 *
   329 	 * @since 4.7.0
   362 	 * @since 4.7.0
   330 	 *
   363 	 *
   331 	 * @param WP_REST_Request $request Full data about the request.
   364 	 * @param WP_REST_Request $request Full details about the request.
   332 	 * @return bool|WP_Error True if the request has read access for the item, WP_Error object otherwise.
   365 	 * @return bool|WP_Error True if the request has read access for the item, WP_Error object otherwise.
   333 	 */
   366 	 */
   334 	public function get_item_permissions_check( $request ) {
   367 	public function get_item_permissions_check( $request ) {
   335 		return $this->get_items_permissions_check( $request );
   368 		return $this->get_items_permissions_check( $request );
   336 	}
   369 	}
   338 	/**
   371 	/**
   339 	 * Retrieves one revision from the collection.
   372 	 * Retrieves one revision from the collection.
   340 	 *
   373 	 *
   341 	 * @since 4.7.0
   374 	 * @since 4.7.0
   342 	 *
   375 	 *
   343 	 * @param WP_REST_Request $request Full data about the request.
   376 	 * @param WP_REST_Request $request Full details about the request.
   344 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   377 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   345 	 */
   378 	 */
   346 	public function get_item( $request ) {
   379 	public function get_item( $request ) {
   347 		$parent = $this->get_parent( $request['parent'] );
   380 		$parent = $this->get_parent( $request['parent'] );
   348 		if ( is_wp_error( $parent ) ) {
   381 		if ( is_wp_error( $parent ) ) {
   361 	/**
   394 	/**
   362 	 * Checks if a given request has access to delete a revision.
   395 	 * Checks if a given request has access to delete a revision.
   363 	 *
   396 	 *
   364 	 * @since 4.7.0
   397 	 * @since 4.7.0
   365 	 *
   398 	 *
   366 	 * @param  WP_REST_Request $request Full details about the request.
   399 	 * @param WP_REST_Request $request Full details about the request.
   367 	 * @return bool|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
   400 	 * @return bool|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
   368 	 */
   401 	 */
   369 	public function delete_item_permissions_check( $request ) {
   402 	public function delete_item_permissions_check( $request ) {
   370 		$parent = $this->get_parent( $request['parent'] );
   403 		$parent = $this->get_parent( $request['parent'] );
   371 		if ( is_wp_error( $parent ) ) {
   404 		if ( is_wp_error( $parent ) ) {
   372 			return $parent;
   405 			return $parent;
   373 		}
   406 		}
   374 
   407 
       
   408 		$parent_post_type = get_post_type_object( $parent->post_type );
       
   409 
       
   410 		if ( ! current_user_can( 'delete_post', $parent->ID ) ) {
       
   411 			return new WP_Error(
       
   412 				'rest_cannot_delete',
       
   413 				__( 'Sorry, you are not allowed to delete revisions of this post.' ),
       
   414 				array( 'status' => rest_authorization_required_code() )
       
   415 			);
       
   416 		}
       
   417 
   375 		$revision = $this->get_revision( $request['id'] );
   418 		$revision = $this->get_revision( $request['id'] );
   376 		if ( is_wp_error( $revision ) ) {
   419 		if ( is_wp_error( $revision ) ) {
   377 			return $revision;
   420 			return $revision;
   378 		}
   421 		}
   379 
   422 
   380 		$response = $this->get_items_permissions_check( $request );
   423 		$response = $this->get_items_permissions_check( $request );
   381 		if ( ! $response || is_wp_error( $response ) ) {
   424 		if ( ! $response || is_wp_error( $response ) ) {
   382 			return $response;
   425 			return $response;
   383 		}
   426 		}
   384 
   427 
   385 		$post_type = get_post_type_object( 'revision' );
   428 		if ( ! current_user_can( 'delete_post', $revision->ID ) ) {
   386 		return current_user_can( $post_type->cap->delete_post, $revision->ID );
   429 			return new WP_Error(
       
   430 				'rest_cannot_delete',
       
   431 				__( 'Sorry, you are not allowed to delete this revision.' ),
       
   432 				array( 'status' => rest_authorization_required_code() )
       
   433 			);
       
   434 		}
       
   435 
       
   436 		return true;
   387 	}
   437 	}
   388 
   438 
   389 	/**
   439 	/**
   390 	 * Deletes a single revision.
   440 	 * Deletes a single revision.
   391 	 *
   441 	 *
   392 	 * @since 4.7.0
   442 	 * @since 4.7.0
   393 	 *
   443 	 *
   394 	 * @param WP_REST_Request $request Full details about the request.
   444 	 * @param WP_REST_Request $request Full details about the request.
   395 	 * @return true|WP_Error True on success, or WP_Error object on failure.
   445 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   396 	 */
   446 	 */
   397 	public function delete_item( $request ) {
   447 	public function delete_item( $request ) {
   398 		$revision = $this->get_revision( $request['id'] );
   448 		$revision = $this->get_revision( $request['id'] );
   399 		if ( is_wp_error( $revision ) ) {
   449 		if ( is_wp_error( $revision ) ) {
   400 			return $revision;
   450 			return $revision;
   402 
   452 
   403 		$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
   453 		$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
   404 
   454 
   405 		// We don't support trashing for revisions.
   455 		// We don't support trashing for revisions.
   406 		if ( ! $force ) {
   456 		if ( ! $force ) {
   407 			/* translators: %s: force=true */
   457 			return new WP_Error(
   408 			return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) );
   458 				'rest_trash_not_supported',
       
   459 				/* translators: %s: force=true */
       
   460 				sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ),
       
   461 				array( 'status' => 501 )
       
   462 			);
   409 		}
   463 		}
   410 
   464 
   411 		$previous = $this->prepare_item_for_response( $revision, $request );
   465 		$previous = $this->prepare_item_for_response( $revision, $request );
   412 
   466 
   413 		$result = wp_delete_post( $request['id'], true );
   467 		$result = wp_delete_post( $request['id'], true );
   415 		/**
   469 		/**
   416 		 * Fires after a revision is deleted via the REST API.
   470 		 * Fires after a revision is deleted via the REST API.
   417 		 *
   471 		 *
   418 		 * @since 4.7.0
   472 		 * @since 4.7.0
   419 		 *
   473 		 *
   420 		 * @param (mixed) $result The revision object (if it was deleted or moved to the trash successfully)
   474 		 * @param WP_Post|false|null $result The revision object (if it was deleted or moved to the Trash successfully)
   421 		 *                        or false (failure). If the revision was moved to the trash, $result represents
   475 		 *                                   or false or null (failure). If the revision was moved to the Trash, $result represents
   422 		 *                        its new state; if it was deleted, $result represents its state before deletion.
   476 		 *                                   its new state; if it was deleted, $result represents its state before deletion.
   423 		 * @param WP_REST_Request $request The request sent to the API.
   477 		 * @param WP_REST_Request $request The request sent to the API.
   424 		 */
   478 		 */
   425 		do_action( 'rest_delete_revision', $result, $request );
   479 		do_action( 'rest_delete_revision', $result, $request );
   426 
   480 
   427 		if ( ! $result ) {
   481 		if ( ! $result ) {
   428 			return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) );
   482 			return new WP_Error(
       
   483 				'rest_cannot_delete',
       
   484 				__( 'The post cannot be deleted.' ),
       
   485 				array( 'status' => 500 )
       
   486 			);
   429 		}
   487 		}
   430 
   488 
   431 		$response = new WP_REST_Response();
   489 		$response = new WP_REST_Response();
   432 		$response->set_data(
   490 		$response->set_data(
   433 			array(
   491 			array(
   604 	 * @since 4.7.0
   662 	 * @since 4.7.0
   605 	 *
   663 	 *
   606 	 * @return array Item schema data.
   664 	 * @return array Item schema data.
   607 	 */
   665 	 */
   608 	public function get_item_schema() {
   666 	public function get_item_schema() {
       
   667 		if ( $this->schema ) {
       
   668 			return $this->add_additional_fields_schema( $this->schema );
       
   669 		}
       
   670 
   609 		$schema = array(
   671 		$schema = array(
   610 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
   672 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
   611 			'title'      => "{$this->parent_post_type}-revision",
   673 			'title'      => "{$this->parent_post_type}-revision",
   612 			'type'       => 'object',
   674 			'type'       => 'object',
   613 			// Base properties for every Revision.
   675 			// Base properties for every Revision.
   680 
   742 
   681 		if ( ! empty( $parent_schema['properties']['guid'] ) ) {
   743 		if ( ! empty( $parent_schema['properties']['guid'] ) ) {
   682 			$schema['properties']['guid'] = $parent_schema['properties']['guid'];
   744 			$schema['properties']['guid'] = $parent_schema['properties']['guid'];
   683 		}
   745 		}
   684 
   746 
   685 		return $this->add_additional_fields_schema( $schema );
   747 		$this->schema = $schema;
       
   748 
       
   749 		return $this->add_additional_fields_schema( $this->schema );
   686 	}
   750 	}
   687 
   751 
   688 	/**
   752 	/**
   689 	 * Retrieves the query params for collections.
   753 	 * Retrieves the query params for collections.
   690 	 *
   754 	 *