Changeset 11410
- Timestamp:
- 01/04/2022 11:40:07 PM (3 years ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/block-json/class-validator.php
r11096 r11410 28 28 * The schema for the block.json file. 29 29 * 30 * This attempts to follow the schema for the schema. 31 * See https://json-schema.org/understanding-json-schema/reference/index.html 30 * Fetch the schema from `schemas.wp.org`, which redirects to the latest version 31 * of this file in GitHub. 32 * See https://github.com/WordPress/gutenberg/blob/trunk/schemas/json/block.json. 32 33 * 33 34 * @return array 34 35 */ 35 36 public static function schema() { 36 return array( 37 'type' => 'object', 38 'properties' => array( 39 'apiVersion' => array( 40 'type' => 'string', 41 ), 42 'attributes' => array( 43 'type' => 'object', 44 'additionalProperties' => array( 45 'type' => 'object', 46 'properties' => array( 47 'attribute' => array( 48 'type' => 'string', 49 ), 50 'meta' => array( 51 'type' => 'string', 52 ), 53 'multiline' => array( 54 'type' => 'string', 55 ), 56 'query' => array( 57 'type' => 'object', 58 ), 59 'selector' => array( 60 'type' => 'string', 61 ), 62 'source' => array( 63 'type' => 'string', 64 'enum' => array( 'attribute', 'text', 'html', 'query' ), 65 ), 66 'type' => array( 67 'type' => 'string', 68 'enum' => array( 'null', 'boolean', 'object', 'array', 'number', 'string', 'integer' ), 69 ), 70 ), 71 'required' => array( 'type' ), 72 ), 73 ), 74 'category' => array( 75 'type' => 'string', 76 ), 77 'comment' => array( 78 'type' => 'string', 79 ), 80 'description' => array( 81 'type' => 'string', 82 ), 83 'editorScript' => array( 84 'type' => 'string', 85 'pattern' => '\.js$', 86 ), 87 'editorStyle' => array( 88 'type' => 'string', 89 'pattern' => '\.css$', 90 ), 91 'example' => array( 92 'type' => 'object', 93 'additionalProperties' => array( 94 'type' => 'object', 95 ), 96 ), 97 'icon' => array( 98 'type' => 'string', 99 ), 100 'keywords' => array( 101 'type' => 'array', 102 'items' => array( 103 'type' => 'string', 104 ), 105 ), 106 'name' => array( 107 'type' => 'string', 108 ), 109 'parent' => array( 110 'type' => 'array', 111 'items' => array( 112 'type' => 'string', 113 ), 114 ), 115 'script' => array( 116 'type' => 'string', 117 'pattern' => '\.js$', 118 ), 119 'style' => array( 120 'type' => 'string', 121 'pattern' => '\.css$', 122 ), 123 'styles' => array( 124 'type' => 'array', 125 'items' => array( 126 'type' => 'object', 127 'properties' => array( 128 'isDefault' => array( 129 'type' => 'boolean', 130 ), 131 'label' => array( 132 'type' => 'string', 133 ), 134 'name' => array( 135 'type' => 'string', 136 ), 137 ), 138 ), 139 ), 140 'supports' => array( 141 'type' => 'object', 142 'properties' => array( 143 'align' => array( 144 'type' => array( 'boolean', 'array' ), 145 'items' => array( 146 'type' => 'string', 147 'enum' => array( 'left', 'center', 'right', 'wide', 'full' ), 148 ), 149 ), 150 'alignWide' => array( 151 'type' => 'boolean', 152 ), 153 'anchor' => array( 154 'type' => 'boolean', 155 ), 156 'className' => array( 157 'type' => 'boolean', 158 ), 159 'customClassName' => array( 160 'type' => 'boolean', 161 ), 162 'html' => array( 163 'type' => 'boolean', 164 ), 165 'inserter' => array( 166 'type' => 'boolean', 167 ), 168 'multiple' => array( 169 'type' => 'boolean', 170 ), 171 'reusable' => array( 172 'type' => 'boolean', 173 ), 174 ), 175 ), 176 'textdomain' => array( 177 'type' => 'string', 178 ), 179 'title' => array( 180 'type' => 'string', 181 ), 182 ), 183 'required' => array( 'name', 'title' ), 184 'additionalProperties' => false, 185 ); 37 $schema_url = 'https://schemas.wp.org/trunk/block.json'; 38 $response = wp_remote_get( $schema_url ); 39 if ( is_wp_error( $response ) ) { 40 return $response; 41 } 42 43 $body = wp_remote_retrieve_body( $response ); 44 $schema = json_decode( $body, true ); 45 return $schema; 186 46 } 187 47 … … 200 60 201 61 $schema = self::schema(); 62 if ( is_wp_error( $schema ) ) { 63 return $schema; 64 } 202 65 203 $this->validate_object( $block_json, 'block.json', $schema ); 66 $result = rest_validate_value_from_schema( $block_json, $schema, 'block.json' ); 67 68 // Workaround for a bug in validation, `oneOf` incorrectly flags that the value matches multiple options. 69 // Getting this message means it passed the "string" condition, so this is not an error. 70 // See https://core.trac.wordpress.org/ticket/54740. 71 if ( is_wp_error( $result ) && 'rest_one_of_multiple_matches' !== $result->get_error_code() ) { 72 $this->messages = $result; 73 } 74 204 75 $this->check_conditional_properties( $block_json ); 205 76 … … 223 94 } 224 95 96 // phpcs:ignore WordPress.NamingConventions.ValidVariableName 225 97 if ( ! isset( $block_json->script ) && ! isset( $block_json->editorScript ) ) { 226 98 $this->messages->add( 227 99 'error', 228 100 sprintf( 229 __( ' At least one of the following properties must be present: %s', 'wporg-plugins' ),101 __( 'block.json[script] At least one of the following properties must be present: %s', 'wporg-plugins' ), 230 102 // translators: used between list items, there is a space after the comma. 231 103 '<code>script</code>' . __( ', ', 'wporg-plugins' ) . '<code>editorScript</code>' 232 104 ) 233 105 ); 234 $this->append_error_data( 'block.json:script', 'error' );235 $this->append_error_data( 'block.json:editorScript', 'error' );236 106 } 237 }238 239 /**240 * Validate an object and its properties.241 *242 * @param object $object The value to validate as an object.243 * @param string $prop The name of the property, used in error reporting.244 * @param array $schema The schema for the property, used for validation.245 *246 * @return bool247 */248 protected function validate_object( $object, $prop, $schema ) {249 if ( ! is_object( $object ) ) {250 $this->messages->add(251 'error',252 sprintf(253 __( 'The %s property must contain an object value.', 'wporg-plugins' ),254 '<code>' . $prop . '</code>'255 )256 );257 $this->append_error_data( $prop, 'error' );258 259 return false;260 }261 262 $results = array();263 264 if ( isset( $schema['required'] ) ) {265 foreach ( $schema['required'] as $required_prop ) {266 if ( ! property_exists( $object, $required_prop ) ) {267 $this->messages->add(268 'error',269 sprintf(270 __( 'The %1$s property is required in the %2$s object.', 'wporg-plugins' ),271 '<code>' . $required_prop . '</code>',272 '<code>' . $prop . '</code>'273 )274 );275 $this->append_error_data( "$prop:$required_prop", 'error' );276 $results[] = false;277 }278 }279 }280 281 if ( isset( $schema['properties'] ) ) {282 foreach ( $schema['properties'] as $subprop => $subschema ) {283 if ( ! isset( $object->$subprop ) ) {284 continue;285 }286 287 if ( isset( $subschema['type'] ) ) {288 $results[] = $this->route_validation_for_type(289 $subschema['type'],290 $object->$subprop,291 "$prop:$subprop",292 $subschema293 );294 }295 }296 }297 298 if ( isset( $schema['additionalProperties'] ) ) {299 if ( false === $schema['additionalProperties'] ) {300 foreach ( array_keys( get_object_vars( $object ) ) as $key ) {301 if ( ! isset( $schema['properties'][ $key ] ) ) {302 $this->messages->add(303 'warning',304 sprintf(305 __( '%1$s is not a valid property in the %2$s object.', 'wporg-plugins' ),306 '<code>' . $key . '</code>',307 '<code>' . $prop . '</code>'308 )309 );310 $this->append_error_data( "$prop:$key", 'warning' );311 $results[] = false;312 continue;313 }314 }315 } elseif ( isset( $schema['additionalProperties']['type'] ) ) {316 foreach ( $object as $subprop => $subvalue ) {317 $results[] = $this->route_validation_for_type(318 $schema['additionalProperties']['type'],319 $subvalue,320 "$prop:$subprop",321 $schema['additionalProperties']322 );323 }324 }325 }326 327 return ! in_array( false, $results, true );328 }329 330 /**331 * Validate an array and its items.332 *333 * @param array $array The value to validate as an array.334 * @param string $prop The name of the property, used in error reporting.335 * @param array $schema The schema for the property, used for validation.336 *337 * @return bool338 */339 protected function validate_array( $array, $prop, $schema ) {340 if ( ! is_array( $array ) ) {341 $this->messages->add(342 'error',343 sprintf(344 __( 'The %s property must contain an array value.', 'wporg-plugins' ),345 '<code>' . $prop . '</code>'346 )347 );348 $this->append_error_data( $prop, 'error' );349 350 return false;351 }352 353 if ( isset( $schema['items']['type'] ) ) {354 $results = array();355 $index = 0;356 357 foreach ( $array as $item ) {358 $results[] = $this->route_validation_for_type(359 $schema['items']['type'],360 $item,361 $prop . "[$index]",362 $schema['items']363 );364 $index ++;365 }366 367 return ! in_array( false, $results, true );368 }369 370 return true;371 }372 373 /**374 * Validate a string.375 *376 * @param string $string The value to validate as a string.377 * @param string $prop The name of the property, used in error reporting.378 * @param array $schema The schema for the property, used for validation.379 *380 * @return bool381 */382 protected function validate_string( $string, $prop, $schema ) {383 if ( ! is_string( $string ) ) {384 $this->messages->add(385 'error',386 sprintf(387 __( 'The %s property must contain a string value.', 'wporg-plugins' ),388 '<code>' . $prop . '</code>'389 )390 );391 $this->append_error_data( $prop, 'error' );392 393 return false;394 }395 396 if ( isset( $schema['enum'] ) ) {397 if ( ! in_array( $string, $schema['enum'], true ) ) {398 $this->messages->add(399 'warning',400 sprintf(401 __( '"%1$s" is not a valid value for the %2$s property.', 'wporg-plugins' ),402 esc_html( $string ),403 '<code>' . $prop . '</code>'404 )405 );406 $this->append_error_data( $prop, 'warning' );407 }408 }409 410 if ( isset( $schema['pattern'] ) ) {411 if ( ! preg_match( '#' . $schema['pattern'] . '#', $string ) ) {412 $pattern_description = $this->get_human_readable_pattern_description( $schema['pattern'] );413 if ( $pattern_description ) {414 $message = sprintf(415 $pattern_description,416 '<code>' . $prop . '</code>'417 );418 } else {419 $message = sprintf(420 __( 'The value of %s does not match the required pattern.', 'wporg-plugins' ),421 '<code>' . $prop . '</code>'422 );423 }424 425 $this->messages->add( 'warning', $message );426 $this->append_error_data( $prop, 'warning' );427 }428 }429 430 return true;431 }432 433 /**434 * Validate a boolean.435 *436 * @param bool $boolean The value to validate as a boolean.437 * @param string $prop The name of the property, used in error reporting.438 *439 * @return bool440 */441 protected function validate_boolean( $boolean, $prop ) {442 if ( ! is_bool( $boolean ) ) {443 $this->messages->add(444 'error',445 sprintf(446 __( 'The %s property must contain a boolean value.', 'wporg-plugins' ),447 '<code>' . $prop . '</code>'448 )449 );450 $this->append_error_data( $prop, 'error' );451 452 return false;453 }454 455 return true;456 }457 458 /**459 * Send a property value to the correct validator depending on which type(s) it can be.460 *461 * @param string|array $valid_types462 * @param mixed $value463 * @param string $prop464 * @param array $schema465 *466 * @return bool467 */468 protected function route_validation_for_type( $valid_types, $value, $prop, $schema ) {469 // There is a single valid type.470 if ( is_string( $valid_types ) ) {471 $method = "validate_$valid_types";472 return $this->$method( $value, $prop, $schema );473 }474 475 // There are multiple valid types in an array.476 foreach ( $valid_types as $type ) {477 switch ( $type ) {478 case 'boolean':479 $check = 'is_bool';480 break;481 default:482 $check = "is_$type";483 break;484 }485 486 if ( $check( $value ) ) {487 $method = "validate_$type";488 return $this->$method( $value, $prop, $schema );489 }490 }491 492 // Made it this far, it's none of the valid types.493 $this->messages->add(494 'error',495 sprintf(496 __( 'The %1$s property must contain a value that is one of these types: %2$s', 'wporg-plugins' ),497 '<code>' . $prop . '</code>',498 // translators: used between list items, there is a space after the comma.499 '<code>' . implode( '</code>' . __( ', ', 'wporg-plugins' ) . '<code>', $valid_types ) . '</code>'500 )501 );502 $this->append_error_data( $prop, 'error' );503 504 return false;505 107 } 506 108 … … 520 122 $this->messages->add_data( $data, $error_code ); 521 123 } 522 523 /**524 * Get a description of a regex pattern that can be understood by humans.525 *526 * @param string $pattern A regex pattern.527 *528 * @return string529 */530 protected function get_human_readable_pattern_description( $pattern ) {531 $description = '';532 533 switch ( $pattern ) {534 case '\.css$':535 $description = __( 'The value of %s must end in ".css".', 'wporg-plugins' );536 break;537 case '\.js$':538 $description = __( 'The value of %s must end in ".js".', 'wporg-plugins' );539 break;540 }541 542 return $description;543 }544 124 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
r11291 r11410 626 626 $potential_block_directories[] = dirname( $relative_filename ); 627 627 foreach ( $blocks_in_file as $block ) { 628 $blocks[ $block->name ] = $block; 628 if ( isset( $blocks[ $block->name ] ) ) { 629 $blocks[ $block->name ] = (object) array_merge( (array) $blocks[ $block->name ], array_filter( (array) $block ) ); 630 } else { 631 $blocks[ $block->name ] = $block; 632 } 629 633 } 630 634 } … … 792 796 // Only certain properties must be valid for our purposes here. 793 797 $required_valid_props = array( 794 'block.json', 795 'block.json:editorScript', 796 'block.json:editorStyle', 797 'block.json:name', 798 'block.json:script', 799 'block.json:style', 798 'block.json[editorScript]', 799 'block.json[editorStyle]', 800 'block.json[name]', 801 'block.json[script]', 802 'block.json[style]', 800 803 ); 801 $invalid_props = array_intersect( $required_valid_props, $result->get_error_data( 'error' ) ?: [] ); 802 if ( empty( $invalid_props ) ) { 804 $error = $result->get_error_message(); 805 $is_json_valid = array_reduce( 806 $required_valid_props, 807 function( $is_valid, $prop ) use ( $error ) { 808 return $is_valid && ( false === strpos( $error, $prop ) ); 809 }, 810 true 811 ); 812 if ( $is_json_valid ) { 803 813 $blocks[] = $block; 804 814 }
Note: See TracChangeset
for help on using the changeset viewer.