mirror of
https://github.com/WordPress/WordPress.git
synced 2026-06-19 07:37:07 +00:00
Abilities API: Harden ability schema preparation for REST responses
Merge `normalize_schema_empty_object_defaults()` and `strip_internal_schema_keywords()` into a single recursive `prepare_schema_for_response()` helper on `WP_REST_Abilities_V1_List_Controller`. Empty object defaults now normalize to `stdClass` at every depth — not just the top level — so nested `{}` defaults serialize consistently alongside the existing internal-keyword stripping.
Follow-up to [62221], [61244].
Props gziolo, westonruter.
See #64955.
Built from https://develop.svn.wordpress.org/trunk@62427
git-svn-id: http://core.svn.wordpress.org/trunk@61708 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
@@ -188,27 +188,6 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
return current_user_can( 'read' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes schema empty object defaults.
|
||||
*
|
||||
* Converts empty array defaults to objects when the schema type is 'object'
|
||||
* to ensure proper JSON serialization as {} instead of [].
|
||||
*
|
||||
* @since 6.9.0
|
||||
*
|
||||
* @param array<string, mixed> $schema The schema array.
|
||||
* @return array<string, mixed> The normalized schema.
|
||||
*/
|
||||
private function normalize_schema_empty_object_defaults( array $schema ): array {
|
||||
if ( isset( $schema['type'] ) && 'object' === $schema['type'] && isset( $schema['default'] ) ) {
|
||||
$default = $schema['default'];
|
||||
if ( is_array( $default ) && empty( $default ) ) {
|
||||
$schema['default'] = (object) $default;
|
||||
}
|
||||
}
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* WordPress-internal schema keywords to strip from REST responses.
|
||||
*
|
||||
@@ -222,19 +201,42 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
);
|
||||
|
||||
/**
|
||||
* Recursively removes WordPress-internal keywords from a schema.
|
||||
* Determines whether the value is an associative array.
|
||||
*
|
||||
* @since 7.1.0
|
||||
*
|
||||
* @param mixed $value Value.
|
||||
* @return bool Whether it is associative array.
|
||||
*
|
||||
* @phpstan-assert-if-true array<string, mixed> $value
|
||||
*/
|
||||
private function is_associative_array( $value ): bool {
|
||||
return is_array( $value ) && ! wp_is_numeric_array( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an ability schema for REST response output.
|
||||
*
|
||||
* Ability schemas may include WordPress-internal properties like
|
||||
* `sanitize_callback`, `validate_callback`, and `arg_options` that are
|
||||
* used server-side but are not valid JSON Schema keywords. This method
|
||||
* removes those specific keys so they are not exposed in REST responses.
|
||||
* It also converts empty array defaults to objects when the schema type is
|
||||
* 'object' to ensure proper JSON serialization as {} instead of [].
|
||||
*
|
||||
* @since 7.0.0
|
||||
* @since 7.1.0
|
||||
*
|
||||
* @param array<string, mixed> $schema The schema array.
|
||||
* @return array<string, mixed> The schema without WordPress-internal keywords.
|
||||
* @return array<string, mixed> The transformed schema.
|
||||
*/
|
||||
private function strip_internal_schema_keywords( array $schema ): array {
|
||||
private function prepare_schema_for_response( array $schema ): array {
|
||||
if ( isset( $schema['type'] ) && 'object' === $schema['type'] && isset( $schema['default'] ) ) {
|
||||
$default = $schema['default'];
|
||||
if ( is_array( $default ) && empty( $default ) ) {
|
||||
$schema['default'] = (object) $default;
|
||||
}
|
||||
}
|
||||
|
||||
$schema = array_diff_key( $schema, self::INTERNAL_SCHEMA_KEYWORDS );
|
||||
|
||||
// Sub-schema maps: keys are user-defined, values are sub-schemas.
|
||||
@@ -243,8 +245,8 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
foreach ( array( 'properties', 'patternProperties', 'definitions', 'dependencies' ) as $keyword ) {
|
||||
if ( isset( $schema[ $keyword ] ) && is_array( $schema[ $keyword ] ) ) {
|
||||
foreach ( $schema[ $keyword ] as $key => $child_schema ) {
|
||||
if ( is_array( $child_schema ) && ! wp_is_numeric_array( $child_schema ) ) {
|
||||
$schema[ $keyword ][ $key ] = $this->strip_internal_schema_keywords( $child_schema );
|
||||
if ( $this->is_associative_array( $child_schema ) ) {
|
||||
$schema[ $keyword ][ $key ] = $this->prepare_schema_for_response( $child_schema );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,21 +254,21 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
|
||||
// Single sub-schema keywords.
|
||||
foreach ( array( 'not', 'additionalProperties', 'additionalItems' ) as $keyword ) {
|
||||
if ( isset( $schema[ $keyword ] ) && is_array( $schema[ $keyword ] ) ) {
|
||||
$schema[ $keyword ] = $this->strip_internal_schema_keywords( $schema[ $keyword ] );
|
||||
if ( isset( $schema[ $keyword ] ) && $this->is_associative_array( $schema[ $keyword ] ) ) {
|
||||
$schema[ $keyword ] = $this->prepare_schema_for_response( $schema[ $keyword ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Items: single schema or tuple array of schemas.
|
||||
if ( isset( $schema['items'] ) ) {
|
||||
if ( wp_is_numeric_array( $schema['items'] ) ) {
|
||||
if ( isset( $schema['items'] ) && is_array( $schema['items'] ) ) {
|
||||
if ( $this->is_associative_array( $schema['items'] ) ) {
|
||||
$schema['items'] = $this->prepare_schema_for_response( $schema['items'] );
|
||||
} else {
|
||||
foreach ( $schema['items'] as $index => $item_schema ) {
|
||||
if ( is_array( $item_schema ) ) {
|
||||
$schema['items'][ $index ] = $this->strip_internal_schema_keywords( $item_schema );
|
||||
if ( $this->is_associative_array( $item_schema ) ) {
|
||||
$schema['items'][ $index ] = $this->prepare_schema_for_response( $item_schema );
|
||||
}
|
||||
}
|
||||
} elseif ( is_array( $schema['items'] ) ) {
|
||||
$schema['items'] = $this->strip_internal_schema_keywords( $schema['items'] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +276,8 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
foreach ( array( 'anyOf', 'oneOf', 'allOf' ) as $keyword ) {
|
||||
if ( isset( $schema[ $keyword ] ) && is_array( $schema[ $keyword ] ) ) {
|
||||
foreach ( $schema[ $keyword ] as $index => $sub_schema ) {
|
||||
if ( is_array( $sub_schema ) ) {
|
||||
$schema[ $keyword ][ $index ] = $this->strip_internal_schema_keywords( $sub_schema );
|
||||
if ( $this->is_associative_array( $sub_schema ) ) {
|
||||
$schema[ $keyword ][ $index ] = $this->prepare_schema_for_response( $sub_schema );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,12 +301,8 @@ class WP_REST_Abilities_V1_List_Controller extends WP_REST_Controller {
|
||||
'label' => $ability->get_label(),
|
||||
'description' => $ability->get_description(),
|
||||
'category' => $ability->get_category(),
|
||||
'input_schema' => $this->strip_internal_schema_keywords(
|
||||
$this->normalize_schema_empty_object_defaults( $ability->get_input_schema() )
|
||||
),
|
||||
'output_schema' => $this->strip_internal_schema_keywords(
|
||||
$this->normalize_schema_empty_object_defaults( $ability->get_output_schema() )
|
||||
),
|
||||
'input_schema' => $this->prepare_schema_for_response( $ability->get_input_schema() ),
|
||||
'output_schema' => $this->prepare_schema_for_response( $ability->get_output_schema() ),
|
||||
'meta' => $ability->get_meta(),
|
||||
);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '7.1-alpha-62426';
|
||||
$wp_version = '7.1-alpha-62427';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
||||
Reference in New Issue
Block a user