rebase on oct-10-2023
This commit is contained in:
@@ -311,7 +311,7 @@ class WP_REST_Request implements ArrayAccess {
|
||||
}
|
||||
|
||||
$value = strtolower( $value );
|
||||
if ( false === strpos( $value, '/' ) ) {
|
||||
if ( ! str_contains( $value, '/' ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -473,8 +473,10 @@ class WP_REST_Request implements ArrayAccess {
|
||||
|
||||
$params = array();
|
||||
foreach ( $order as $type ) {
|
||||
// array_merge() / the "+" operator will mess up
|
||||
// numeric keys, so instead do a manual foreach.
|
||||
/*
|
||||
* array_merge() / the "+" operator will mess up
|
||||
* numeric keys, so instead do a manual foreach.
|
||||
*/
|
||||
foreach ( (array) $this->params[ $type ] as $key => $value ) {
|
||||
$params[ $key ] = $value;
|
||||
}
|
||||
@@ -1031,7 +1033,7 @@ class WP_REST_Request implements ArrayAccess {
|
||||
}
|
||||
|
||||
$api_root = rest_url();
|
||||
if ( get_option( 'permalink_structure' ) && 0 === strpos( $url, $api_root ) ) {
|
||||
if ( get_option( 'permalink_structure' ) && str_starts_with( $url, $api_root ) ) {
|
||||
// Pretty permalinks on, and URL is under the API root.
|
||||
$api_url_part = substr( $url, strlen( untrailingslashit( $api_root ) ) );
|
||||
$route = parse_url( $api_url_part, PHP_URL_PATH );
|
||||
|
||||
@@ -158,8 +158,8 @@ class WP_REST_Server {
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @return WP_Error|null WP_Error indicates unsuccessful login, null indicates successful
|
||||
* or no authentication provided
|
||||
* @return WP_Error|null|true WP_Error indicates unsuccessful login, null indicates successful
|
||||
* or no authentication provided
|
||||
*/
|
||||
public function check_authentication() {
|
||||
/**
|
||||
@@ -321,42 +321,6 @@ class WP_REST_Server {
|
||||
* https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/
|
||||
*/
|
||||
$this->send_header( 'X-Content-Type-Options', 'nosniff' );
|
||||
$expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' );
|
||||
|
||||
/**
|
||||
* Filters the list of response headers that are exposed to REST API CORS requests.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param string[] $expose_headers The list of response headers to expose.
|
||||
*/
|
||||
$expose_headers = apply_filters( 'rest_exposed_cors_headers', $expose_headers );
|
||||
|
||||
$this->send_header( 'Access-Control-Expose-Headers', implode( ', ', $expose_headers ) );
|
||||
|
||||
$allow_headers = array(
|
||||
'Authorization',
|
||||
'X-WP-Nonce',
|
||||
'Content-Disposition',
|
||||
'Content-MD5',
|
||||
'Content-Type',
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters the list of request headers that are allowed for REST API CORS requests.
|
||||
*
|
||||
* The allowed headers are passed to the browser to specify which
|
||||
* headers can be passed to the REST API. By default, we allow the
|
||||
* Content-* headers needed to upload files to the media endpoints.
|
||||
* As well as the Authorization and Nonce headers for allowing authentication.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param string[] $allow_headers The list of request headers to allow.
|
||||
*/
|
||||
$allow_headers = apply_filters( 'rest_allowed_cors_headers', $allow_headers );
|
||||
|
||||
$this->send_header( 'Access-Control-Allow-Headers', implode( ', ', $allow_headers ) );
|
||||
|
||||
/**
|
||||
* Filters whether to send nocache headers on a REST API request.
|
||||
@@ -436,6 +400,47 @@ class WP_REST_Server {
|
||||
$request->set_method( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] );
|
||||
}
|
||||
|
||||
$expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' );
|
||||
|
||||
/**
|
||||
* Filters the list of response headers that are exposed to REST API CORS requests.
|
||||
*
|
||||
* @since 5.5.0
|
||||
* @since 6.3.0 The `$request` parameter was added.
|
||||
*
|
||||
* @param string[] $expose_headers The list of response headers to expose.
|
||||
* @param WP_REST_Request $request The request in context.
|
||||
*/
|
||||
$expose_headers = apply_filters( 'rest_exposed_cors_headers', $expose_headers, $request );
|
||||
|
||||
$this->send_header( 'Access-Control-Expose-Headers', implode( ', ', $expose_headers ) );
|
||||
|
||||
$allow_headers = array(
|
||||
'Authorization',
|
||||
'X-WP-Nonce',
|
||||
'Content-Disposition',
|
||||
'Content-MD5',
|
||||
'Content-Type',
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters the list of request headers that are allowed for REST API CORS requests.
|
||||
*
|
||||
* The allowed headers are passed to the browser to specify which
|
||||
* headers can be passed to the REST API. By default, we allow the
|
||||
* Content-* headers needed to upload files to the media endpoints.
|
||||
* As well as the Authorization and Nonce headers for allowing authentication.
|
||||
*
|
||||
* @since 5.5.0
|
||||
* @since 6.3.0 The `$request` parameter was added.
|
||||
*
|
||||
* @param string[] $allow_headers The list of request headers to allow.
|
||||
* @param WP_REST_Request $request The request in context.
|
||||
*/
|
||||
$allow_headers = apply_filters( 'rest_allowed_cors_headers', $allow_headers, $request );
|
||||
|
||||
$this->send_header( 'Access-Control-Allow-Headers', implode( ', ', $allow_headers ) );
|
||||
|
||||
$result = $this->check_authentication();
|
||||
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
@@ -648,7 +653,7 @@ class WP_REST_Server {
|
||||
// Convert $rel URIs to their compact versions if they exist.
|
||||
foreach ( $curies as $curie ) {
|
||||
$href_prefix = substr( $curie['href'], 0, strpos( $curie['href'], '{rel}' ) );
|
||||
if ( strpos( $rel, $href_prefix ) !== 0 ) {
|
||||
if ( ! str_starts_with( $rel, $href_prefix ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -696,8 +701,10 @@ class WP_REST_Server {
|
||||
$embedded = array();
|
||||
|
||||
foreach ( $data['_links'] as $rel => $links ) {
|
||||
// If a list of relations was specified, and the link relation
|
||||
// is not in the list of allowed relations, don't process the link.
|
||||
/*
|
||||
* If a list of relations was specified, and the link relation
|
||||
* is not in the list of allowed relations, don't process the link.
|
||||
*/
|
||||
if ( is_array( $embed ) && ! in_array( $rel, $embed, true ) ) {
|
||||
continue;
|
||||
}
|
||||
@@ -1044,7 +1051,7 @@ class WP_REST_Server {
|
||||
$with_namespace = array();
|
||||
|
||||
foreach ( $this->get_namespaces() as $namespace ) {
|
||||
if ( 0 === strpos( trailingslashit( ltrim( $path, '/' ) ), $namespace ) ) {
|
||||
if ( str_starts_with( trailingslashit( ltrim( $path, '/' ) ), $namespace ) ) {
|
||||
$with_namespace[] = $this->get_routes( $namespace );
|
||||
}
|
||||
}
|
||||
@@ -1538,7 +1545,7 @@ class WP_REST_Server {
|
||||
$data['endpoints'][] = $endpoint_data;
|
||||
|
||||
// For non-variable routes, generate links.
|
||||
if ( strpos( $route, '{' ) === false ) {
|
||||
if ( ! str_contains( $route, '{' ) ) {
|
||||
$data['_links'] = array(
|
||||
'self' => array(
|
||||
array(
|
||||
@@ -1827,7 +1834,7 @@ class WP_REST_Server {
|
||||
);
|
||||
|
||||
foreach ( $server as $key => $value ) {
|
||||
if ( strpos( $key, 'HTTP_' ) === 0 ) {
|
||||
if ( str_starts_with( $key, 'HTTP_' ) ) {
|
||||
$headers[ substr( $key, 5 ) ] = $value;
|
||||
} elseif ( 'REDIRECT_HTTP_AUTHORIZATION' === $key && empty( $server['HTTP_AUTHORIZATION'] ) ) {
|
||||
/*
|
||||
|
||||
@@ -202,8 +202,10 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
wp_after_insert_post( $attachment, false, null );
|
||||
|
||||
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
|
||||
// Set a custom header with the attachment_id.
|
||||
// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
|
||||
/*
|
||||
* Set a custom header with the attachment_id.
|
||||
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
|
||||
*/
|
||||
header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
|
||||
}
|
||||
|
||||
@@ -211,8 +213,10 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
|
||||
// Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta.
|
||||
// At this point the server may run out of resources and post-processing of uploaded images may fail.
|
||||
/*
|
||||
* Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta.
|
||||
* At this point the server may run out of resources and post-processing of uploaded images may fail.
|
||||
*/
|
||||
wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
|
||||
|
||||
$response = $this->prepare_item_for_response( $attachment, $request );
|
||||
@@ -562,8 +566,10 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
$image_ext = pathinfo( $image_file, PATHINFO_EXTENSION );
|
||||
$image_name = wp_basename( $image_file, ".{$image_ext}" );
|
||||
|
||||
// Do not append multiple `-edited` to the file name.
|
||||
// The user may be editing a previously edited image.
|
||||
/*
|
||||
* Do not append multiple `-edited` to the file name.
|
||||
* The user may be editing a previously edited image.
|
||||
*/
|
||||
if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) {
|
||||
// Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number.
|
||||
$image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name );
|
||||
@@ -625,8 +631,10 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
}
|
||||
|
||||
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
|
||||
// Set a custom header with the attachment_id.
|
||||
// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
|
||||
/*
|
||||
* Set a custom header with the attachment_id.
|
||||
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
|
||||
*/
|
||||
header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id );
|
||||
}
|
||||
|
||||
@@ -968,8 +976,8 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
*
|
||||
* @since 4.7.0
|
||||
*
|
||||
* @param array $data Supplied file data.
|
||||
* @param array $headers HTTP headers from the request.
|
||||
* @param string $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 ) {
|
||||
@@ -1111,7 +1119,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
foreach ( $disposition_header as $value ) {
|
||||
$value = trim( $value );
|
||||
|
||||
if ( strpos( $value, ';' ) === false ) {
|
||||
if ( ! str_contains( $value, ';' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1121,7 +1129,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
$attributes = array();
|
||||
|
||||
foreach ( $attr_parts as $part ) {
|
||||
if ( strpos( $part, '=' ) === false ) {
|
||||
if ( ! str_contains( $part, '=' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1137,7 +1145,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
||||
$filename = trim( $attributes['filename'] );
|
||||
|
||||
// Unquote quoted filename, but after trimming.
|
||||
if ( substr( $filename, 0, 1 ) === '"' && substr( $filename, -1, 1 ) === '"' ) {
|
||||
if ( str_starts_with( $filename, '"' ) && str_ends_with( $filename, '"' ) ) {
|
||||
$filename = substr( $filename, 1, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
|
||||
$this->parent_controller = $parent_controller;
|
||||
$this->revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type );
|
||||
$this->rest_base = 'autosaves';
|
||||
$this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
|
||||
$this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name;
|
||||
$this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,8 +229,10 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
|
||||
$is_draft = 'draft' === $post->post_status || 'auto-draft' === $post->post_status;
|
||||
|
||||
if ( $is_draft && (int) $post->post_author === $user_id && ! $post_lock ) {
|
||||
// Draft posts for the same author: autosaving updates the post and does not create a revision.
|
||||
// Convert the post object to an array and add slashes, wp_update_post() expects escaped array.
|
||||
/*
|
||||
* Draft posts for the same author: autosaving updates the post and does not create a revision.
|
||||
* Convert the post object to an array and add slashes, wp_update_post() expects escaped array.
|
||||
*/
|
||||
$autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true );
|
||||
} else {
|
||||
// Non-draft posts: create or update the post autosave.
|
||||
@@ -304,7 +306,7 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
|
||||
$revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) );
|
||||
|
||||
foreach ( $revisions as $revision ) {
|
||||
if ( false !== strpos( $revision->post_name, "{$parent_id}-autosave" ) ) {
|
||||
if ( str_contains( $revision->post_name, "{$parent_id}-autosave" ) ) {
|
||||
$data = $this->prepare_item_for_response( $revision, $request );
|
||||
$response[] = $this->prepare_response_for_collection( $data );
|
||||
}
|
||||
@@ -371,19 +373,16 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $autosave_is_different ) {
|
||||
return new WP_Error(
|
||||
'rest_autosave_no_changes',
|
||||
__( 'There is nothing to save. The autosave and the post content are the same.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
// Store one autosave per author. If there is already an autosave, overwrite it.
|
||||
$old_autosave = wp_get_post_autosave( $post_id, $user_id );
|
||||
|
||||
if ( ! $autosave_is_different && $old_autosave ) {
|
||||
// Nothing to save, return the existing autosave.
|
||||
return $old_autosave->ID;
|
||||
}
|
||||
|
||||
if ( $old_autosave ) {
|
||||
$new_autosave['ID'] = $old_autosave->ID;
|
||||
$new_autosave['post_author'] = $user_id;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Block_Pattern_Catergories_Controller class
|
||||
* REST API: WP_REST_Block_Pattern_Categories_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
@@ -125,6 +125,10 @@ class WP_REST_Block_Pattern_Categories_Controller extends WP_REST_Controller {
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'block-pattern-category',
|
||||
@@ -151,6 +155,8 @@ class WP_REST_Block_Pattern_Categories_Controller extends WP_REST_Controller {
|
||||
),
|
||||
);
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller {
|
||||
* Prepare a raw block pattern before it gets output in a REST API response.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @since 6.3.0 Added `source` property.
|
||||
*
|
||||
* @param array $item Raw pattern as registered, before any changes.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
@@ -174,6 +175,7 @@ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller {
|
||||
'blockTypes' => 'block_types',
|
||||
'postTypes' => 'post_types',
|
||||
'templateTypes' => 'template_types',
|
||||
'source' => 'source',
|
||||
);
|
||||
$data = array();
|
||||
foreach ( $keys as $item_key => $rest_key ) {
|
||||
@@ -192,10 +194,15 @@ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller {
|
||||
* Retrieves the block pattern schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @since 6.3.0 Added `source` property.
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'block-pattern',
|
||||
@@ -267,9 +274,25 @@ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller {
|
||||
'readonly' => true,
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'source' => array(
|
||||
'description' => __( 'Where the pattern comes from e.g. core' ),
|
||||
'type' => 'string',
|
||||
'readonly' => true,
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'enum' => array(
|
||||
'core',
|
||||
'plugin',
|
||||
'theme',
|
||||
'pattern-directory/core',
|
||||
'pattern-directory/theme',
|
||||
'pattern-directory/featured',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller {
|
||||
*
|
||||
* @since 5.5.0
|
||||
* @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support.
|
||||
* @since 6.3.0 Added `selectors` field.
|
||||
*
|
||||
* @param WP_Block_Type $item Block type data.
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
@@ -278,6 +279,7 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller {
|
||||
'ancestor',
|
||||
'provides_context',
|
||||
'uses_context',
|
||||
'selectors',
|
||||
'supports',
|
||||
'styles',
|
||||
'textdomain',
|
||||
@@ -379,6 +381,7 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller {
|
||||
* Retrieves the block type' schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 5.5.0
|
||||
* @since 6.3.0 Added `selectors` field.
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
@@ -518,6 +521,14 @@ class WP_REST_Block_Types_Controller extends WP_REST_Controller {
|
||||
'context' => array( 'embed', 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'selectors' => array(
|
||||
'description' => __( 'Custom CSS selectors.' ),
|
||||
'type' => 'object',
|
||||
'default' => array(),
|
||||
'properties' => array(),
|
||||
'context' => array( 'embed', 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'supports' => array(
|
||||
'description' => __( 'Block supports.' ),
|
||||
'type' => 'object',
|
||||
|
||||
@@ -40,6 +40,7 @@ class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
|
||||
* Filters a response based on the context defined in the schema.
|
||||
*
|
||||
* @since 5.0.0
|
||||
* @since 6.3.0 Adds the `wp_pattern_sync_status` postmeta property to the top level of response.
|
||||
*
|
||||
* @param array $data Response data to filter.
|
||||
* @param string $context Context defined in the schema.
|
||||
@@ -56,6 +57,9 @@ class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
|
||||
unset( $data['title']['rendered'] );
|
||||
unset( $data['content']['rendered'] );
|
||||
|
||||
// Add the core wp_pattern_sync_status meta as top level property to the response.
|
||||
$data['wp_pattern_sync_status'] = isset( $data['meta']['wp_pattern_sync_status'] ) ? $data['meta']['wp_pattern_sync_status'] : '';
|
||||
unset( $data['meta']['wp_pattern_sync_status'] );
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -67,6 +71,10 @@ class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
// Do not cache this schema because all properties are derived from parent controller.
|
||||
$schema = parent::get_item_schema();
|
||||
|
||||
@@ -86,7 +94,9 @@ class WP_REST_Blocks_Controller extends WP_REST_Posts_Controller {
|
||||
unset( $schema['properties']['title']['properties']['rendered'] );
|
||||
unset( $schema['properties']['content']['properties']['rendered'] );
|
||||
|
||||
return $schema;
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1761,8 +1761,10 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
||||
|
||||
$posts_controller = $post_type->get_rest_controller();
|
||||
|
||||
// Ensure the posts controller is specifically a WP_REST_Posts_Controller instance
|
||||
// before using methods specific to that controller.
|
||||
/*
|
||||
* Ensure the posts controller is specifically a WP_REST_Posts_Controller instance
|
||||
* before using methods specific to that controller.
|
||||
*/
|
||||
if ( ! $posts_controller instanceof WP_REST_Posts_Controller ) {
|
||||
$posts_controller = new WP_REST_Posts_Controller( $post->post_type );
|
||||
}
|
||||
|
||||
@@ -576,8 +576,10 @@ abstract class WP_REST_Controller {
|
||||
$additional_fields = $this->get_additional_fields();
|
||||
|
||||
foreach ( $additional_fields as $field_name => $field_options ) {
|
||||
// For back-compat, include any field with an empty schema
|
||||
// because it won't be present in $this->get_item_schema().
|
||||
/*
|
||||
* For back-compat, include any field with an empty schema
|
||||
* because it won't be present in $this->get_item_schema().
|
||||
*/
|
||||
if ( is_null( $field_options['schema'] ) ) {
|
||||
$properties[ $field_name ] = $field_options;
|
||||
}
|
||||
@@ -630,8 +632,10 @@ abstract class WP_REST_Controller {
|
||||
}
|
||||
// Check for nested fields if $field is not a direct match.
|
||||
$nested_fields = explode( '.', $field );
|
||||
// A nested field is included so long as its top-level property
|
||||
// is present in the schema.
|
||||
/*
|
||||
* A nested field is included so long as its top-level property
|
||||
* is present in the schema.
|
||||
*/
|
||||
if ( in_array( $nested_fields[0], $fields, true ) ) {
|
||||
$response_fields[] = $field;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
* Registers the controllers routes.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
@@ -63,8 +61,10 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
sprintf(
|
||||
'/%s/themes/(?P<stylesheet>%s)',
|
||||
$this->rest_base,
|
||||
// Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
// Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
/*
|
||||
* Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
* Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
*/
|
||||
'[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'
|
||||
),
|
||||
array(
|
||||
@@ -422,6 +422,7 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
* Prepares links for the request.
|
||||
*
|
||||
* @since 5.9.0
|
||||
* @since 6.3.0 Adds revisions count and rest URL href to version-history.
|
||||
*
|
||||
* @param integer $id ID.
|
||||
* @return array Links for the given post.
|
||||
@@ -435,6 +436,16 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
),
|
||||
);
|
||||
|
||||
if ( post_type_supports( $this->post_type, 'revisions' ) ) {
|
||||
$revisions = wp_get_latest_revision_id_and_total_count( $id );
|
||||
$revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0;
|
||||
$revisions_base = sprintf( '/%s/%d/revisions', $base, $id );
|
||||
$links['version-history'] = array(
|
||||
'href' => rest_url( $revisions_base ),
|
||||
'count' => $revisions_count,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
@@ -556,8 +567,10 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_theme_item_permissions_check( $request ) {
|
||||
// Verify if the current user has edit_theme_options capability.
|
||||
// This capability is required to edit/view/delete templates.
|
||||
/*
|
||||
* Verify if the current user has edit_theme_options capability.
|
||||
* This capability is required to edit/view/delete templates.
|
||||
*/
|
||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_manage_global_styles',
|
||||
@@ -629,8 +642,10 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_theme_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
// Verify if the current user has edit_theme_options capability.
|
||||
// This capability is required to edit/view/delete templates.
|
||||
/*
|
||||
* Verify if the current user has edit_theme_options capability.
|
||||
* This capability is required to edit/view/delete templates.
|
||||
*/
|
||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_manage_global_styles',
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Global_Styles_Revisions_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 6.3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Core class used to access global styles revisions via the REST API.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @see WP_REST_Controller
|
||||
*/
|
||||
class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Controller {
|
||||
/**
|
||||
* Parent post type.
|
||||
*
|
||||
* @since 6.3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $parent_post_type;
|
||||
|
||||
/**
|
||||
* The base of the parent controller's route.
|
||||
*
|
||||
* @since 6.3.0
|
||||
* @var string
|
||||
*/
|
||||
protected $parent_base;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->parent_post_type = 'wp_global_styles';
|
||||
$this->rest_base = 'revisions';
|
||||
$this->parent_base = 'global-styles';
|
||||
$this->namespace = 'wp/v2';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the controller's routes.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*/
|
||||
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 revision.' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for collections.
|
||||
*
|
||||
* Inherits from WP_REST_Controller::get_collection_params(),
|
||||
* also reflects changes to return value WP_REST_Revisions_Controller::get_collection_params().
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$collection_params = parent::get_collection_params();
|
||||
$collection_params['context']['default'] = 'view';
|
||||
$collection_params['offset'] = array(
|
||||
'description' => __( 'Offset the result set by a specific number of items.' ),
|
||||
'type' => 'integer',
|
||||
);
|
||||
unset( $collection_params['search'] );
|
||||
unset( $collection_params['per_page']['default'] );
|
||||
|
||||
return $collection_params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns decoded JSON from post content string,
|
||||
* or a 404 if not found.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param string $raw_json Encoded JSON from global styles custom post content.
|
||||
* @return Array|WP_Error
|
||||
*/
|
||||
protected function get_decoded_global_styles_json( $raw_json ) {
|
||||
$decoded_json = json_decode( $raw_json, true );
|
||||
|
||||
if ( is_array( $decoded_json ) && isset( $decoded_json['isGlobalStylesUserThemeJSON'] ) && true === $decoded_json['isGlobalStylesUserThemeJSON'] ) {
|
||||
return $decoded_json;
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
'rest_global_styles_not_found',
|
||||
__( 'Cannot find user global styles revisions.' ),
|
||||
array( 'status' => 404 )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns paginated revisions of the given global styles config custom post type.
|
||||
*
|
||||
* The bulk of the body is taken from WP_REST_Revisions_Controller->get_items,
|
||||
* but global styles does not require as many parameters.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param WP_REST_Request $request The request instance.
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
public function get_items( $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
|
||||
if ( is_wp_error( $parent ) ) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$global_styles_config = $this->get_decoded_global_styles_json( $parent->post_content );
|
||||
|
||||
if ( is_wp_error( $global_styles_config ) ) {
|
||||
return $global_styles_config;
|
||||
}
|
||||
|
||||
if ( wp_revisions_enabled( $parent ) ) {
|
||||
$registered = $this->get_collection_params();
|
||||
$query_args = array(
|
||||
'post_parent' => $parent->ID,
|
||||
'post_type' => 'revision',
|
||||
'post_status' => 'inherit',
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'date ID',
|
||||
'order' => 'DESC',
|
||||
);
|
||||
|
||||
$parameter_mappings = array(
|
||||
'offset' => 'offset',
|
||||
'page' => 'paged',
|
||||
'per_page' => 'posts_per_page',
|
||||
);
|
||||
|
||||
foreach ( $parameter_mappings as $api_param => $wp_param ) {
|
||||
if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
|
||||
$query_args[ $wp_param ] = $request[ $api_param ];
|
||||
}
|
||||
}
|
||||
|
||||
$revisions_query = new WP_Query();
|
||||
$revisions = $revisions_query->query( $query_args );
|
||||
$offset = isset( $query_args['offset'] ) ? (int) $query_args['offset'] : 0;
|
||||
$page = (int) $query_args['paged'];
|
||||
$total_revisions = $revisions_query->found_posts;
|
||||
|
||||
if ( $total_revisions < 1 ) {
|
||||
// Out-of-bounds, run the query again without LIMIT for total count.
|
||||
unset( $query_args['paged'], $query_args['offset'] );
|
||||
$count_query = new WP_Query();
|
||||
$count_query->query( $query_args );
|
||||
|
||||
$total_revisions = $count_query->found_posts;
|
||||
}
|
||||
|
||||
if ( $revisions_query->query_vars['posts_per_page'] > 0 ) {
|
||||
$max_pages = ceil( $total_revisions / (int) $revisions_query->query_vars['posts_per_page'] );
|
||||
} else {
|
||||
$max_pages = $total_revisions > 0 ? 1 : 0;
|
||||
}
|
||||
if ( $total_revisions > 0 ) {
|
||||
if ( $offset >= $total_revisions ) {
|
||||
return new WP_Error(
|
||||
'rest_revision_invalid_offset_number',
|
||||
__( 'The offset number requested is larger than or equal to the number of available revisions.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
} elseif ( ! $offset && $page > $max_pages ) {
|
||||
return new WP_Error(
|
||||
'rest_revision_invalid_page_number',
|
||||
__( 'The page number requested is larger than the number of pages available.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$revisions = array();
|
||||
$total_revisions = 0;
|
||||
$max_pages = 0;
|
||||
$page = (int) $request['page'];
|
||||
}
|
||||
|
||||
$response = array();
|
||||
|
||||
foreach ( $revisions as $revision ) {
|
||||
$data = $this->prepare_item_for_response( $revision, $request );
|
||||
$response[] = $this->prepare_response_for_collection( $data );
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( $response );
|
||||
|
||||
$response->header( 'X-WP-Total', (int) $total_revisions );
|
||||
$response->header( 'X-WP-TotalPages', (int) $max_pages );
|
||||
|
||||
$request_params = $request->get_query_params();
|
||||
$base_path = rest_url( sprintf( '%s/%s/%d/%s', $this->namespace, $this->parent_base, $request['parent'], $this->rest_base ) );
|
||||
$base = add_query_arg( urlencode_deep( $request_params ), $base_path );
|
||||
|
||||
if ( $page > 1 ) {
|
||||
$prev_page = $page - 1;
|
||||
|
||||
if ( $prev_page > $max_pages ) {
|
||||
$prev_page = $max_pages;
|
||||
}
|
||||
|
||||
$prev_link = add_query_arg( 'page', $prev_page, $base );
|
||||
$response->link_header( 'prev', $prev_link );
|
||||
}
|
||||
if ( $max_pages > $page ) {
|
||||
$next_page = $page + 1;
|
||||
$next_link = add_query_arg( 'page', $next_page, $base );
|
||||
|
||||
$response->link_header( 'next', $next_link );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the post_date_gmt or modified_gmt and prepare any post or
|
||||
* modified date for single post output.
|
||||
*
|
||||
* Duplicate of WP_REST_Revisions_Controller::prepare_date_response.
|
||||
*
|
||||
* @since 6.3.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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the revision for the REST response.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param WP_Post $post Post revision object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response|WP_Error Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $post, $request ) {
|
||||
$parent = $this->get_parent( $request['parent'] );
|
||||
$global_styles_config = $this->get_decoded_global_styles_json( $post->post_content );
|
||||
|
||||
if ( is_wp_error( $global_styles_config ) ) {
|
||||
return $global_styles_config;
|
||||
}
|
||||
|
||||
$fields = $this->get_fields_for_response( $request );
|
||||
$data = array();
|
||||
|
||||
if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) ) {
|
||||
$global_styles_config = ( new WP_Theme_JSON( $global_styles_config, 'custom' ) )->get_raw_data();
|
||||
if ( rest_is_field_included( 'settings', $fields ) ) {
|
||||
$data['settings'] = ! empty( $global_styles_config['settings'] ) ? $global_styles_config['settings'] : new stdClass();
|
||||
}
|
||||
if ( rest_is_field_included( 'styles', $fields ) ) {
|
||||
$data['styles'] = ! empty( $global_styles_config['styles'] ) ? $global_styles_config['styles'] : new stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'author', $fields ) ) {
|
||||
$data['author'] = (int) $post->post_author;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'date', $fields ) ) {
|
||||
$data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date );
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'date_gmt', $fields ) ) {
|
||||
$data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt );
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'id', $fields ) ) {
|
||||
$data['id'] = (int) $post->ID;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'modified', $fields ) ) {
|
||||
$data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified );
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'modified_gmt', $fields ) ) {
|
||||
$data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt );
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'parent', $fields ) ) {
|
||||
$data['parent'] = (int) $parent->ID;
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
return rest_ensure_response( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the revision's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->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(
|
||||
|
||||
/*
|
||||
* Adds settings and styles from the WP_REST_Revisions_Controller item fields.
|
||||
* Leaves out GUID as global styles shouldn't be accessible via URL.
|
||||
*/
|
||||
'author' => array(
|
||||
'description' => __( 'The ID for the author of the revision.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'date' => array(
|
||||
'description' => __( "The date the revision was published, in the site's timezone." ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'date_gmt' => array(
|
||||
'description' => __( 'The date the revision was published, as GMT.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the revision.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'modified' => array(
|
||||
'description' => __( "The date the revision was last modified, in the site's timezone." ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'modified_gmt' => array(
|
||||
'description' => __( 'The date the revision was last modified, as GMT.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'parent' => array(
|
||||
'description' => __( 'The ID for the parent of the revision.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
|
||||
// Adds settings and styles from the WP_REST_Global_Styles_Controller parent schema.
|
||||
'styles' => array(
|
||||
'description' => __( 'Global styles.' ),
|
||||
'type' => array( 'object' ),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'settings' => array(
|
||||
'description' => __( 'Global settings.' ),
|
||||
'type' => array( 'object' ),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to read a single global style.
|
||||
*
|
||||
* @since 6.3.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_item_permissions_check( $request ) {
|
||||
$post = $this->get_parent( $request['parent'] );
|
||||
if ( is_wp_error( $post ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
/*
|
||||
* The same check as WP_REST_Global_Styles_Controller::get_item_permissions_check.
|
||||
*/
|
||||
if ( ! current_user_can( 'read_post', $post->ID ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_view',
|
||||
__( 'Sorry, you are not allowed to view revisions for this global style.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent post, if the ID is valid.
|
||||
*
|
||||
* Duplicate of WP_REST_Revisions_Controller::get_parent.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param int $parent_post_id Supplied ID.
|
||||
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
|
||||
*/
|
||||
protected function get_parent( $parent_post_id ) {
|
||||
$error = new WP_Error(
|
||||
'rest_post_invalid_parent',
|
||||
__( 'Invalid post parent ID.' ),
|
||||
array( 'status' => 404 )
|
||||
);
|
||||
|
||||
if ( (int) $parent_post_id <= 0 ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$parent_post = get_post( (int) $parent_post_id );
|
||||
|
||||
if ( empty( $parent_post ) || empty( $parent_post->ID )
|
||||
|| $this->parent_post_type !== $parent_post->post_type
|
||||
) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $parent_post;
|
||||
}
|
||||
}
|
||||
@@ -710,6 +710,10 @@ class WP_REST_Menu_Items_Controller extends WP_REST_Posts_Controller {
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => $this->post_type,
|
||||
@@ -792,7 +796,7 @@ class WP_REST_Menu_Items_Controller extends WP_REST_Posts_Controller {
|
||||
),
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
'sanitize_callback' => static function ( $value ) {
|
||||
return array_map( 'sanitize_html_class', wp_parse_list( $value ) );
|
||||
},
|
||||
),
|
||||
@@ -873,7 +877,7 @@ class WP_REST_Menu_Items_Controller extends WP_REST_Posts_Controller {
|
||||
),
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
'sanitize_callback' => static function ( $value ) {
|
||||
return array_map( 'sanitize_html_class', wp_parse_list( $value ) );
|
||||
},
|
||||
),
|
||||
@@ -914,7 +918,9 @@ class WP_REST_Menu_Items_Controller extends WP_REST_Posts_Controller {
|
||||
$schema['links'] = $schema_links;
|
||||
}
|
||||
|
||||
return $this->add_additional_fields_schema( $schema );
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -523,6 +523,10 @@ class WP_REST_Menus_Controller extends WP_REST_Terms_Controller {
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = parent::get_item_schema();
|
||||
unset( $schema['properties']['count'], $schema['properties']['link'], $schema['properties']['taxonomy'] );
|
||||
|
||||
@@ -534,7 +538,7 @@ class WP_REST_Menus_Controller extends WP_REST_Terms_Controller {
|
||||
),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'arg_options' => array(
|
||||
'validate_callback' => function ( $locations, $request, $param ) {
|
||||
'validate_callback' => static function ( $locations, $request, $param ) {
|
||||
$valid = rest_validate_request_arg( $locations, $request, $param );
|
||||
|
||||
if ( true !== $valid ) {
|
||||
@@ -566,6 +570,8 @@ class WP_REST_Menus_Controller extends WP_REST_Terms_Controller {
|
||||
'type' => 'boolean',
|
||||
);
|
||||
|
||||
return $schema;
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
/**
|
||||
* WP_REST_Navigation_Fallback_Controller class
|
||||
*
|
||||
* REST Controller to create/fetch a fallback Navigation Menu.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 6.3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* REST Controller to fetch a fallback Navigation Block Menu. If needed it creates one.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*/
|
||||
class WP_REST_Navigation_Fallback_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* The Post Type for the Controller
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $post_type;
|
||||
|
||||
/**
|
||||
* Constructs the controller.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->namespace = 'wp-block-editor/v1';
|
||||
$this->rest_base = 'navigation-fallback';
|
||||
$this->post_type = 'wp_navigation';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the controllers routes.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_routes() {
|
||||
|
||||
// Lists a single nav item based on the given id or slug.
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::READABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to read fallbacks.
|
||||
*
|
||||
* @since 6.3.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_item_permissions_check( $request ) {
|
||||
|
||||
$post_type = get_post_type_object( $this->post_type );
|
||||
|
||||
// Getting fallbacks requires creating and reading `wp_navigation` posts.
|
||||
if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( 'edit_theme_options' ) || ! current_user_can( 'edit_posts' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_create',
|
||||
__( 'Sorry, you are not allowed to create Navigation Menus as this user.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'edit' === $request['context'] && ! current_user_can( $post_type->cap->edit_posts ) ) {
|
||||
return new WP_Error(
|
||||
'rest_forbidden_context',
|
||||
__( 'Sorry, you are not allowed to edit Navigation Menus as this user.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the most appropriate fallback Navigation Menu.
|
||||
*
|
||||
* @since 6.3.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 ) {
|
||||
$post = WP_Navigation_Fallback::get_fallback();
|
||||
|
||||
if ( empty( $post ) ) {
|
||||
return rest_ensure_response( new WP_Error( 'no_fallback_menu', __( 'No fallback menu found.' ), array( 'status' => 404 ) ) );
|
||||
}
|
||||
|
||||
$response = $this->prepare_item_for_response( $post, $request );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the fallbacks' schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$this->schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'navigation-fallback',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'The unique identifier for the Navigation Menu.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the post data to the schema we want.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param WP_Post $item The wp_navigation Post object whose response is being prepared.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response $response The response data.
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
$data = array();
|
||||
|
||||
$fields = $this->get_fields_for_response( $request );
|
||||
|
||||
if ( rest_is_field_included( 'id', $fields ) ) {
|
||||
$data['id'] = (int) $item->ID;
|
||||
}
|
||||
|
||||
$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 ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
|
||||
$links = $this->prepare_links( $item );
|
||||
$response->add_links( $links );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the links for the request.
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param WP_Post $post the Navigation Menu post object.
|
||||
* @return array Links for the given request.
|
||||
*/
|
||||
private function prepare_links( $post ) {
|
||||
return array(
|
||||
'self' => array(
|
||||
'href' => rest_url( rest_get_route_for_post( $post->ID ) ),
|
||||
'embeddable' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -298,7 +298,7 @@ class WP_REST_Plugins_Controller extends WP_REST_Controller {
|
||||
);
|
||||
|
||||
if ( is_wp_error( $api ) ) {
|
||||
if ( false !== strpos( $api->get_error_message(), 'Plugin not found.' ) ) {
|
||||
if ( str_contains( $api->get_error_message(), 'Plugin not found.' ) ) {
|
||||
$api->add_data( array( 'status' => 404 ) );
|
||||
} else {
|
||||
$api->add_data( array( 'status' => 500 ) );
|
||||
@@ -809,7 +809,7 @@ class WP_REST_Plugins_Controller extends WP_REST_Controller {
|
||||
$matched_search = false;
|
||||
|
||||
foreach ( $item as $field ) {
|
||||
if ( is_string( $field ) && false !== strpos( strip_tags( $field ), $search ) ) {
|
||||
if ( is_string( $field ) && str_contains( strip_tags( $field ), $search ) ) {
|
||||
$matched_search = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1063,8 +1063,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
|
||||
// (Note that internally this falls through to `wp_delete_post()`
|
||||
// if the Trash is disabled.)
|
||||
/*
|
||||
* (Note that internally this falls through to `wp_delete_post()`
|
||||
* if the Trash is disabled.)
|
||||
*/
|
||||
$result = wp_trash_post( $id );
|
||||
$post = get_post( $id );
|
||||
$response = $this->prepare_item_for_response( $post, $request );
|
||||
@@ -1269,8 +1271,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
||||
}
|
||||
}
|
||||
|
||||
// Sending a null date or date_gmt value resets date and date_gmt to their
|
||||
// default values (`0000-00-00 00:00:00`).
|
||||
/*
|
||||
* Sending a null date or date_gmt value resets date and date_gmt to their
|
||||
* default values (`0000-00-00 00:00:00`).
|
||||
*/
|
||||
if (
|
||||
( ! empty( $schema['properties']['date_gmt'] ) && $request->has_param( 'date_gmt' ) && null === $request['date_gmt'] ) ||
|
||||
( ! empty( $schema['properties']['date'] ) && $request->has_param( 'date' ) && null === $request['date'] )
|
||||
|
||||
@@ -48,16 +48,18 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
|
||||
* @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_post_type = $parent_post_type;
|
||||
$post_type_object = get_post_type_object( $parent_post_type );
|
||||
$parent_controller = $post_type_object->get_rest_controller();
|
||||
|
||||
if ( ! $parent_controller ) {
|
||||
$parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
|
||||
}
|
||||
|
||||
$this->parent_controller = $parent_controller;
|
||||
$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;
|
||||
$this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2';
|
||||
$this->parent_controller = $post_type_object->get_rest_controller();
|
||||
|
||||
if ( ! $this->parent_controller ) {
|
||||
$this->parent_controller = new WP_REST_Posts_Controller( $parent_post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,8 +412,6 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
$parent_post_type = get_post_type_object( $parent->post_type );
|
||||
|
||||
if ( ! current_user_can( 'delete_post', $parent->ID ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_delete',
|
||||
|
||||
@@ -261,8 +261,10 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller {
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
protected function do_permissions_check() {
|
||||
// Verify if the current user has edit_theme_options capability.
|
||||
// This capability is required to access the widgets screen.
|
||||
/*
|
||||
* Verify if the current user has edit_theme_options capability.
|
||||
* This capability is required to access the widgets screen.
|
||||
*/
|
||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_manage_widgets',
|
||||
|
||||
@@ -101,8 +101,10 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
sprintf(
|
||||
'/%s/(?P<id>%s%s)',
|
||||
$this->rest_base,
|
||||
// Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
// Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
/*
|
||||
* Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
* Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
*/
|
||||
'([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
|
||||
// Matches the template name.
|
||||
'[\/\w%-]+'
|
||||
@@ -150,14 +152,21 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
* Returns the fallback template for the given slug.
|
||||
*
|
||||
* @since 6.1.0
|
||||
* @since 6.3.0 Ignore empty templates.
|
||||
*
|
||||
* @param WP_REST_Request $request The request instance.
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
public function get_template_fallback( $request ) {
|
||||
$hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] );
|
||||
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
|
||||
$response = $this->prepare_item_for_response( $fallback_template, $request );
|
||||
$hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] );
|
||||
|
||||
do {
|
||||
$fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' );
|
||||
array_shift( $hierarchy );
|
||||
} while ( ! empty( $hierarchy ) && empty( $fallback_template->content ) );
|
||||
|
||||
$response = $this->prepare_item_for_response( $fallback_template, $request );
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
@@ -170,8 +179,10 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
protected function permissions_check( $request ) {
|
||||
// Verify if the current user has edit_theme_options capability.
|
||||
// This capability is required to edit/view/delete templates.
|
||||
/*
|
||||
* Verify if the current user has edit_theme_options capability.
|
||||
* This capability is required to edit/view/delete templates.
|
||||
*/
|
||||
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_manage_templates',
|
||||
@@ -495,8 +506,10 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
|
||||
// (Note that internally this falls through to `wp_delete_post()`
|
||||
// if the Trash is disabled.)
|
||||
/*
|
||||
* (Note that internally this falls through to `wp_delete_post()`
|
||||
* if the Trash is disabled.)
|
||||
*/
|
||||
$result = wp_trash_post( $id );
|
||||
$template->status = 'trash';
|
||||
$response = $this->prepare_item_for_response( $template, $request );
|
||||
@@ -583,7 +596,7 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
$changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] );
|
||||
} elseif ( null !== $template && 'custom' !== $template->source && $template->area ) {
|
||||
$changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $template->area );
|
||||
} elseif ( ! $template->area ) {
|
||||
} elseif ( empty( $template->area ) ) {
|
||||
$changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED;
|
||||
}
|
||||
}
|
||||
@@ -614,6 +627,7 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
*
|
||||
* @since 5.8.0
|
||||
* @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support.
|
||||
* @since 6.3.0 Added `modified` property to the response.
|
||||
*
|
||||
* @param WP_Block_Template $item Template instance.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
@@ -708,6 +722,10 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
$data['area'] = $template->area;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'modified', $fields ) ) {
|
||||
$data['modified'] = mysql_to_rfc3339( $template->modified );
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
@@ -926,6 +944,13 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'modified' => array(
|
||||
'description' => __( "The date the template was last modified, in the site's timezone." ),
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -326,6 +326,10 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'is_block_theme', $fields ) ) {
|
||||
$data['is_block_theme'] = $theme->is_block_theme();
|
||||
}
|
||||
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
|
||||
// Wrap the data in a response object.
|
||||
@@ -494,6 +498,11 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
|
||||
),
|
||||
),
|
||||
),
|
||||
'is_block_theme' => array(
|
||||
'description' => __( 'Whether the theme is a block-based theme.' ),
|
||||
'type' => 'boolean',
|
||||
'readonly' => true,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => __( 'The name of the theme.' ),
|
||||
'type' => 'object',
|
||||
|
||||
@@ -683,8 +683,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
||||
|
||||
$request_params = array_keys( $request->get_params() );
|
||||
sort( $request_params );
|
||||
// If only 'id' and 'roles' are specified (we are only trying to
|
||||
// edit roles), then only the 'promote_user' cap is required.
|
||||
/*
|
||||
* If only 'id' and 'roles' are specified (we are only trying to
|
||||
* edit roles), then only the 'promote_user' cap is required.
|
||||
*/
|
||||
if ( array( 'id', 'roles' ) === $request_params ) {
|
||||
return true;
|
||||
}
|
||||
@@ -1305,7 +1307,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
|
||||
if ( false !== strpos( $password, '\\' ) ) {
|
||||
if ( str_contains( $password, '\\' ) ) {
|
||||
return new WP_Error(
|
||||
'rest_user_invalid_password',
|
||||
sprintf(
|
||||
|
||||
@@ -464,8 +464,10 @@ class WP_REST_Widget_Types_Controller extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
|
||||
// Set the widget's number so that the id attributes in the HTML that we
|
||||
// return are predictable.
|
||||
/*
|
||||
* Set the widget's number so that the id attributes in the HTML that we
|
||||
* return are predictable.
|
||||
*/
|
||||
if ( isset( $request['number'] ) && is_numeric( $request['number'] ) ) {
|
||||
$widget_object->_set( (int) $request['number'] );
|
||||
} else {
|
||||
|
||||
@@ -368,6 +368,16 @@ abstract class WP_REST_Meta_Fields {
|
||||
protected function update_meta_value( $object_id, $meta_key, $name, $value ) {
|
||||
$meta_type = $this->get_meta_type();
|
||||
|
||||
// Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false.
|
||||
$old_value = get_metadata( $meta_type, $object_id, $meta_key );
|
||||
$subtype = get_object_subtype( $meta_type, $object_id );
|
||||
|
||||
if ( is_array( $old_value ) && 1 === count( $old_value )
|
||||
&& $this->is_meta_value_same_as_stored_value( $meta_key, $subtype, $old_value[0], $value )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_update',
|
||||
@@ -380,16 +390,6 @@ abstract class WP_REST_Meta_Fields {
|
||||
);
|
||||
}
|
||||
|
||||
// Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false.
|
||||
$old_value = get_metadata( $meta_type, $object_id, $meta_key );
|
||||
$subtype = get_object_subtype( $meta_type, $object_id );
|
||||
|
||||
if ( is_array( $old_value ) && 1 === count( $old_value )
|
||||
&& $this->is_meta_value_same_as_stored_value( $meta_key, $subtype, $old_value[0], $value )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! update_metadata( $meta_type, $object_id, wp_slash( $meta_key ), wp_slash( $value ) ) ) {
|
||||
return new WP_Error(
|
||||
'rest_meta_database_error',
|
||||
|
||||
Reference in New Issue
Block a user