Docs: Add much more complete and syntactically correct documentation throughout the `WP_REST_Controller` class.

Props Soean, mrahmadawais, flixos90.
See #38398.

Built from https://develop.svn.wordpress.org/trunk@39021


git-svn-id: http://core.svn.wordpress.org/trunk@38963 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Drew Jaynes 2016-10-30 16:20:29 +00:00
parent 2d0d9cfbf9
commit 718f9fe868
2 changed files with 185 additions and 80 deletions

View File

@ -1,11 +1,24 @@
<?php <?php
/**
* REST API: WP_REST_Controller class
*
* @package WordPress
* @subpackage REST_API
* @since 4.7.0
*/
/**
* Core base controller for managing and interacting with REST API items.
*
* @since 4.7.0
*/
abstract class WP_REST_Controller { abstract class WP_REST_Controller {
/** /**
* The namespace of this controller's route. * The namespace of this controller's route.
* *
* @since 4.7.0
* @access protected
* @var string * @var string
*/ */
protected $namespace; protected $namespace;
@ -13,143 +26,187 @@ abstract class WP_REST_Controller {
/** /**
* The base of this controller's route. * The base of this controller's route.
* *
* @since 4.7.0
* @access protected
* @var string * @var string
*/ */
protected $rest_base; protected $rest_base;
/** /**
* Register the routes for the objects of the controller. * Registers the routes for the objects of the controller.
*
* @since 4.7.0
* @access public
*/ */
public function register_routes() { public function register_routes() {
_doing_it_wrong( 'WP_REST_Controller::register_routes', __( 'The register_routes() method must be overridden' ), 'WPAPI-2.0' ); _doing_it_wrong( 'WP_REST_Controller::register_routes', __( 'The register_routes() method must be overridden' ), '4.7' );
} }
/** /**
* Check if a given request has access to get items. * Checks if a given request has access to get items.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean * @return WP_Error|bool True if the request has read access, WP_Error object otherwise.
*/ */
public function get_items_permissions_check( $request ) { public function get_items_permissions_check( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Get a collection of items. * Retrieves a collection of items.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function get_items( $request ) { public function get_items( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Check if a given request has access to get a specific item. * Checks if a given request has access to get a specific item.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean * @return WP_Error|bool True if the request has read access for the item, WP_Error object otherwise.
*/ */
public function get_item_permissions_check( $request ) { public function get_item_permissions_check( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Get one item from the collection. * Retrieves one item from the collection.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function get_item( $request ) { public function get_item( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Check if a given request has access to create items. * Checks if a given request has access to create items.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean * @return WP_Error|bool True if the request has access to create items, WP_Error object otherwise.
*/ */
public function create_item_permissions_check( $request ) { public function create_item_permissions_check( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Create one item from the collection. * Creates one item from the collection.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function create_item( $request ) { public function create_item( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Check if a given request has access to update a specific item. * Checks if a given request has access to update a specific item.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean * @return WP_Error|bool True if the request has access to update the item, WP_Error object otherwise.
*/ */
public function update_item_permissions_check( $request ) { public function update_item_permissions_check( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Update one item from the collection. * Updates one item from the collection.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function update_item( $request ) { public function update_item( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Check if a given request has access to delete a specific item. * Checks if a given request has access to delete a specific item.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|boolean * @return WP_Error|bool True if the request has access to delete the item, WP_Error object otherwise.
*/ */
public function delete_item_permissions_check( $request ) { public function delete_item_permissions_check( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Delete one item from the collection. * Deletes one item from the collection.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Full data about the request. * @param WP_REST_Request $request Full data about the request.
* @return WP_Error|WP_REST_Response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function delete_item( $request ) { public function delete_item( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Prepare the item for create or update operation. * Prepares one item for create or update operation.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Request $request Request object. * @param WP_REST_Request $request Request object.
* @return WP_Error|object $prepared_item * @return WP_Error|object The prepared item, or WP_Error object on failure.
*/ */
protected function prepare_item_for_database( $request ) { protected function prepare_item_for_database( $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Prepare the item for the REST response. * Prepares the item for the REST response.
*
* @since 4.7.0
* @access public
* *
* @param mixed $item WordPress representation of the item. * @param mixed $item WordPress representation of the item.
* @param WP_REST_Request $request Request object. * @param WP_REST_Request $request Request object.
* @return WP_Error|WP_REST_Response $response * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
*/ */
public function prepare_item_for_response( $item, $request ) { public function prepare_item_for_response( $item, $request ) {
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
} }
/** /**
* Prepare a response for inserting into a collection. * Prepares a response for insertion into a collection.
*
* @since 4.7.0
* @access public
* *
* @param WP_REST_Response $response Response object. * @param WP_REST_Response $response Response object.
* @return array Response data, ready for insertion into collection data. * @return array|mixed Response data, ready for insertion into collection data.
*/ */
public function prepare_response_for_collection( $response ) { public function prepare_response_for_collection( $response ) {
if ( ! ( $response instanceof WP_REST_Response ) ) { if ( ! ( $response instanceof WP_REST_Response ) ) {
@ -173,15 +230,19 @@ abstract class WP_REST_Controller {
} }
/** /**
* Filter a response based on the context defined in the schema. * Filters a response based on the context defined in the schema.
* *
* @param array $data * @since 4.7.0
* @param string $context * @access public
* @return array *
* @param array $data Response data to fiter.
* @param string $context Context defined in the schema.
* @return array Filtered response.
*/ */
public function filter_response_by_context( $data, $context ) { public function filter_response_by_context( $data, $context ) {
$schema = $this->get_item_schema(); $schema = $this->get_item_schema();
foreach ( $data as $key => $value ) { foreach ( $data as $key => $value ) {
if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) { if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) {
continue; continue;
@ -197,6 +258,7 @@ abstract class WP_REST_Controller {
if ( empty( $details['context'] ) ) { if ( empty( $details['context'] ) ) {
continue; continue;
} }
if ( ! in_array( $context, $details['context'], true ) ) { if ( ! in_array( $context, $details['context'], true ) ) {
if ( isset( $data[ $key ][ $attribute ] ) ) { if ( isset( $data[ $key ][ $attribute ] ) ) {
unset( $data[ $key ][ $attribute ] ); unset( $data[ $key ][ $attribute ] );
@ -210,18 +272,24 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get the item's schema, conforming to JSON Schema. * Retrieves the item's schema, conforming to JSON Schema.
* *
* @return array * @since 4.7.0
* @access public
*
* @return array Item schema data.
*/ */
public function get_item_schema() { public function get_item_schema() {
return $this->add_additional_fields_schema( array() ); return $this->add_additional_fields_schema( array() );
} }
/** /**
* Get the item's schema for display / public consumption purposes. * Retrieves the item's schema for display / public consumption purposes.
* *
* @return array * @since 4.7.0
* @access public
*
* @return array Public item schema data.
*/ */
public function get_public_item_schema() { public function get_public_item_schema() {
@ -235,9 +303,12 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get the query params for collections. * Retrieves the query params for the collections.
* *
* @return array * @since 4.7.0
* @access public
*
* @return array Query parameters for the collection.
*/ */
public function get_collection_params() { public function get_collection_params() {
return array( return array(
@ -269,12 +340,15 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get the magical context param. * Retrieves the magical context param.
* *
* Ensures consistent description between endpoints, and populates enum from schema. * Ensures consistent descriptions between endpoints, and populates enum from schema.
* *
* @param array $args * @since 4.7.0
* @return array * @access public
*
* @param array $args Optional. Additional arguments for context parameter. Default empty array.
* @return array Context parameter details.
*/ */
public function get_context_param( $args = array() ) { public function get_context_param( $args = array() ) {
$param_details = array( $param_details = array(
@ -283,29 +357,38 @@ abstract class WP_REST_Controller {
'sanitize_callback' => 'sanitize_key', 'sanitize_callback' => 'sanitize_key',
'validate_callback' => 'rest_validate_request_arg', 'validate_callback' => 'rest_validate_request_arg',
); );
$schema = $this->get_item_schema(); $schema = $this->get_item_schema();
if ( empty( $schema['properties'] ) ) { if ( empty( $schema['properties'] ) ) {
return array_merge( $param_details, $args ); return array_merge( $param_details, $args );
} }
$contexts = array(); $contexts = array();
foreach ( $schema['properties'] as $attributes ) { foreach ( $schema['properties'] as $attributes ) {
if ( ! empty( $attributes['context'] ) ) { if ( ! empty( $attributes['context'] ) ) {
$contexts = array_merge( $contexts, $attributes['context'] ); $contexts = array_merge( $contexts, $attributes['context'] );
} }
} }
if ( ! empty( $contexts ) ) { if ( ! empty( $contexts ) ) {
$param_details['enum'] = array_unique( $contexts ); $param_details['enum'] = array_unique( $contexts );
rsort( $param_details['enum'] ); rsort( $param_details['enum'] );
} }
return array_merge( $param_details, $args ); return array_merge( $param_details, $args );
} }
/** /**
* Add the values from additional fields to a data object. * Adds the values from additional fields to a data object.
* *
* @param array $object * @since 4.7.0
* @param WP_REST_Request $request * @access protected
* @return array modified object with additional fields. *
* @param array $object Data object.
* @param WP_REST_Request $request Full details about the request.
* @return array Modified data object with additional fields.
*/ */
protected function add_additional_fields_to_object( $object, $request ) { protected function add_additional_fields_to_object( $object, $request ) {
@ -324,10 +407,13 @@ abstract class WP_REST_Controller {
} }
/** /**
* Update the values of additional fields added to a data object. * Updates the values of additional fields added to a data object.
* *
* @param array $object * @since 4.7.0
* @param WP_REST_Request $request * @access protected
*
* @param array $object Data Object.
* @param WP_REST_Request $request Full details about the request.
* @return bool|WP_Error True on success, WP_Error object if a field cannot be updated. * @return bool|WP_Error True on success, WP_Error object if a field cannot be updated.
*/ */
protected function update_additional_fields_for_object( $object, $request ) { protected function update_additional_fields_for_object( $object, $request ) {
@ -344,6 +430,7 @@ abstract class WP_REST_Controller {
} }
$result = call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() ); $result = call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
if ( is_wp_error( $result ) ) { if ( is_wp_error( $result ) ) {
return $result; return $result;
} }
@ -353,10 +440,13 @@ abstract class WP_REST_Controller {
} }
/** /**
* Add the schema from additional fields to an schema array. * Adds the schema from additional fields to a schema array.
* *
* The type of object is inferred from the passed schema. * The type of object is inferred from the passed schema.
* *
* @since 4.7.0
* @access protected
*
* @param array $schema Schema array. * @param array $schema Schema array.
* @return array Modified Schema array. * @return array Modified Schema array.
*/ */
@ -365,9 +455,7 @@ abstract class WP_REST_Controller {
return $schema; return $schema;
} }
/** // Can't use $this->get_object_type otherwise we cause an inf loop.
* Can't use $this->get_object_type otherwise we cause an inf loop.
*/
$object_type = $schema['title']; $object_type = $schema['title'];
$additional_fields = $this->get_additional_fields( $object_type ); $additional_fields = $this->get_additional_fields( $object_type );
@ -384,10 +472,14 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get all the registered additional fields for a given object-type. * Retrieves all of the registered additional fields for a given object-type.
* *
* @param string $object_type * @since 4.7.0
* @return array * @access protected
*
* @param string $object_type Optional. The object type.
* @return array Registered additional fields (if any), empty array if none or if the object type could
* not be inferred.
*/ */
protected function get_additional_fields( $object_type = null ) { protected function get_additional_fields( $object_type = null ) {
@ -409,9 +501,12 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get the object type this controller is responsible for managing. * Retrieves the object type this controller is responsible for managing.
* *
* @return string * @since 4.7.0
* @access protected
*
* @return string Object type for the controller.
*/ */
protected function get_object_type() { protected function get_object_type() {
$schema = $this->get_item_schema(); $schema = $this->get_item_schema();
@ -424,14 +519,15 @@ abstract class WP_REST_Controller {
} }
/** /**
* Get an array of endpoint arguments from the item schema for the controller. * Retrieves an array of endpoint arguments from the item schema for the controller.
* *
* @param string $method HTTP method of the request. The arguments * @since 4.7.0
* for `CREATABLE` requests are checked for required * @access public
* values and may fall-back to a given default, this *
* is not done on `EDITABLE` requests. Default is * @param string $method Optional. HTTP method of the request. The arguments for `CREATABLE` requests are
* WP_REST_Server::CREATABLE. * checked for required values and may fall-back to a given default, this is not done
* @return array $endpoint_args * on `EDITABLE` requests. Default WP_REST_Server::CREATABLE.
* @return array Endpoint arguments.
*/ */
public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) { public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
@ -492,21 +588,26 @@ abstract class WP_REST_Controller {
* resultant post object. This is done so that plugins may manipulate the * resultant post object. This is done so that plugins may manipulate the
* post that is used in the REST API. * post that is used in the REST API.
* *
* @since 4.7.0
* @access public
*
* @see get_post() * @see get_post()
* @global WP_Query $wp_query * @global WP_Query $wp_query
* *
* @param int|WP_Post $post Post ID or post object. Defaults to global $post. * @param int|WP_Post $post Post ID or object. Defaults to global `$post` object.
* @return WP_Post|null A `WP_Post` object when successful. * @return WP_Post|null A WP_Post object when successful, otherwise null.
*/ */
public function get_post( $post ) { public function get_post( $post ) {
$post_obj = get_post( $post ); $post_obj = get_post( $post );
/** /**
* Filter the post. * Filters the post in the context of a REST request.
* *
* Allows plugins to filter the post object as returned by `\WP_REST_Controller::get_post()`. * Allows plugins to filter the post object as returned by WP_REST_Controller::get_post().
* *
* @param WP_Post|null $post_obj The post object as returned by `get_post()`. * @since 4.7.0
*
* @param WP_Post|null $post_obj The post object as returned by get_post().
* @param int|WP_Post $post The original value used to obtain the post object. * @param int|WP_Post $post The original value used to obtain the post object.
*/ */
$post = apply_filters( 'rest_the_post', $post_obj, $post ); $post = apply_filters( 'rest_the_post', $post_obj, $post );
@ -515,11 +616,15 @@ abstract class WP_REST_Controller {
} }
/** /**
* Sanitize the slug value. * Sanitizes the slug value.
* *
* @internal We can't use {@see sanitize_title} directly, as the second * @since 4.7.0
* @access public
*
* @internal We can't use sanitize_title() directly, as the second
* parameter is the fallback title, which would end up being set to the * parameter is the fallback title, which would end up being set to the
* request object. * request object.
*
* @see https://github.com/WP-API/WP-API/issues/1585 * @see https://github.com/WP-API/WP-API/issues/1585
* *
* @todo Remove this in favour of https://core.trac.wordpress.org/ticket/34659 * @todo Remove this in favour of https://core.trac.wordpress.org/ticket/34659

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.7-beta1-39020'; $wp_version = '4.7-beta1-39021';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.