Added login request
This commit is contained in:
@@ -0,0 +1,743 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Attachments_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core controller used to access attachments via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Posts_Controller
|
||||
*/
|
||||
class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
|
||||
/**
|
||||
* Determines the allowed query_vars for a get_items() response and
|
||||
* prepares for WP_Query.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $prepared_args Optional. Array of prepared arguments. Default empty array.
|
||||
* @param WP_REST_Request $request Optional. Request to prepare items for.
|
||||
* @return array Array of query arguments.
|
||||
*/
|
||||
protected function prepare_items_query( $prepared_args = array(), $request = null ) {
|
||||
$query_args = parent::prepare_items_query( $prepared_args, $request );
|
||||
|
||||
if ( empty( $query_args['post_status'] ) ) {
|
||||
$query_args['post_status'] = 'inherit';
|
||||
}
|
||||
|
||||
$media_types = $this->get_media_types();
|
||||
|
||||
if ( ! empty( $request['media_type'] ) && isset( $media_types[ $request['media_type'] ] ) ) {
|
||||
$query_args['post_mime_type'] = $media_types[ $request['media_type'] ];
|
||||
}
|
||||
|
||||
if ( ! empty( $request['mime_type'] ) ) {
|
||||
$parts = explode( '/', $request['mime_type'] );
|
||||
if ( isset( $media_types[ $parts[0] ] ) && in_array( $request['mime_type'], $media_types[ $parts[0] ], true ) ) {
|
||||
$query_args['post_mime_type'] = $request['mime_type'];
|
||||
}
|
||||
}
|
||||
|
||||
// Filter query clauses to include filenames.
|
||||
if ( isset( $query_args['s'] ) ) {
|
||||
add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
|
||||
}
|
||||
|
||||
return $query_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to create an attachment.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|true Boolean true if the attachment may be created, or a WP_Error if not.
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
$ret = parent::create_item_permissions_check( $request );
|
||||
|
||||
if ( ! $ret || is_wp_error( $ret ) ) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'upload_files' ) ) {
|
||||
return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
// Attaching media to a post requires ability to edit said post.
|
||||
if ( ! empty( $request['post'] ) ) {
|
||||
$parent = get_post( (int) $request['post'] );
|
||||
$post_parent_type = get_post_type_object( $parent->post_type );
|
||||
|
||||
if ( ! current_user_can( $post_parent_type->cap->edit_post, $request['post'] ) ) {
|
||||
return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this post.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single attachment.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, WP_Error object on failure.
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
|
||||
if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) {
|
||||
return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
// Get the file via $_FILES or raw data.
|
||||
$files = $request->get_file_params();
|
||||
$headers = $request->get_headers();
|
||||
|
||||
if ( ! empty( $files ) ) {
|
||||
$file = $this->upload_from_file( $files, $headers );
|
||||
} else {
|
||||
$file = $this->upload_from_data( $request->get_body(), $headers );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $file ) ) {
|
||||
return $file;
|
||||
}
|
||||
|
||||
$name = basename( $file['file'] );
|
||||
$name_parts = pathinfo( $name );
|
||||
$name = trim( substr( $name, 0, -(1 + strlen( $name_parts['extension'] ) ) ) );
|
||||
|
||||
$url = $file['url'];
|
||||
$type = $file['type'];
|
||||
$file = $file['file'];
|
||||
|
||||
// use image exif/iptc data for title and caption defaults if possible
|
||||
$image_meta = wp_read_image_metadata( $file );
|
||||
|
||||
if ( ! empty( $image_meta ) ) {
|
||||
if ( empty( $request['title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
|
||||
$request['title'] = $image_meta['title'];
|
||||
}
|
||||
|
||||
if ( empty( $request['caption'] ) && trim( $image_meta['caption'] ) ) {
|
||||
$request['caption'] = $image_meta['caption'];
|
||||
}
|
||||
}
|
||||
|
||||
$attachment = $this->prepare_item_for_database( $request );
|
||||
$attachment->file = $file;
|
||||
$attachment->post_mime_type = $type;
|
||||
$attachment->guid = $url;
|
||||
|
||||
if ( empty( $attachment->post_title ) ) {
|
||||
$attachment->post_title = preg_replace( '/\.[^.]+$/', '', basename( $file ) );
|
||||
}
|
||||
|
||||
$id = wp_insert_post( wp_slash( (array) $attachment ), true );
|
||||
|
||||
if ( is_wp_error( $id ) ) {
|
||||
if ( 'db_update_error' === $id->get_error_code() ) {
|
||||
$id->add_data( array( 'status' => 500 ) );
|
||||
} else {
|
||||
$id->add_data( array( 'status' => 400 ) );
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
$attachment = get_post( $id );
|
||||
|
||||
/**
|
||||
* Fires after a single attachment is created or updated via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_Post $attachment Inserted or updated attachment
|
||||
* object.
|
||||
* @param WP_REST_Request $request The request sent to the API.
|
||||
* @param bool $creating True when creating an attachment, false when updating.
|
||||
*/
|
||||
do_action( 'rest_insert_attachment', $attachment, $request, true );
|
||||
|
||||
// Include admin functions to get access to wp_generate_attachment_metadata().
|
||||
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
||||
|
||||
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
|
||||
|
||||
if ( isset( $request['alt_text'] ) ) {
|
||||
update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
|
||||
}
|
||||
|
||||
$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
|
||||
|
||||
if ( is_wp_error( $fields_update ) ) {
|
||||
return $fields_update;
|
||||
}
|
||||
|
||||
$request->set_param( 'context', 'edit' );
|
||||
$response = $this->prepare_item_for_response( $attachment, $request );
|
||||
$response = rest_ensure_response( $response );
|
||||
$response->set_status( 201 );
|
||||
$response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a single attachment.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, WP_Error object on failure.
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) {
|
||||
return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$response = parent::update_item( $request );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( $response );
|
||||
$data = $response->get_data();
|
||||
|
||||
if ( isset( $request['alt_text'] ) ) {
|
||||
update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
|
||||
}
|
||||
|
||||
$attachment = get_post( $request['id'] );
|
||||
|
||||
/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
|
||||
do_action( 'rest_insert_attachment', $data, $request, false );
|
||||
|
||||
$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
|
||||
|
||||
if ( is_wp_error( $fields_update ) ) {
|
||||
return $fields_update;
|
||||
}
|
||||
|
||||
$request->set_param( 'context', 'edit' );
|
||||
$response = $this->prepare_item_for_response( $attachment, $request );
|
||||
$response = rest_ensure_response( $response );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single attachment for create or update.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_Error|stdClass $prepared_attachment Post object.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$prepared_attachment = parent::prepare_item_for_database( $request );
|
||||
|
||||
// Attachment caption (post_excerpt internally)
|
||||
if ( isset( $request['caption'] ) ) {
|
||||
if ( is_string( $request['caption'] ) ) {
|
||||
$prepared_attachment->post_excerpt = $request['caption'];
|
||||
} elseif ( isset( $request['caption']['raw'] ) ) {
|
||||
$prepared_attachment->post_excerpt = $request['caption']['raw'];
|
||||
}
|
||||
}
|
||||
|
||||
// Attachment description (post_content internally)
|
||||
if ( isset( $request['description'] ) ) {
|
||||
if ( is_string( $request['description'] ) ) {
|
||||
$prepared_attachment->post_content = $request['description'];
|
||||
} elseif ( isset( $request['description']['raw'] ) ) {
|
||||
$prepared_attachment->post_content = $request['description']['raw'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $request['post'] ) ) {
|
||||
$prepared_attachment->post_parent = (int) $request['post'];
|
||||
}
|
||||
|
||||
return $prepared_attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single attachment output for response.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_Post $post Attachment object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $post, $request ) {
|
||||
$response = parent::prepare_item_for_response( $post, $request );
|
||||
$data = $response->get_data();
|
||||
|
||||
$data['description'] = array(
|
||||
'raw' => $post->post_content,
|
||||
/** This filter is documented in wp-includes/post-template.php */
|
||||
'rendered' => apply_filters( 'the_content', $post->post_content ),
|
||||
);
|
||||
|
||||
/** This filter is documented in wp-includes/post-template.php */
|
||||
$caption = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ) );
|
||||
$data['caption'] = array(
|
||||
'raw' => $post->post_excerpt,
|
||||
'rendered' => $caption,
|
||||
);
|
||||
|
||||
$data['alt_text'] = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
|
||||
$data['media_type'] = wp_attachment_is_image( $post->ID ) ? 'image' : 'file';
|
||||
$data['mime_type'] = $post->post_mime_type;
|
||||
$data['media_details'] = wp_get_attachment_metadata( $post->ID );
|
||||
$data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null;
|
||||
$data['source_url'] = wp_get_attachment_url( $post->ID );
|
||||
|
||||
// Ensure empty details is an empty object.
|
||||
if ( empty( $data['media_details'] ) ) {
|
||||
$data['media_details'] = new stdClass;
|
||||
} elseif ( ! empty( $data['media_details']['sizes'] ) ) {
|
||||
|
||||
foreach ( $data['media_details']['sizes'] as $size => &$size_data ) {
|
||||
|
||||
if ( isset( $size_data['mime-type'] ) ) {
|
||||
$size_data['mime_type'] = $size_data['mime-type'];
|
||||
unset( $size_data['mime-type'] );
|
||||
}
|
||||
|
||||
// Use the same method image_downsize() does.
|
||||
$image_src = wp_get_attachment_image_src( $post->ID, $size );
|
||||
if ( ! $image_src ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$size_data['source_url'] = $image_src[0];
|
||||
}
|
||||
|
||||
$full_src = wp_get_attachment_image_src( $post->ID, 'full' );
|
||||
|
||||
if ( ! empty( $full_src ) ) {
|
||||
$data['media_details']['sizes']['full'] = array(
|
||||
'file' => wp_basename( $full_src[0] ),
|
||||
'width' => $full_src[1],
|
||||
'height' => $full_src[2],
|
||||
'mime_type' => $post->post_mime_type,
|
||||
'source_url' => $full_src[0],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$data['media_details']['sizes'] = new stdClass;
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
// Wrap the data in a response object.
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
$response->add_links( $this->prepare_links( $post ) );
|
||||
|
||||
/**
|
||||
* Filters an attachment returned from the REST API.
|
||||
*
|
||||
* Allows modification of the attachment right before it is returned.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Post $post The original attachment post.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_attachment', $response, $post, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the attachment's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema as an array.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
|
||||
$schema = parent::get_item_schema();
|
||||
|
||||
$schema['properties']['alt_text'] = array(
|
||||
'description' => __( 'Alternative text to display when attachment is not displayed.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
);
|
||||
|
||||
$schema['properties']['caption'] = array(
|
||||
'description' => __( 'The attachment caption.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database()
|
||||
'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database()
|
||||
),
|
||||
'properties' => array(
|
||||
'raw' => array(
|
||||
'description' => __( 'Caption for the attachment, as it exists in the database.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'rendered' => array(
|
||||
'description' => __( 'HTML caption for the attachment, transformed for display.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['properties']['description'] = array(
|
||||
'description' => __( 'The attachment description.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database()
|
||||
'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database()
|
||||
),
|
||||
'properties' => array(
|
||||
'raw' => array(
|
||||
'description' => __( 'Description for the object, as it exists in the database.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'rendered' => array(
|
||||
'description' => __( 'HTML description for the object, transformed for display.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['properties']['media_type'] = array(
|
||||
'description' => __( 'Attachment type.' ),
|
||||
'type' => 'string',
|
||||
'enum' => array( 'image', 'file' ),
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
);
|
||||
|
||||
$schema['properties']['mime_type'] = array(
|
||||
'description' => __( 'The attachment MIME type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
);
|
||||
|
||||
$schema['properties']['media_details'] = array(
|
||||
'description' => __( 'Details about the media file, specific to its type.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
);
|
||||
|
||||
$schema['properties']['post'] = array(
|
||||
'description' => __( 'The ID for the associated post of the attachment.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
);
|
||||
|
||||
$schema['properties']['source_url'] = array(
|
||||
'description' => __( 'URL to the original attachment file.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'uri',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
);
|
||||
|
||||
unset( $schema['properties']['password'] );
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an upload via raw POST data.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $data Supplied file data.
|
||||
* @param array $headers HTTP headers from the request.
|
||||
* @return array|WP_Error Data from wp_handle_sideload().
|
||||
*/
|
||||
protected function upload_from_data( $data, $headers ) {
|
||||
if ( empty( $data ) ) {
|
||||
return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
if ( empty( $headers['content_type'] ) ) {
|
||||
return new WP_Error( 'rest_upload_no_content_type', __( 'No Content-Type supplied.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
if ( empty( $headers['content_disposition'] ) ) {
|
||||
return new WP_Error( 'rest_upload_no_content_disposition', __( 'No Content-Disposition supplied.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$filename = self::get_filename_from_disposition( $headers['content_disposition'] );
|
||||
|
||||
if ( empty( $filename ) ) {
|
||||
return new WP_Error( 'rest_upload_invalid_disposition', __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $headers['content_md5'] ) ) {
|
||||
$content_md5 = array_shift( $headers['content_md5'] );
|
||||
$expected = trim( $content_md5 );
|
||||
$actual = md5( $data );
|
||||
|
||||
if ( $expected !== $actual ) {
|
||||
return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Get the content-type.
|
||||
$type = array_shift( $headers['content_type'] );
|
||||
|
||||
/** Include admin functions to get access to wp_tempnam() and wp_handle_sideload() */
|
||||
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
||||
|
||||
// Save the file.
|
||||
$tmpfname = wp_tempnam( $filename );
|
||||
|
||||
$fp = fopen( $tmpfname, 'w+' );
|
||||
|
||||
if ( ! $fp ) {
|
||||
return new WP_Error( 'rest_upload_file_error', __( 'Could not open file handle.' ), array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
fwrite( $fp, $data );
|
||||
fclose( $fp );
|
||||
|
||||
// Now, sideload it in.
|
||||
$file_data = array(
|
||||
'error' => null,
|
||||
'tmp_name' => $tmpfname,
|
||||
'name' => $filename,
|
||||
'type' => $type,
|
||||
);
|
||||
|
||||
$overrides = array(
|
||||
'test_form' => false,
|
||||
);
|
||||
|
||||
$sideloaded = wp_handle_sideload( $file_data, $overrides );
|
||||
|
||||
if ( isset( $sideloaded['error'] ) ) {
|
||||
@unlink( $tmpfname );
|
||||
|
||||
return new WP_Error( 'rest_upload_sideload_error', $sideloaded['error'], array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
return $sideloaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses filename from a Content-Disposition header value.
|
||||
*
|
||||
* As per RFC6266:
|
||||
*
|
||||
* content-disposition = "Content-Disposition" ":"
|
||||
* disposition-type *( ";" disposition-parm )
|
||||
*
|
||||
* disposition-type = "inline" | "attachment" | disp-ext-type
|
||||
* ; case-insensitive
|
||||
* disp-ext-type = token
|
||||
*
|
||||
* disposition-parm = filename-parm | disp-ext-parm
|
||||
*
|
||||
* filename-parm = "filename" "=" value
|
||||
* | "filename*" "=" ext-value
|
||||
*
|
||||
* disp-ext-parm = token "=" value
|
||||
* | ext-token "=" ext-value
|
||||
* ext-token = <the characters in token, followed by "*">
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc2388
|
||||
* @link http://tools.ietf.org/html/rfc6266
|
||||
*
|
||||
* @param string[] $disposition_header List of Content-Disposition header values.
|
||||
* @return string|null Filename if available, or null if not found.
|
||||
*/
|
||||
public static function get_filename_from_disposition( $disposition_header ) {
|
||||
// Get the filename.
|
||||
$filename = null;
|
||||
|
||||
foreach ( $disposition_header as $value ) {
|
||||
$value = trim( $value );
|
||||
|
||||
if ( strpos( $value, ';' ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $type, $attr_parts ) = explode( ';', $value, 2 );
|
||||
|
||||
$attr_parts = explode( ';', $attr_parts );
|
||||
$attributes = array();
|
||||
|
||||
foreach ( $attr_parts as $part ) {
|
||||
if ( strpos( $part, '=' ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $key, $value ) = explode( '=', $part, 2 );
|
||||
|
||||
$attributes[ trim( $key ) ] = trim( $value );
|
||||
}
|
||||
|
||||
if ( empty( $attributes['filename'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = trim( $attributes['filename'] );
|
||||
|
||||
// Unquote quoted filename, but after trimming.
|
||||
if ( substr( $filename, 0, 1 ) === '"' && substr( $filename, -1, 1 ) === '"' ) {
|
||||
$filename = substr( $filename, 1, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections of attachments.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Query parameters for the attachment collection as an array.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$params = parent::get_collection_params();
|
||||
$params['status']['default'] = 'inherit';
|
||||
$params['status']['items']['enum'] = array( 'inherit', 'private', 'trash' );
|
||||
$media_types = $this->get_media_types();
|
||||
|
||||
$params['media_type'] = array(
|
||||
'default' => null,
|
||||
'description' => __( 'Limit result set to attachments of a particular media type.' ),
|
||||
'type' => 'string',
|
||||
'enum' => array_keys( $media_types ),
|
||||
);
|
||||
|
||||
$params['mime_type'] = array(
|
||||
'default' => null,
|
||||
'description' => __( 'Limit result set to attachments of a particular MIME type.' ),
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the user can query private statuses.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param mixed $value Status value.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @param string $parameter Additional parameter to pass for validation.
|
||||
* @return WP_Error|bool True if the user may query, WP_Error if not.
|
||||
*/
|
||||
public function validate_user_can_query_private_statuses( $value, $request, $parameter ) {
|
||||
if ( 'inherit' === $value ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::validate_user_can_query_private_statuses( $value, $request, $parameter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an upload via multipart/form-data ($_FILES).
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $files Data from the `$_FILES` superglobal.
|
||||
* @param array $headers HTTP headers from the request.
|
||||
* @return array|WP_Error Data from wp_handle_upload().
|
||||
*/
|
||||
protected function upload_from_file( $files, $headers ) {
|
||||
if ( empty( $files ) ) {
|
||||
return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
// Verify hash, if given.
|
||||
if ( ! empty( $headers['content_md5'] ) ) {
|
||||
$content_md5 = array_shift( $headers['content_md5'] );
|
||||
$expected = trim( $content_md5 );
|
||||
$actual = md5_file( $files['file']['tmp_name'] );
|
||||
|
||||
if ( $expected !== $actual ) {
|
||||
return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Pass off to WP to handle the actual upload.
|
||||
$overrides = array(
|
||||
'test_form' => false,
|
||||
);
|
||||
|
||||
// Bypasses is_uploaded_file() when running unit tests.
|
||||
if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) {
|
||||
$overrides['action'] = 'wp_handle_mock_upload';
|
||||
}
|
||||
|
||||
/** Include admin functions to get access to wp_handle_upload() */
|
||||
require_once ABSPATH . 'wp-admin/includes/admin.php';
|
||||
|
||||
$file = wp_handle_upload( $files['file'], $overrides );
|
||||
|
||||
if ( isset( $file['error'] ) ) {
|
||||
return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the supported media types.
|
||||
*
|
||||
* Media types are considered the MIME type category.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Array of supported media types.
|
||||
*/
|
||||
protected function get_media_types() {
|
||||
$media_types = array();
|
||||
|
||||
foreach ( get_allowed_mime_types() as $mime_type ) {
|
||||
$parts = explode( '/', $mime_type );
|
||||
|
||||
if ( ! isset( $media_types[ $parts[0] ] ) ) {
|
||||
$media_types[ $parts[0] ] = array();
|
||||
}
|
||||
|
||||
$media_types[ $parts[0] ][] = $mime_type;
|
||||
}
|
||||
|
||||
return $media_types;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,588 @@
|
||||
<?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 {
|
||||
|
||||
/**
|
||||
* The namespace of this controller's route.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace;
|
||||
|
||||
/**
|
||||
* The base of this controller's route.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @var string
|
||||
*/
|
||||
protected $rest_base;
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
public function register_routes() {
|
||||
/* translators: %s: register_routes() */
|
||||
_doing_it_wrong( 'WP_REST_Controller::register_routes', sprintf( __( "Method '%s' must be overridden." ), __METHOD__ ), '4.7' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to get items.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|bool True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a collection of items.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to get a specific item.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @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 ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves one item from the collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to create items.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|bool True if the request has access to create items, WP_Error object otherwise.
|
||||
*/
|
||||
public function create_item_permissions_check( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one item from the collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to update a specific item.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @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 ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates one item from the collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to delete a specific item.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @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 ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one item from the collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares one item for create or update operation.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_Error|object The prepared item, or WP_Error object on failure.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the item for the REST response.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param mixed $item WordPress representation of the item.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
/* translators: %s: method name */
|
||||
return new WP_Error( 'invalid-method', sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a response for insertion into a collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response Response object.
|
||||
* @return array|mixed Response data, ready for insertion into collection data.
|
||||
*/
|
||||
public function prepare_response_for_collection( $response ) {
|
||||
if ( ! ( $response instanceof WP_REST_Response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$data = (array) $response->get_data();
|
||||
$server = rest_get_server();
|
||||
|
||||
if ( method_exists( $server, 'get_compact_response_links' ) ) {
|
||||
$links = call_user_func( array( $server, 'get_compact_response_links' ), $response );
|
||||
} else {
|
||||
$links = call_user_func( array( $server, 'get_response_links' ), $response );
|
||||
}
|
||||
|
||||
if ( ! empty( $links ) ) {
|
||||
$data['_links'] = $links;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a response based on the context defined in the schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @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 ) {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
foreach ( $data as $key => $value ) {
|
||||
if ( empty( $schema['properties'][ $key ] ) || empty( $schema['properties'][ $key ]['context'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! in_array( $context, $schema['properties'][ $key ]['context'], true ) ) {
|
||||
unset( $data[ $key ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
|
||||
foreach ( $schema['properties'][ $key ]['properties'] as $attribute => $details ) {
|
||||
if ( empty( $details['context'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! in_array( $context, $details['context'], true ) ) {
|
||||
if ( isset( $data[ $key ][ $attribute ] ) ) {
|
||||
unset( $data[ $key ][ $attribute ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
return $this->add_additional_fields_schema( array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item's schema for display / public consumption purposes.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Public item schema data.
|
||||
*/
|
||||
public function get_public_item_schema() {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
foreach ( $schema['properties'] as &$property ) {
|
||||
unset( $property['arg_options'] );
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for the collections.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Query parameters for the collection.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'context' => $this->get_context_param(),
|
||||
'page' => array(
|
||||
'description' => __( 'Current page of the collection.' ),
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'minimum' => 1,
|
||||
),
|
||||
'per_page' => array(
|
||||
'description' => __( 'Maximum number of items to be returned in result set.' ),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'minimum' => 1,
|
||||
'maximum' => 100,
|
||||
'sanitize_callback' => 'absint',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'search' => array(
|
||||
'description' => __( 'Limit results to those matching a string.' ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the magical context param.
|
||||
*
|
||||
* Ensures consistent descriptions between endpoints, and populates enum from schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $args Optional. Additional arguments for context parameter. Default empty array.
|
||||
* @return array Context parameter details.
|
||||
*/
|
||||
public function get_context_param( $args = array() ) {
|
||||
$param_details = array(
|
||||
'description' => __( 'Scope under which the request is made; determines fields present in response.' ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_key',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
if ( empty( $schema['properties'] ) ) {
|
||||
return array_merge( $param_details, $args );
|
||||
}
|
||||
|
||||
$contexts = array();
|
||||
|
||||
foreach ( $schema['properties'] as $attributes ) {
|
||||
if ( ! empty( $attributes['context'] ) ) {
|
||||
$contexts = array_merge( $contexts, $attributes['context'] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $contexts ) ) {
|
||||
$param_details['enum'] = array_unique( $contexts );
|
||||
rsort( $param_details['enum'] );
|
||||
}
|
||||
|
||||
return array_merge( $param_details, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the values from additional fields to a data object.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @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 ) {
|
||||
|
||||
$additional_fields = $this->get_additional_fields();
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
|
||||
if ( ! $field_options['get_callback'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$object[ $field_name ] = call_user_func( $field_options['get_callback'], $object, $field_name, $request, $this->get_object_type() );
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the values of additional fields added to a data object.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
protected function update_additional_fields_for_object( $object, $request ) {
|
||||
$additional_fields = $this->get_additional_fields();
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
if ( ! $field_options['update_callback'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't run the update callbacks if the data wasn't passed in the request.
|
||||
if ( ! isset( $request[ $field_name ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the schema from additional fields to a schema array.
|
||||
*
|
||||
* The type of object is inferred from the passed schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $schema Schema array.
|
||||
* @return array Modified Schema array.
|
||||
*/
|
||||
protected function add_additional_fields_schema( $schema ) {
|
||||
if ( empty( $schema['title'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
// Can't use $this->get_object_type otherwise we cause an inf loop.
|
||||
$object_type = $schema['title'];
|
||||
|
||||
$additional_fields = $this->get_additional_fields( $object_type );
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
if ( ! $field_options['schema'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$schema['properties'][ $field_name ] = $field_options['schema'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all of the registered additional fields for a given object-type.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @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 ) {
|
||||
|
||||
if ( ! $object_type ) {
|
||||
$object_type = $this->get_object_type();
|
||||
}
|
||||
|
||||
if ( ! $object_type ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
global $wp_rest_additional_fields;
|
||||
|
||||
if ( ! $wp_rest_additional_fields || ! isset( $wp_rest_additional_fields[ $object_type ] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $wp_rest_additional_fields[ $object_type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object type this controller is responsible for managing.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return string Object type for the controller.
|
||||
*/
|
||||
protected function get_object_type() {
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
if ( ! $schema || ! isset( $schema['title'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $schema['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of endpoint arguments from the item schema for the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param string $method Optional. HTTP method of the request. The arguments for `CREATABLE` requests are
|
||||
* checked for required values and may fall-back to a given default, this is not done
|
||||
* 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 ) {
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
$schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array();
|
||||
$endpoint_args = array();
|
||||
|
||||
foreach ( $schema_properties as $field_id => $params ) {
|
||||
|
||||
// Arguments specified as `readonly` are not allowed to be set.
|
||||
if ( ! empty( $params['readonly'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$endpoint_args[ $field_id ] = array(
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
'sanitize_callback' => 'rest_sanitize_request_arg',
|
||||
);
|
||||
|
||||
if ( isset( $params['description'] ) ) {
|
||||
$endpoint_args[ $field_id ]['description'] = $params['description'];
|
||||
}
|
||||
|
||||
if ( WP_REST_Server::CREATABLE === $method && isset( $params['default'] ) ) {
|
||||
$endpoint_args[ $field_id ]['default'] = $params['default'];
|
||||
}
|
||||
|
||||
if ( WP_REST_Server::CREATABLE === $method && ! empty( $params['required'] ) ) {
|
||||
$endpoint_args[ $field_id ]['required'] = true;
|
||||
}
|
||||
|
||||
foreach ( array( 'type', 'format', 'enum', 'items', 'properties', 'additionalProperties' ) as $schema_prop ) {
|
||||
if ( isset( $params[ $schema_prop ] ) ) {
|
||||
$endpoint_args[ $field_id ][ $schema_prop ] = $params[ $schema_prop ];
|
||||
}
|
||||
}
|
||||
|
||||
// Merge in any options provided by the schema property.
|
||||
if ( isset( $params['arg_options'] ) ) {
|
||||
|
||||
// Only use required / default from arg_options on CREATABLE endpoints.
|
||||
if ( WP_REST_Server::CREATABLE !== $method ) {
|
||||
$params['arg_options'] = array_diff_key( $params['arg_options'], array( 'required' => '', 'default' => '' ) );
|
||||
}
|
||||
|
||||
$endpoint_args[ $field_id ] = array_merge( $endpoint_args[ $field_id ], $params['arg_options'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $endpoint_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the slug value.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @internal We can't use sanitize_title() directly, as the second
|
||||
* parameter is the fallback title, which would end up being set to the
|
||||
* request object.
|
||||
*
|
||||
* @see https://github.com/WP-API/WP-API/issues/1585
|
||||
*
|
||||
* @todo Remove this in favour of https://core.trac.wordpress.org/ticket/34659
|
||||
*
|
||||
* @param string $slug Slug value passed in request.
|
||||
* @return string Sanitized value for the slug.
|
||||
*/
|
||||
public function sanitize_slug( $slug ) {
|
||||
return sanitize_title( $slug );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Post_Statuses_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to access post statuses via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Post_Statuses_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = 'wp/v2';
|
||||
$this->rest_base = 'statuses';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<status>[\w-]+)', array(
|
||||
'args' => array(
|
||||
'status' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the status.' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given request has permission to read post statuses.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|bool True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
if ( 'edit' === $request['context'] ) {
|
||||
$types = get_post_types( array( 'show_in_rest' => true ), 'objects' );
|
||||
|
||||
foreach ( $types as $type ) {
|
||||
if ( current_user_can( $type->cap->edit_posts ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all post statuses, depending on user context.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$data = array();
|
||||
$statuses = get_post_stati( array( 'internal' => false ), 'object' );
|
||||
$statuses['trash'] = get_post_status_object( 'trash' );
|
||||
|
||||
foreach ( $statuses as $slug => $obj ) {
|
||||
$ret = $this->check_read_permission( $obj );
|
||||
|
||||
if ( ! $ret ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = $this->prepare_item_for_response( $obj, $request );
|
||||
$data[ $obj->name ] = $this->prepare_response_for_collection( $status );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to read a post status.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @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 ) {
|
||||
$status = get_post_status_object( $request['status'] );
|
||||
|
||||
if ( empty( $status ) ) {
|
||||
return new WP_Error( 'rest_status_invalid', __( 'Invalid status.' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$check = $this->check_read_permission( $status );
|
||||
|
||||
if ( ! $check ) {
|
||||
return new WP_Error( 'rest_cannot_read_status', __( 'Cannot view status.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given post status should be visible.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param object $status Post status.
|
||||
* @return bool True if the post status is visible, otherwise false.
|
||||
*/
|
||||
protected function check_read_permission( $status ) {
|
||||
if ( true === $status->public ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( false === $status->internal || 'trash' === $status->name ) {
|
||||
$types = get_post_types( array( 'show_in_rest' => true ), 'objects' );
|
||||
|
||||
foreach ( $types as $type ) {
|
||||
if ( current_user_can( $type->cap->edit_posts ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific post status.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$obj = get_post_status_object( $request['status'] );
|
||||
|
||||
if ( empty( $obj ) ) {
|
||||
return new WP_Error( 'rest_status_invalid', __( 'Invalid status.' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$data = $this->prepare_item_for_response( $obj, $request );
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a post status object for serialization.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param stdClass $status Post status data.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response Post status data.
|
||||
*/
|
||||
public function prepare_item_for_response( $status, $request ) {
|
||||
|
||||
$data = array(
|
||||
'name' => $status->label,
|
||||
'private' => (bool) $status->private,
|
||||
'protected' => (bool) $status->protected,
|
||||
'public' => (bool) $status->public,
|
||||
'queryable' => (bool) $status->publicly_queryable,
|
||||
'show_in_list' => (bool) $status->show_in_admin_all_list,
|
||||
'slug' => $status->name,
|
||||
);
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
if ( 'publish' === $status->name ) {
|
||||
$response->add_link( 'archives', rest_url( 'wp/v2/posts' ) );
|
||||
} else {
|
||||
$response->add_link( 'archives', add_query_arg( 'status', $status->name, rest_url( 'wp/v2/posts' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a status returned from the REST API.
|
||||
*
|
||||
* Allows modification of the status data right before it is returned.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param object $status The original status object.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_status', $response, $status, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the post status' schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'status',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'name' => array(
|
||||
'description' => __( 'The title for the status.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'embed', 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'private' => array(
|
||||
'description' => __( 'Whether posts with this status should be private.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'protected' => array(
|
||||
'description' => __( 'Whether posts with this status should be protected.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'public' => array(
|
||||
'description' => __( 'Whether posts of this status should be shown in the front end of the site.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'queryable' => array(
|
||||
'description' => __( 'Whether posts with this status should be publicly-queryable.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'show_in_list' => array(
|
||||
'description' => __( 'Whether to include posts in the edit listing for their post type.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'slug' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the status.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'embed', 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Post_Types_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class to access post types via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Post_Types_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = 'wp/v2';
|
||||
$this->rest_base = 'types';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<type>[\w-]+)', array(
|
||||
'args' => array(
|
||||
'type' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the post type.' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given request has permission to read types.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|true True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
if ( 'edit' === $request['context'] ) {
|
||||
foreach ( get_post_types( array(), 'object' ) as $post_type ) {
|
||||
if ( ! empty( $post_type->show_in_rest ) && current_user_can( $post_type->cap->edit_posts ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all public post types.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$data = array();
|
||||
|
||||
foreach ( get_post_types( array(), 'object' ) as $obj ) {
|
||||
if ( empty( $obj->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $obj->cap->edit_posts ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$post_type = $this->prepare_item_for_response( $obj, $request );
|
||||
$data[ $obj->name ] = $this->prepare_response_for_collection( $post_type );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific post type.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$obj = get_post_type_object( $request['type'] );
|
||||
|
||||
if ( empty( $obj ) ) {
|
||||
return new WP_Error( 'rest_type_invalid', __( 'Invalid post type.' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
if ( empty( $obj->show_in_rest ) ) {
|
||||
return new WP_Error( 'rest_cannot_read_type', __( 'Cannot view post type.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
if ( 'edit' === $request['context'] && ! current_user_can( $obj->cap->edit_posts ) ) {
|
||||
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
$data = $this->prepare_item_for_response( $obj, $request );
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a post type object for serialization.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param stdClass $post_type Post type data.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $post_type, $request ) {
|
||||
$taxonomies = wp_list_filter( get_object_taxonomies( $post_type->name, 'objects' ), array( 'show_in_rest' => true ) );
|
||||
$taxonomies = wp_list_pluck( $taxonomies, 'name' );
|
||||
$base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name;
|
||||
$supports = get_all_post_type_supports( $post_type->name );
|
||||
|
||||
$data = array(
|
||||
'capabilities' => $post_type->cap,
|
||||
'description' => $post_type->description,
|
||||
'hierarchical' => $post_type->hierarchical,
|
||||
'viewable' => is_post_type_viewable( $post_type ),
|
||||
'labels' => $post_type->labels,
|
||||
'name' => $post_type->label,
|
||||
'slug' => $post_type->name,
|
||||
'supports' => $supports,
|
||||
'taxonomies' => array_values( $taxonomies ),
|
||||
'rest_base' => $base,
|
||||
);
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
// Wrap the data in a response object.
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
$response->add_links( array(
|
||||
'collection' => array(
|
||||
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
|
||||
),
|
||||
'https://api.w.org/items' => array(
|
||||
'href' => rest_url( sprintf( 'wp/v2/%s', $base ) ),
|
||||
),
|
||||
) );
|
||||
|
||||
/**
|
||||
* Filters a post type returned from the API.
|
||||
*
|
||||
* Allows modification of the post type data right before it is returned.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param object $item The original post type object.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_post_type', $response, $post_type, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the post type's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'type',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'capabilities' => array(
|
||||
'description' => __( 'All capabilities used by the post type.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'description' => __( 'A human-readable description of the post type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'hierarchical' => array(
|
||||
'description' => __( 'Whether or not the post type should have children.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'viewable' => array(
|
||||
'description' => __( 'Whether or not the post type can be viewed.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'labels' => array(
|
||||
'description' => __( 'Human-readable labels for the post type for various contexts.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => __( 'The title for the post type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'slug' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the post type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'supports' => array(
|
||||
'description' => __( 'All features, supported by the post type.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'taxonomies' => array(
|
||||
'description' => __( 'Taxonomies associated with post type.' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'rest_base' => array(
|
||||
'description' => __( 'REST base route for the post type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,566 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Revisions_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to access revisions via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Revisions_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Parent post type.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @var string
|
||||
*/
|
||||
private $parent_post_type;
|
||||
|
||||
/**
|
||||
* Parent controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @var WP_REST_Controller
|
||||
*/
|
||||
private $parent_controller;
|
||||
|
||||
/**
|
||||
* The base of the parent controller's route.
|
||||
*
|
||||
* @since 4.7.0
|
||||
* @var string
|
||||
*/
|
||||
private $parent_base;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param string $parent_post_type Post type of the parent.
|
||||
*/
|
||||
public function __construct( $parent_post_type ) {
|
||||
$this->parent_post_type = $parent_post_type;
|
||||
$this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
|
||||
$this->namespace = 'wp/v2';
|
||||
$this->rest_base = 'revisions';
|
||||
$post_type_object = get_post_type_object( $parent_post_type );
|
||||
$this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers routes for revisions based on post types supporting revisions.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base, array(
|
||||
'args' => array(
|
||||
'parent' => array(
|
||||
'description' => __( 'The ID for the parent of the object.' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', array(
|
||||
'args' => array(
|
||||
'parent' => array(
|
||||
'description' => __( 'The ID for the parent of the object.' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the object.' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => false,
|
||||
'description' => __( 'Required to be true, as revisions do not support trashing.' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent post, if the ID is valid.
|
||||
*
|
||||
* @since 4.7.2
|
||||
*
|
||||
* @param int $id Supplied ID.
|
||||
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
|
||||
*/
|
||||
protected function get_parent( $parent ) {
|
||||
$error = new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent ID.' ), array( 'status' => 404 ) );
|
||||
if ( (int) $parent <= 0 ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$parent = get_post( (int) $parent );
|
||||
if ( empty( $parent ) || empty( $parent->ID ) || $this->parent_post_type !== $parent->post_type ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to get revisions.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
if ( is_wp_error( $parent ) ) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$parent_post_type_obj = get_post_type_object( $parent->post_type );
|
||||
if ( ! current_user_can( $parent_post_type_obj->cap->edit_post, $parent->ID ) ) {
|
||||
return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to view revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the revision, if the ID is valid.
|
||||
*
|
||||
* @since 4.7.2
|
||||
*
|
||||
* @param int $id Supplied ID.
|
||||
* @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise.
|
||||
*/
|
||||
protected function get_revision( $id ) {
|
||||
$error = new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision ID.' ), array( 'status' => 404 ) );
|
||||
if ( (int) $id <= 0 ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$revision = get_post( (int) $id );
|
||||
if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection of revisions.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
if ( is_wp_error( $parent ) ) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$revisions = wp_get_post_revisions( $request['parent'] );
|
||||
|
||||
$response = array();
|
||||
foreach ( $revisions as $revision ) {
|
||||
$data = $this->prepare_item_for_response( $revision, $request );
|
||||
$response[] = $this->prepare_response_for_collection( $data );
|
||||
}
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to get a specific revision.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return bool|WP_Error True if the request has read access for the item, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return $this->get_items_permissions_check( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves one revision from the collection.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
if ( is_wp_error( $parent ) ) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$revision = $this->get_revision( $request['id'] );
|
||||
if ( is_wp_error( $revision ) ) {
|
||||
return $revision;
|
||||
}
|
||||
|
||||
$response = $this->prepare_item_for_response( $revision, $request );
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to delete a revision.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return bool|WP_Error True if the request has access to delete the item, WP_Error object otherwise.
|
||||
*/
|
||||
public function delete_item_permissions_check( $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
if ( is_wp_error( $parent ) ) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$revision = $this->get_revision( $request['id'] );
|
||||
if ( is_wp_error( $revision ) ) {
|
||||
return $revision;
|
||||
}
|
||||
|
||||
$response = $this->get_items_permissions_check( $request );
|
||||
if ( ! $response || is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$post_type = get_post_type_object( 'revision' );
|
||||
return current_user_can( $post_type->cap->delete_post, $revision->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single revision.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function delete_item( $request ) {
|
||||
$revision = $this->get_revision( $request['id'] );
|
||||
if ( is_wp_error( $revision ) ) {
|
||||
return $revision;
|
||||
}
|
||||
|
||||
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
|
||||
|
||||
// We don't support trashing for revisions.
|
||||
if ( ! $force ) {
|
||||
/* translators: %s: force=true */
|
||||
return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) );
|
||||
}
|
||||
|
||||
$previous = $this->prepare_item_for_response( $revision, $request );
|
||||
|
||||
$result = wp_delete_post( $request['id'], true );
|
||||
|
||||
/**
|
||||
* Fires after a revision is deleted via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param (mixed) $result The revision object (if it was deleted or moved to the trash successfully)
|
||||
* or false (failure). If the revision was moved to the trash, $result represents
|
||||
* its new state; if it was deleted, $result represents its state before deletion.
|
||||
* @param WP_REST_Request $request The request sent to the API.
|
||||
*/
|
||||
do_action( 'rest_delete_revision', $result, $request );
|
||||
|
||||
if ( ! $result ) {
|
||||
return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) );
|
||||
}
|
||||
|
||||
$response = new WP_REST_Response();
|
||||
$response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the revision for the REST response.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_Post $post Post revision object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $post, $request ) {
|
||||
$GLOBALS['post'] = $post;
|
||||
|
||||
setup_postdata( $post );
|
||||
|
||||
$schema = $this->get_item_schema();
|
||||
|
||||
$data = array();
|
||||
|
||||
if ( ! empty( $schema['properties']['author'] ) ) {
|
||||
$data['author'] = (int) $post->post_author;
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['date'] ) ) {
|
||||
$data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date );
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['date_gmt'] ) ) {
|
||||
$data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt );
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['id'] ) ) {
|
||||
$data['id'] = $post->ID;
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['modified'] ) ) {
|
||||
$data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified );
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['modified_gmt'] ) ) {
|
||||
$data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt );
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['parent'] ) ) {
|
||||
$data['parent'] = (int) $post->post_parent;
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['slug'] ) ) {
|
||||
$data['slug'] = $post->post_name;
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['guid'] ) ) {
|
||||
$data['guid'] = array(
|
||||
/** This filter is documented in wp-includes/post-template.php */
|
||||
'rendered' => apply_filters( 'get_the_guid', $post->guid, $post->ID ),
|
||||
'raw' => $post->guid,
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['title'] ) ) {
|
||||
$data['title'] = array(
|
||||
'raw' => $post->post_title,
|
||||
'rendered' => get_the_title( $post->ID ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['content'] ) ) {
|
||||
|
||||
$data['content'] = array(
|
||||
'raw' => $post->post_content,
|
||||
/** This filter is documented in wp-includes/post-template.php */
|
||||
'rendered' => apply_filters( 'the_content', $post->post_content ),
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $schema['properties']['excerpt'] ) ) {
|
||||
$data['excerpt'] = array(
|
||||
'raw' => $post->post_excerpt,
|
||||
'rendered' => $this->prepare_excerpt_response( $post->post_excerpt, $post ),
|
||||
);
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
if ( ! empty( $data['parent'] ) ) {
|
||||
$response->add_link( 'parent', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->parent_base, $data['parent'] ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a revision returned from the API.
|
||||
*
|
||||
* Allows modification of the revision right before it is returned.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Post $post The original revision object.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_revision', $response, $post, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the post_date_gmt or modified_gmt and prepare any post or
|
||||
* modified date for single post output.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param string $date_gmt GMT publication time.
|
||||
* @param string|null $date Optional. Local publication time. Default null.
|
||||
* @return string|null ISO8601/RFC3339 formatted datetime, otherwise null.
|
||||
*/
|
||||
protected function prepare_date_response( $date_gmt, $date = null ) {
|
||||
if ( '0000-00-00 00:00:00' === $date_gmt ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( isset( $date ) ) {
|
||||
return mysql_to_rfc3339( $date );
|
||||
}
|
||||
|
||||
return mysql_to_rfc3339( $date_gmt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the revision's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => "{$this->parent_post_type}-revision",
|
||||
'type' => 'object',
|
||||
// Base properties for every Revision.
|
||||
'properties' => array(
|
||||
'author' => array(
|
||||
'description' => __( 'The ID for the author of the object.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'date' => array(
|
||||
'description' => __( "The date the object was published, in the site's timezone." ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'date_gmt' => array(
|
||||
'description' => __( 'The date the object was published, as GMT.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'guid' => array(
|
||||
'description' => __( 'GUID for the object, as it exists in the database.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the object.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'modified' => array(
|
||||
'description' => __( "The date the object was last modified, in the site's timezone." ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'modified_gmt' => array(
|
||||
'description' => __( 'The date the object was last modified, as GMT.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'parent' => array(
|
||||
'description' => __( 'The ID for the parent of the object.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'slug' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the object unique to its type.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$parent_schema = $this->parent_controller->get_item_schema();
|
||||
|
||||
if ( ! empty( $parent_schema['properties']['title'] ) ) {
|
||||
$schema['properties']['title'] = $parent_schema['properties']['title'];
|
||||
}
|
||||
|
||||
if ( ! empty( $parent_schema['properties']['content'] ) ) {
|
||||
$schema['properties']['content'] = $parent_schema['properties']['content'];
|
||||
}
|
||||
|
||||
if ( ! empty( $parent_schema['properties']['excerpt'] ) ) {
|
||||
$schema['properties']['excerpt'] = $parent_schema['properties']['excerpt'];
|
||||
}
|
||||
|
||||
if ( ! empty( $parent_schema['properties']['guid'] ) ) {
|
||||
$schema['properties']['guid'] = $parent_schema['properties']['guid'];
|
||||
}
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the post excerpt and prepare it for single post output.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param string $excerpt The post excerpt.
|
||||
* @param WP_Post $post Post revision object.
|
||||
* @return string Prepared excerpt or empty string.
|
||||
*/
|
||||
protected function prepare_excerpt_response( $excerpt, $post ) {
|
||||
|
||||
/** This filter is documented in wp-includes/post-template.php */
|
||||
$excerpt = apply_filters( 'the_excerpt', $excerpt, $post );
|
||||
|
||||
if ( empty( $excerpt ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Settings_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to manage a site's settings via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Settings_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = 'wp/v2';
|
||||
$this->rest_base = 'settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'args' => array(),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_item' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to read and manage settings.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return bool True if the request has read access for the item, otherwise false.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the settings.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return array|WP_Error Array on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$options = $this->get_registered_options();
|
||||
$response = array();
|
||||
|
||||
foreach ( $options as $name => $args ) {
|
||||
/**
|
||||
* Filters the value of a setting recognized by the REST API.
|
||||
*
|
||||
* Allow hijacking the setting value and overriding the built-in behavior by returning a
|
||||
* non-null value. The returned value will be presented as the setting value instead.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param mixed $result Value to use for the requested setting. Can be a scalar
|
||||
* matching the registered schema for the setting, or null to
|
||||
* follow the default get_option() behavior.
|
||||
* @param string $name Setting name (as shown in REST API responses).
|
||||
* @param array $args Arguments passed to register_setting() for this setting.
|
||||
*/
|
||||
$response[ $name ] = apply_filters( 'rest_pre_get_setting', null, $name, $args );
|
||||
|
||||
if ( is_null( $response[ $name ] ) ) {
|
||||
// Default to a null value as "null" in the response means "not set".
|
||||
$response[ $name ] = get_option( $args['option_name'], $args['schema']['default'] );
|
||||
}
|
||||
|
||||
/*
|
||||
* Because get_option() is lossy, we have to
|
||||
* cast values to the type they are registered with.
|
||||
*/
|
||||
$response[ $name ] = $this->prepare_value( $response[ $name ], $args['schema'] );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a value for output based off a schema array.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param mixed $value Value to prepare.
|
||||
* @param array $schema Schema to match.
|
||||
* @return mixed The prepared value.
|
||||
*/
|
||||
protected function prepare_value( $value, $schema ) {
|
||||
// If the value is not valid by the schema, set the value to null. Null
|
||||
// values are specifcally non-destructive so this will not cause overwriting
|
||||
// the current invalid value to null.
|
||||
if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) {
|
||||
return null;
|
||||
}
|
||||
return rest_sanitize_value_from_schema( $value, $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates settings for the settings object.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return array|WP_Error Array on success, or error object on failure.
|
||||
*/
|
||||
public function update_item( $request ) {
|
||||
$options = $this->get_registered_options();
|
||||
|
||||
$params = $request->get_params();
|
||||
|
||||
foreach ( $options as $name => $args ) {
|
||||
if ( ! array_key_exists( $name, $params ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters whether to preempt a setting value update.
|
||||
*
|
||||
* Allows hijacking the setting update logic and overriding the built-in behavior by
|
||||
* returning true.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param bool $result Whether to override the default behavior for updating the
|
||||
* value of a setting.
|
||||
* @param string $name Setting name (as shown in REST API responses).
|
||||
* @param mixed $value Updated setting value.
|
||||
* @param array $args Arguments passed to register_setting() for this setting.
|
||||
*/
|
||||
$updated = apply_filters( 'rest_pre_update_setting', false, $name, $request[ $name ], $args );
|
||||
|
||||
if ( $updated ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A null value for an option would have the same effect as
|
||||
* deleting the option from the database, and relying on the
|
||||
* default value.
|
||||
*/
|
||||
if ( is_null( $request[ $name ] ) ) {
|
||||
/*
|
||||
* A null value is returned in the response for any option
|
||||
* that has a non-scalar value.
|
||||
*
|
||||
* To protect clients from accidentally including the null
|
||||
* values from a response object in a request, we do not allow
|
||||
* options with values that don't pass validation to be updated to null.
|
||||
* Without this added protection a client could mistakenly
|
||||
* delete all options that have invalid values from the
|
||||
* database.
|
||||
*/
|
||||
if ( is_wp_error( rest_validate_value_from_schema( get_option( $args['option_name'], false ), $args['schema'] ) ) ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_stored_value', sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 )
|
||||
);
|
||||
}
|
||||
|
||||
delete_option( $args['option_name'] );
|
||||
} else {
|
||||
update_option( $args['option_name'], $request[ $name ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->get_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all of the registered options for the Settings API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Array of registered options.
|
||||
*/
|
||||
protected function get_registered_options() {
|
||||
$rest_options = array();
|
||||
|
||||
foreach ( get_registered_settings() as $name => $args ) {
|
||||
if ( empty( $args['show_in_rest'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rest_args = array();
|
||||
|
||||
if ( is_array( $args['show_in_rest'] ) ) {
|
||||
$rest_args = $args['show_in_rest'];
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'name' => ! empty( $rest_args['name'] ) ? $rest_args['name'] : $name,
|
||||
'schema' => array(),
|
||||
);
|
||||
|
||||
$rest_args = array_merge( $defaults, $rest_args );
|
||||
|
||||
$default_schema = array(
|
||||
'type' => empty( $args['type'] ) ? null : $args['type'],
|
||||
'description' => empty( $args['description'] ) ? '' : $args['description'],
|
||||
'default' => isset( $args['default'] ) ? $args['default'] : null,
|
||||
);
|
||||
|
||||
$rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] );
|
||||
$rest_args['option_name'] = $name;
|
||||
|
||||
// Skip over settings that don't have a defined type in the schema.
|
||||
if ( empty( $rest_args['schema']['type'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whitelist the supported types for settings, as we don't want invalid types
|
||||
* to be updated with arbitrary values that we can't do decent sanitizing for.
|
||||
*/
|
||||
if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rest_args['schema'] = $this->set_additional_properties_to_false( $rest_args['schema'] );
|
||||
|
||||
$rest_options[ $rest_args['name'] ] = $rest_args;
|
||||
}
|
||||
|
||||
return $rest_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the site setting schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$options = $this->get_registered_options();
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'settings',
|
||||
'type' => 'object',
|
||||
'properties' => array(),
|
||||
);
|
||||
|
||||
foreach ( $options as $option_name => $option ) {
|
||||
$schema['properties'][ $option_name ] = $option['schema'];
|
||||
$schema['properties'][ $option_name ]['arg_options'] = array(
|
||||
'sanitize_callback' => array( $this, 'sanitize_callback' ),
|
||||
);
|
||||
}
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom sanitize callback used for all options to allow the use of 'null'.
|
||||
*
|
||||
* By default, the schema of settings will throw an error if a value is set to
|
||||
* `null` as it's not a valid value for something like "type => string". We
|
||||
* provide a wrapper sanitizer to whitelist the use of `null`.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param mixed $value The value for the setting.
|
||||
* @param WP_REST_Request $request The request object.
|
||||
* @param string $param The parameter name.
|
||||
* @return mixed|WP_Error
|
||||
*/
|
||||
public function sanitize_callback( $value, $request, $param ) {
|
||||
if ( is_null( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
return rest_parse_request_arg( $value, $request, $param );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively add additionalProperties = false to all objects in a schema.
|
||||
*
|
||||
* This is need to restrict properties of objects in settings values to only
|
||||
* registered items, as the REST API will allow additional properties by
|
||||
* default.
|
||||
*
|
||||
* @since 4.9.0
|
||||
*
|
||||
* @param array $schema The schema array.
|
||||
* @return array
|
||||
*/
|
||||
protected function set_additional_properties_to_false( $schema ) {
|
||||
switch ( $schema['type'] ) {
|
||||
case 'object':
|
||||
foreach ( $schema['properties'] as $key => $child_schema ) {
|
||||
$schema['properties'][ $key ] = $this->set_additional_properties_to_false( $child_schema );
|
||||
}
|
||||
$schema['additionalProperties'] = false;
|
||||
break;
|
||||
case 'array':
|
||||
$schema['items'] = $this->set_additional_properties_to_false( $schema['items'] );
|
||||
break;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Taxonomies_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 4.7.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to manage taxonomies via the REST API.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Taxonomies_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = 'wp/v2';
|
||||
$this->rest_base = 'taxonomies';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<taxonomy>[\w-]+)', array(
|
||||
'args' => array(
|
||||
'taxonomy' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the taxonomy.' ),
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given request has permission to read taxonomies.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
if ( 'edit' === $request['context'] ) {
|
||||
if ( ! empty( $request['type'] ) ) {
|
||||
$taxonomies = get_object_taxonomies( $request['type'], 'objects' );
|
||||
} else {
|
||||
$taxonomies = get_taxonomies( '', 'objects' );
|
||||
}
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( ! empty( $taxonomy->show_in_rest ) && current_user_can( $taxonomy->cap->manage_terms ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to manage terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all public taxonomies.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
|
||||
// Retrieve the list of registered collection query parameters.
|
||||
$registered = $this->get_collection_params();
|
||||
|
||||
if ( isset( $registered['type'] ) && ! empty( $request['type'] ) ) {
|
||||
$taxonomies = get_object_taxonomies( $request['type'], 'objects' );
|
||||
} else {
|
||||
$taxonomies = get_taxonomies( '', 'objects' );
|
||||
}
|
||||
$data = array();
|
||||
foreach ( $taxonomies as $tax_type => $value ) {
|
||||
if ( empty( $value->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $value->cap->manage_terms ) ) ) {
|
||||
continue;
|
||||
}
|
||||
$tax = $this->prepare_item_for_response( $value, $request );
|
||||
$tax = $this->prepare_response_for_collection( $tax );
|
||||
$data[ $tax_type ] = $tax;
|
||||
}
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
// Response should still be returned as a JSON object when it is empty.
|
||||
$data = (object) $data;
|
||||
}
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to a taxonomy.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access for the item, otherwise false or WP_Error object.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
|
||||
$tax_obj = get_taxonomy( $request['taxonomy'] );
|
||||
|
||||
if ( $tax_obj ) {
|
||||
if ( empty( $tax_obj->show_in_rest ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->manage_terms ) ) {
|
||||
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to manage terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a specific taxonomy.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function get_item( $request ) {
|
||||
$tax_obj = get_taxonomy( $request['taxonomy'] );
|
||||
if ( empty( $tax_obj ) ) {
|
||||
return new WP_Error( 'rest_taxonomy_invalid', __( 'Invalid taxonomy.' ), array( 'status' => 404 ) );
|
||||
}
|
||||
$data = $this->prepare_item_for_response( $tax_obj, $request );
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a taxonomy object for serialization.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param stdClass $taxonomy Taxonomy data.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $taxonomy, $request ) {
|
||||
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
|
||||
$data = array(
|
||||
'name' => $taxonomy->label,
|
||||
'slug' => $taxonomy->name,
|
||||
'capabilities' => $taxonomy->cap,
|
||||
'description' => $taxonomy->description,
|
||||
'labels' => $taxonomy->labels,
|
||||
'types' => $taxonomy->object_type,
|
||||
'show_cloud' => $taxonomy->show_tagcloud,
|
||||
'hierarchical' => $taxonomy->hierarchical,
|
||||
'rest_base' => $base,
|
||||
);
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
// Wrap the data in a response object.
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
$response->add_links( array(
|
||||
'collection' => array(
|
||||
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
|
||||
),
|
||||
'https://api.w.org/items' => array(
|
||||
'href' => rest_url( sprintf( 'wp/v2/%s', $base ) ),
|
||||
),
|
||||
) );
|
||||
|
||||
/**
|
||||
* Filters a taxonomy returned from the REST API.
|
||||
*
|
||||
* Allows modification of the taxonomy data right before it is returned.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param object $item The original taxonomy object.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_taxonomy', $response, $taxonomy, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the taxonomy's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'taxonomy',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'capabilities' => array(
|
||||
'description' => __( 'All capabilities used by the taxonomy.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'description' => __( 'A human-readable description of the taxonomy.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'hierarchical' => array(
|
||||
'description' => __( 'Whether or not the taxonomy should have children.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'labels' => array(
|
||||
'description' => __( 'Human-readable labels for the taxonomy for various contexts.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => __( 'The title for the taxonomy.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'slug' => array(
|
||||
'description' => __( 'An alphanumeric identifier for the taxonomy.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'show_cloud' => array(
|
||||
'description' => __( 'Whether or not the term cloud should be displayed.' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'types' => array(
|
||||
'description' => __( 'Types associated with the taxonomy.' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'rest_base' => array(
|
||||
'description' => __( 'REST base route for the taxonomy.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections.
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$new_params = array();
|
||||
$new_params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
|
||||
$new_params['type'] = array(
|
||||
'description' => __( 'Limit results to taxonomies associated with a specific post type.' ),
|
||||
'type' => 'string',
|
||||
);
|
||||
return $new_params;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user