Changeset 62447
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php
r62427 r62447 190 190 191 191 /** 192 * WordPress-internal schema keywords to strip from REST responses. 193 * 194 * @since 7.0.0 195 * @var array<string, true> 196 */ 197 private const INTERNAL_SCHEMA_KEYWORDS = array( 198 'sanitize_callback' => true, 199 'validate_callback' => true, 200 'arg_options' => true, 192 * Additional schema keywords to preserve in REST responses. 193 * 194 * Ability schemas are exposed to clients as JSON Schema. Preserve additional 195 * draft-04 keywords so clients can validate richer schemas, even when some 196 * of those keywords are not enforced by the server-side REST schema validator. 197 * 198 * @since 7.1.0 199 * @var string[] 200 */ 201 private const ADDITIONAL_ALLOWED_SCHEMA_KEYWORDS = array( 202 'required', 203 'allOf', 204 'not', 205 '$ref', 206 'definitions', 207 'dependencies', 208 'additionalItems', 201 209 ); 202 210 … … 218 226 * Transforms an ability schema for REST response output. 219 227 * 220 * Ability schemas may include WordPress-internal properties like 221 * `sanitize_callback`, `validate_callback`, and `arg_options` that are 222 * used server-side but are not valid JSON Schema keywords. This method 223 * removes those specific keys so they are not exposed in REST responses. 224 * It also converts empty array defaults to objects when the schema type is 225 * 'object' to ensure proper JSON serialization as {} instead of []. 228 * Ability schemas may include WordPress-internal properties or unsupported 229 * schema keywords that should not be exposed in REST responses. This method 230 * strips keys not recognized by the REST API schema handling. It also 231 * converts empty array defaults to objects when the schema type is 'object' 232 * to ensure proper JSON serialization as {} instead of []. 226 233 * 227 234 * @since 7.1.0 … … 238 245 } 239 246 240 $schema = array_diff_key( $schema, self::INTERNAL_SCHEMA_KEYWORDS ); 247 // Computed once and reused across the recursive calls for every schema node. 248 static $allowed_keywords = null; 249 $allowed_keywords ??= array_fill_keys( 250 array_merge( 251 rest_get_allowed_schema_keywords(), 252 self::ADDITIONAL_ALLOWED_SCHEMA_KEYWORDS 253 ), 254 true 255 ); 256 257 $schema = array_intersect_key( $schema, $allowed_keywords ); 241 258 242 259 // Sub-schema maps: keys are user-defined, values are sub-schemas. -
trunk/tests/phpunit/tests/rest-api/wpRestAbilitiesV1ListController.php
r62427 r62447 830 830 831 831 /** 832 * Test that WordPress-internal schema keywordsare stripped from ability schemas in REST response.832 * Test that schema keywords outside the allow-list are stripped from ability schemas in REST response. 833 833 * 834 834 * @ticket 65035 835 835 */ 836 public function test_ internal_schema_keywords_stripped_from_response(): void {836 public function test_unsupported_schema_keywords_stripped_from_response(): void { 837 837 $this->register_test_ability( 838 'test/with- internal-keywords',838 'test/with-unsupported-keywords', 839 839 array( 840 'label' => 'Test InternalKeywords',841 'description' => 'Tests stripping of internalschema keywords',840 'label' => 'Test Unsupported Keywords', 841 'description' => 'Tests stripping of unsupported schema keywords', 842 842 'category' => 'general', 843 843 'input_schema' => array( 844 844 'type' => 'object', 845 'required' => array( 'content' ), 845 846 'properties' => array( 846 847 'content' => array( 847 848 'type' => 'string', 848 849 'description' => 'The content value.', 850 'example' => 'example content', 851 'examples' => array( 'example content' ), 852 'context' => array( 'view', 'edit', 'embed' ), 853 'readonly' => true, 849 854 'sanitize_callback' => 'sanitize_text_field', 850 855 'validate_callback' => 'is_string', … … 855 860 'output_schema' => array( 856 861 'type' => 'string', 862 'example' => 'example output', 863 'examples' => array( 'example output' ), 864 'context' => array( 'view', 'edit', 'embed' ), 865 'readonly' => true, 857 866 'sanitize_callback' => 'sanitize_text_field', 867 'validate_callback' => 'is_string', 868 'arg_options' => array( 'sanitize_callback' => 'wp_kses_post' ), 858 869 ), 859 870 'execute_callback' => static function ( $input ) { … … 865 876 ); 866 877 867 $request = new WP_REST_Request( 'GET', '/wp-abilities/v1/abilities/test/with- internal-keywords' );878 $request = new WP_REST_Request( 'GET', '/wp-abilities/v1/abilities/test/with-unsupported-keywords' ); 868 879 $response = $this->server->dispatch( $request ); 869 880 … … 876 887 $this->assertArrayHasKey( 'output_schema', $data ); 877 888 878 // Verify internalkeywords are stripped from input_schema properties.889 // Verify unsupported schema keywords are stripped from input_schema properties. 879 890 $content_schema = $data['input_schema']['properties']['content']; 880 891 $this->assertArrayNotHasKey( 'sanitize_callback', $content_schema ); 881 892 $this->assertArrayNotHasKey( 'validate_callback', $content_schema ); 882 893 $this->assertArrayNotHasKey( 'arg_options', $content_schema ); 894 $this->assertArrayNotHasKey( 'example', $content_schema ); 895 $this->assertArrayNotHasKey( 'examples', $content_schema ); 896 $this->assertArrayNotHasKey( 'context', $content_schema ); 897 $this->assertArrayNotHasKey( 'readonly', $content_schema ); 883 898 884 899 // Verify valid JSON Schema keywords are preserved. 885 900 $this->assertSame( 'string', $content_schema['type'] ); 886 901 $this->assertSame( 'The content value.', $content_schema['description'] ); 902 $this->assertSame( array( 'content' ), $data['input_schema']['required'] ); 887 903 888 904 // Verify internal keywords are stripped from output_schema. 889 905 $this->assertArrayNotHasKey( 'sanitize_callback', $data['output_schema'] ); 906 $this->assertArrayNotHasKey( 'validate_callback', $data['output_schema'] ); 907 $this->assertArrayNotHasKey( 'arg_options', $data['output_schema'] ); 908 $this->assertArrayNotHasKey( 'example', $data['output_schema'] ); 909 $this->assertArrayNotHasKey( 'examples', $data['output_schema'] ); 910 $this->assertArrayNotHasKey( 'context', $data['output_schema'] ); 911 $this->assertArrayNotHasKey( 'readonly', $data['output_schema'] ); 890 912 $this->assertSame( 'string', $data['output_schema']['type'] ); 891 913 } … … 948 970 949 971 /** 950 * Test that internal schema keywordsare stripped from nested sub-schema locations.951 * 952 * @ticket 64098 953 */ 954 public function test_ internal_schema_keywords_stripped_from_nested_sub_schemas(): void {972 * Test that schema keywords outside the allow-list are stripped from nested sub-schema locations. 973 * 974 * @ticket 64098 975 */ 976 public function test_unsupported_schema_keywords_stripped_from_nested_sub_schemas(): void { 955 977 $this->register_test_ability( 956 'test/nested- internal-keywords',978 'test/nested-unsupported-keywords', 957 979 array( 958 'label' => 'Test Nested Keywords',980 'label' => 'Test Nested Unsupported Keywords', 959 981 'description' => 'Tests stripping from all sub-schema locations', 960 982 'category' => 'general', 961 983 'input_schema' => array( 962 984 'type' => 'object', 985 '$ref' => '#/definitions/address', 963 986 'anyOf' => array( 964 987 array( … … 1054 1077 ); 1055 1078 1056 $request = new WP_REST_Request( 'GET', '/wp-abilities/v1/abilities/test/nested- internal-keywords' );1079 $request = new WP_REST_Request( 'GET', '/wp-abilities/v1/abilities/test/nested-unsupported-keywords' ); 1057 1080 $response = $this->server->dispatch( $request ); 1058 1081 … … 1062 1085 1063 1086 // Verify internal keywords are stripped from anyOf sub-schemas. 1087 $this->assertSame( '#/definitions/address', $data['input_schema']['$ref'] ); 1064 1088 $this->assertArrayHasKey( 'anyOf', $data['input_schema'] ); 1065 1089 $this->assertArrayNotHasKey( 'sanitize_callback', $data['input_schema']['anyOf'][0] );
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)