Skip to content

Commit

Permalink
Block API: Preserve unknown, respect null in server attributes prep…
Browse files Browse the repository at this point in the history
…aration (#12003)

* Framework: Preserve unknown attributes in block render

* Framework: Respect null as a valid attribute type

* REST API: Update block renderer test to omit undefined defaults

* REST API: Assign default for block renderer attributes

Previously we would pass `NULL` to `render`. While `render` provides a default `array()` value, since an explicit value is provided, it would not take effect. With this change, the endpoint assures a default value to be provided as a parameter to get the `get_item` callback that is compatible with the function signature of `WP_BlockType::render`.

Alternatively, it could be considered to have separate invocations of `render`, depending on whether the request parameter is set.
  • Loading branch information
aduth authored and gziolo committed Nov 20, 2018
1 parent 9297fc9 commit 53c975b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 17 deletions.
39 changes: 25 additions & 14 deletions lib/class-wp-block-type.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,36 +120,47 @@ public function is_dynamic() {

/**
* Validates attributes against the current block schema, populating
* defaulted and missing values, and omitting unknown attributes.
* defaulted and missing values.
*
* @param array $attributes Original block attributes.
* @return array Prepared block attributes.
*/
public function prepare_attributes_for_render( $attributes ) {
// If there are no attribute definitions for the block type, skip
// processing and return vebatim.
if ( ! isset( $this->attributes ) ) {
return $attributes;
}

$prepared_attributes = array();
foreach ( $attributes as $attribute_name => $value ) {
// If the attribute is not defined by the block type, it cannot be
// validated.
if ( ! isset( $this->attributes[ $attribute_name ] ) ) {
continue;
}

foreach ( $this->attributes as $attribute_name => $schema ) {
$value = null;
$schema = $this->attributes[ $attribute_name ];

if ( isset( $attributes[ $attribute_name ] ) ) {
$is_valid = rest_validate_value_from_schema( $attributes[ $attribute_name ], $schema );
if ( ! is_wp_error( $is_valid ) ) {
$value = rest_sanitize_value_from_schema( $attributes[ $attribute_name ], $schema );
}
// Validate value by JSON schema. An invalid value should revert to
// its default, if one exists. This occurs by virtue of the missing
// attributes loop immediately following. If there is not a default
// assigned, the attribute value should remain unset.
$is_valid = rest_validate_value_from_schema( $value, $schema );
if ( is_wp_error( $is_valid ) ) {
unset( $attributes[ $attribute_name ] );
}
}

if ( is_null( $value ) && isset( $schema['default'] ) ) {
$value = $schema['default'];
// Populate values of any missing attributes for which the block type
// defines a default.
$missing_schema_attributes = array_diff_key( $this->attributes, $attributes );
foreach ( $missing_schema_attributes as $attribute_name => $schema ) {
if ( isset( $schema['default'] ) ) {
$attributes[ $attribute_name ] = $schema['default'];
}

$prepared_attributes[ $attribute_name ] = $value;
}

return $prepared_attributes;
return $attributes;
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/class-wp-rest-block-renderer-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public function register_routes() {
'type' => 'object',
'additionalProperties' => false,
'properties' => $block_type->get_attributes(),
'default' => array(),
),
'post_id' => array(
'description' => __( 'ID of the post context.', 'gutenberg' ),
Expand Down
21 changes: 19 additions & 2 deletions phpunit/class-block-type-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ function test_prepare_attributes() {
'wrongType' => 5,
'wrongTypeDefaulted' => 5,
/* missingDefaulted */
'undefined' => 'omit',
'undefined' => 'include',
'intendedNull' => null,
);

$block_type = new WP_Block_Type(
Expand All @@ -160,6 +161,10 @@ function test_prepare_attributes() {
'type' => 'string',
'default' => 'define',
),
'intendedNull' => array(
'type' => array( 'string', 'null' ),
'default' => 'wrong',
),
),
)
);
Expand All @@ -169,14 +174,26 @@ function test_prepare_attributes() {
$this->assertEquals(
array(
'correct' => 'include',
'wrongType' => null,
/* wrongType */
'wrongTypeDefaulted' => 'defaulted',
'missingDefaulted' => 'define',
'undefined' => 'include',
'intendedNull' => null,
),
$prepared_attributes
);
}

function test_prepare_attributes_none_defined() {
$attributes = array( 'exists' => 'keep' );

$block_type = new WP_Block_Type( 'core/dummy', array() );

$prepared_attributes = $block_type->prepare_attributes_for_render( $attributes );

$this->assertEquals( $attributes, $prepared_attributes );
}

function test_has_block_with_mixed_content() {
$mixed_post_content = 'before' .
'<!-- wp:core/dummy --><!-- /wp:core/dummy -->' .
Expand Down
4 changes: 3 additions & 1 deletion phpunit/class-rest-block-renderer-controller-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,9 @@ public function test_get_item_default_attributes() {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( self::$block_name );
$defaults = array();
foreach ( $block_type->attributes as $key => $attribute ) {
$defaults[ $key ] = isset( $attribute['default'] ) ? $attribute['default'] : null;
if ( isset( $attribute['default'] ) ) {
$defaults[ $key ] = $attribute['default'];
}
}

$request = new WP_REST_Request( 'GET', self::$rest_api_route . self::$block_name );
Expand Down

0 comments on commit 53c975b

Please sign in to comment.