wp/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    23 	 * @var string
    23 	 * @var string
    24 	 */
    24 	 */
    25 	private $parent_post_type;
    25 	private $parent_post_type;
    26 
    26 
    27 	/**
    27 	/**
       
    28 	 * Instance of a revision meta fields object.
       
    29 	 *
       
    30 	 * @since 6.4.0
       
    31 	 * @var WP_REST_Post_Meta_Fields
       
    32 	 */
       
    33 	protected $meta;
       
    34 
       
    35 	/**
    28 	 * Parent controller.
    36 	 * Parent controller.
    29 	 *
    37 	 *
    30 	 * @since 4.7.0
    38 	 * @since 4.7.0
    31 	 * @var WP_REST_Controller
    39 	 * @var WP_REST_Controller
    32 	 */
    40 	 */
    46 	 * @since 4.7.0
    54 	 * @since 4.7.0
    47 	 *
    55 	 *
    48 	 * @param string $parent_post_type Post type of the parent.
    56 	 * @param string $parent_post_type Post type of the parent.
    49 	 */
    57 	 */
    50 	public function __construct( $parent_post_type ) {
    58 	public function __construct( $parent_post_type ) {
    51 		$this->parent_post_type  = $parent_post_type;
    59 		$this->parent_post_type = $parent_post_type;
       
    60 		$post_type_object       = get_post_type_object( $parent_post_type );
       
    61 		$parent_controller      = $post_type_object->get_rest_controller();
       
    62 
       
    63 		if ( ! $parent_controller ) {
       
    64 			$parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
       
    65 		}
       
    66 
       
    67 		$this->parent_controller = $parent_controller;
    52 		$this->rest_base         = 'revisions';
    68 		$this->rest_base         = 'revisions';
    53 		$post_type_object        = get_post_type_object( $parent_post_type );
       
    54 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
    69 		$this->parent_base       = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
    55 		$this->namespace         = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
    70 		$this->namespace         = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
    56 		$this->parent_controller = $post_type_object->get_rest_controller();
    71 		$this->meta              = new WP_REST_Post_Meta_Fields( $parent_post_type );
    57 
       
    58 		if ( ! $this->parent_controller ) {
       
    59 			$this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
       
    60 		}
       
    61 	}
    72 	}
    62 
    73 
    63 	/**
    74 	/**
    64 	 * Registers the routes for revisions based on post types supporting revisions.
    75 	 * Registers the routes for revisions based on post types supporting revisions.
    65 	 *
    76 	 *
   124 					),
   135 					),
   125 				),
   136 				),
   126 				'schema' => array( $this, 'get_public_item_schema' ),
   137 				'schema' => array( $this, 'get_public_item_schema' ),
   127 			)
   138 			)
   128 		);
   139 		);
   129 
       
   130 	}
   140 	}
   131 
   141 
   132 	/**
   142 	/**
   133 	 * Get the parent post, if the ID is valid.
   143 	 * Get the parent post, if the ID is valid.
   134 	 *
   144 	 *
   135 	 * @since 4.7.2
   145 	 * @since 4.7.2
   136 	 *
   146 	 *
   137 	 * @param int $parent Supplied ID.
   147 	 * @param int $parent_post_id Supplied ID.
   138 	 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
   148 	 * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
   139 	 */
   149 	 */
   140 	protected function get_parent( $parent ) {
   150 	protected function get_parent( $parent_post_id ) {
   141 		$error = new WP_Error(
   151 		$error = new WP_Error(
   142 			'rest_post_invalid_parent',
   152 			'rest_post_invalid_parent',
   143 			__( 'Invalid post parent ID.' ),
   153 			__( 'Invalid post parent ID.' ),
   144 			array( 'status' => 404 )
   154 			array( 'status' => 404 )
   145 		);
   155 		);
   146 		if ( (int) $parent <= 0 ) {
   156 
       
   157 		if ( (int) $parent_post_id <= 0 ) {
   147 			return $error;
   158 			return $error;
   148 		}
   159 		}
   149 
   160 
   150 		$parent = get_post( (int) $parent );
   161 		$parent_post = get_post( (int) $parent_post_id );
   151 		if ( empty( $parent ) || empty( $parent->ID ) || $this->parent_post_type !== $parent->post_type ) {
   162 
       
   163 		if ( empty( $parent_post ) || empty( $parent_post->ID )
       
   164 			|| $this->parent_post_type !== $parent_post->post_type
       
   165 		) {
   152 			return $error;
   166 			return $error;
   153 		}
   167 		}
   154 
   168 
   155 		return $parent;
   169 		return $parent_post;
   156 	}
   170 	}
   157 
   171 
   158 	/**
   172 	/**
   159 	 * Checks if a given request has access to get revisions.
   173 	 * Checks if a given request has access to get revisions.
   160 	 *
   174 	 *
   292 
   306 
   293 				$total_revisions = $count_query->found_posts;
   307 				$total_revisions = $count_query->found_posts;
   294 			}
   308 			}
   295 
   309 
   296 			if ( $revisions_query->query_vars['posts_per_page'] > 0 ) {
   310 			if ( $revisions_query->query_vars['posts_per_page'] > 0 ) {
   297 				$max_pages = ceil( $total_revisions / (int) $revisions_query->query_vars['posts_per_page'] );
   311 				$max_pages = (int) ceil( $total_revisions / (int) $revisions_query->query_vars['posts_per_page'] );
   298 			} else {
   312 			} else {
   299 				$max_pages = $total_revisions > 0 ? 1 : 0;
   313 				$max_pages = $total_revisions > 0 ? 1 : 0;
   300 			}
   314 			}
   301 
   315 
   302 			if ( $total_revisions > 0 ) {
   316 			if ( $total_revisions > 0 ) {
   332 
   346 
   333 		$response->header( 'X-WP-Total', (int) $total_revisions );
   347 		$response->header( 'X-WP-Total', (int) $total_revisions );
   334 		$response->header( 'X-WP-TotalPages', (int) $max_pages );
   348 		$response->header( 'X-WP-TotalPages', (int) $max_pages );
   335 
   349 
   336 		$request_params = $request->get_query_params();
   350 		$request_params = $request->get_query_params();
   337 		$base           = add_query_arg( urlencode_deep( $request_params ), rest_url( sprintf( '%s/%s/%d/%s', $this->namespace, $this->parent_base, $request['parent'], $this->rest_base ) ) );
   351 		$base_path      = rest_url( sprintf( '%s/%s/%d/%s', $this->namespace, $this->parent_base, $request['parent'], $this->rest_base ) );
       
   352 		$base           = add_query_arg( urlencode_deep( $request_params ), $base_path );
   338 
   353 
   339 		if ( $page > 1 ) {
   354 		if ( $page > 1 ) {
   340 			$prev_page = $page - 1;
   355 			$prev_page = $page - 1;
   341 
   356 
   342 			if ( $prev_page > $max_pages ) {
   357 			if ( $prev_page > $max_pages ) {
   370 
   385 
   371 	/**
   386 	/**
   372 	 * Retrieves one revision from the collection.
   387 	 * Retrieves one revision from the collection.
   373 	 *
   388 	 *
   374 	 * @since 4.7.0
   389 	 * @since 4.7.0
       
   390 	 * @since 6.5.0 Added a condition to check that parent id matches revision parent id.
   375 	 *
   391 	 *
   376 	 * @param WP_REST_Request $request Full details about the request.
   392 	 * @param WP_REST_Request $request Full details about the request.
   377 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   393 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   378 	 */
   394 	 */
   379 	public function get_item( $request ) {
   395 	public function get_item( $request ) {
   385 		$revision = $this->get_revision( $request['id'] );
   401 		$revision = $this->get_revision( $request['id'] );
   386 		if ( is_wp_error( $revision ) ) {
   402 		if ( is_wp_error( $revision ) ) {
   387 			return $revision;
   403 			return $revision;
   388 		}
   404 		}
   389 
   405 
       
   406 		if ( (int) $parent->ID !== (int) $revision->post_parent ) {
       
   407 			return new WP_Error(
       
   408 				'rest_revision_parent_id_mismatch',
       
   409 				/* translators: %d: A post id. */
       
   410 				sprintf( __( 'The revision does not belong to the specified parent with id of "%d"' ), $parent->ID ),
       
   411 				array( 'status' => 404 )
       
   412 			);
       
   413 		}
       
   414 
   390 		$response = $this->prepare_item_for_response( $revision, $request );
   415 		$response = $this->prepare_item_for_response( $revision, $request );
   391 		return rest_ensure_response( $response );
   416 		return rest_ensure_response( $response );
   392 	}
   417 	}
   393 
   418 
   394 	/**
   419 	/**
   402 	public function delete_item_permissions_check( $request ) {
   427 	public function delete_item_permissions_check( $request ) {
   403 		$parent = $this->get_parent( $request['parent'] );
   428 		$parent = $this->get_parent( $request['parent'] );
   404 		if ( is_wp_error( $parent ) ) {
   429 		if ( is_wp_error( $parent ) ) {
   405 			return $parent;
   430 			return $parent;
   406 		}
   431 		}
   407 
       
   408 		$parent_post_type = get_post_type_object( $parent->post_type );
       
   409 
   432 
   410 		if ( ! current_user_can( 'delete_post', $parent->ID ) ) {
   433 		if ( ! current_user_can( 'delete_post', $parent->ID ) ) {
   411 			return new WP_Error(
   434 			return new WP_Error(
   412 				'rest_cannot_delete',
   435 				'rest_cannot_delete',
   413 				__( 'Sorry, you are not allowed to delete revisions of this post.' ),
   436 				__( 'Sorry, you are not allowed to delete revisions of this post.' ),
   535 	 * Prepares the revision for the REST response.
   558 	 * Prepares the revision for the REST response.
   536 	 *
   559 	 *
   537 	 * @since 4.7.0
   560 	 * @since 4.7.0
   538 	 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support.
   561 	 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support.
   539 	 *
   562 	 *
       
   563 	 * @global WP_Post $post Global post object.
       
   564 	 *
   540 	 * @param WP_Post         $item    Post revision object.
   565 	 * @param WP_Post         $item    Post revision object.
   541 	 * @param WP_REST_Request $request Request object.
   566 	 * @param WP_REST_Request $request Request object.
   542 	 * @return WP_REST_Response Response object.
   567 	 * @return WP_REST_Response Response object.
   543 	 */
   568 	 */
   544 	public function prepare_item_for_response( $item, $request ) {
   569 	public function prepare_item_for_response( $item, $request ) {
   545 		// Restores the more descriptive, specific name for use within this method.
   570 		// Restores the more descriptive, specific name for use within this method.
   546 		$post            = $item;
   571 		$post = $item;
       
   572 
   547 		$GLOBALS['post'] = $post;
   573 		$GLOBALS['post'] = $post;
   548 
   574 
   549 		setup_postdata( $post );
   575 		setup_postdata( $post );
   550 
   576 
   551 		$fields = $this->get_fields_for_response( $request );
   577 		$fields = $this->get_fields_for_response( $request );
   612 				'raw'      => $post->post_excerpt,
   638 				'raw'      => $post->post_excerpt,
   613 				'rendered' => $this->prepare_excerpt_response( $post->post_excerpt, $post ),
   639 				'rendered' => $this->prepare_excerpt_response( $post->post_excerpt, $post ),
   614 			);
   640 			);
   615 		}
   641 		}
   616 
   642 
       
   643 		if ( rest_is_field_included( 'meta', $fields ) ) {
       
   644 			$data['meta'] = $this->meta->get_value( $post->ID, $request );
       
   645 		}
       
   646 
   617 		$context  = ! empty( $request['context'] ) ? $request['context'] : 'view';
   647 		$context  = ! empty( $request['context'] ) ? $request['context'] : 'view';
   618 		$data     = $this->add_additional_fields_to_object( $data, $request );
   648 		$data     = $this->add_additional_fields_to_object( $data, $request );
   619 		$data     = $this->filter_response_by_context( $data, $context );
   649 		$data     = $this->filter_response_by_context( $data, $context );
   620 		$response = rest_ensure_response( $data );
   650 		$response = rest_ensure_response( $data );
   621 
   651 
   622 		if ( ! empty( $data['parent'] ) ) {
   652 		if ( ! empty( $data['parent'] ) ) {
   623 			$response->add_link( 'parent', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->parent_base, $data['parent'] ) ) );
   653 			$response->add_link( 'parent', rest_url( rest_get_route_for_post( $data['parent'] ) ) );
   624 		}
   654 		}
   625 
   655 
   626 		/**
   656 		/**
   627 		 * Filters a revision returned from the REST API.
   657 		 * Filters a revision returned from the REST API.
   628 		 *
   658 		 *
   744 		}
   774 		}
   745 
   775 
   746 		if ( ! empty( $parent_schema['properties']['guid'] ) ) {
   776 		if ( ! empty( $parent_schema['properties']['guid'] ) ) {
   747 			$schema['properties']['guid'] = $parent_schema['properties']['guid'];
   777 			$schema['properties']['guid'] = $parent_schema['properties']['guid'];
   748 		}
   778 		}
       
   779 
       
   780 		$schema['properties']['meta'] = $this->meta->get_field_schema();
   749 
   781 
   750 		$this->schema = $schema;
   782 		$this->schema = $schema;
   751 
   783 
   752 		return $this->add_additional_fields_schema( $this->schema );
   784 		return $this->add_additional_fields_schema( $this->schema );
   753 	}
   785 	}