From 9c065ac201a83d2ceb0ec50e1a0da0ee3b22e64c Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 23 Jun 2020 18:10:26 +0200 Subject: [PATCH 1/7] Editor: Introduce WP_Block class --- src/wp-includes/class-wp-block.php | 220 ++++++++++++++++ tests/phpunit/tests/blocks/block.php | 358 +++++++++++++++++++++++++++ 2 files changed, 578 insertions(+) create mode 100644 src/wp-includes/class-wp-block.php create mode 100644 tests/phpunit/tests/blocks/block.php diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php new file mode 100644 index 0000000000000..1165a82bd421d --- /dev/null +++ b/src/wp-includes/class-wp-block.php @@ -0,0 +1,220 @@ + testing..." -> "Just testing..." + * + * @var string + */ + public $inner_html = ''; + + /** + * List of string fragments and null markers where inner blocks were found + * + * @example array( + * 'inner_html' => 'BeforeInnerAfter', + * 'inner_blocks' => array( block, block ), + * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), + * ) + * + * @var array + */ + public $inner_content = array(); + + /** + * Constructor. + * + * Populates object properties from the provided block instance argument. + * + * The given array of context values will not necessarily be available on + * the instance itself, but is treated as the full set of values provided by + * the block's ancestry. This is assigned to the private `available_context` + * property. Only values which are configured to consumed by the block via + * its registered type will be assigned to the block's `context` property. + * + * @param array $block Array of parsed block properties. + * @param array $available_context Optional array of ancestry context values. + * @param WP_Block_Type_Registry $registry Optional block type registry. + */ + public function __construct( $block, $available_context = array(), $registry = null ) { + $this->parsed_block = $block; + $this->name = $block['blockName']; + + if ( is_null( $registry ) ) { + $registry = WP_Block_Type_Registry::get_instance(); + } + + $this->block_type = $registry->get_registered( $this->name ); + + $this->available_context = $available_context; + + if ( ! empty( $this->block_type->uses_context ) ) { + foreach ( $this->block_type->uses_context as $context_name ) { + if ( array_key_exists( $context_name, $this->available_context ) ) { + $this->context[ $context_name ] = $this->available_context[ $context_name ]; + } + } + } + + if ( ! empty( $block['innerBlocks'] ) ) { + $child_context = $this->available_context; + + if ( ! empty( $this->block_type->provides_context ) ) { + foreach ( $this->block_type->provides_context as $context_name => $attribute_name ) { + if ( array_key_exists( $attribute_name, $this->attributes ) ) { + $child_context[ $context_name ] = $this->attributes[ $attribute_name ]; + } + } + } + + $this->inner_blocks = new WP_Block_List( $block['innerBlocks'], $child_context, $registry ); + } + + if ( ! empty( $block['innerHTML'] ) ) { + $this->inner_html = $block['innerHTML']; + } + + if ( ! empty( $block['innerContent'] ) ) { + $this->inner_content = $block['innerContent']; + } + } + + /** + * Returns a value from an inaccessible property. + * + * This is used to lazily initialize the `attributes` property of a block, + * such that it is only prepared with default attributes at the time that + * the property is accessed. For all other inaccessible properties, a `null` + * value is returned. + * + * @param string $name Property name. + * + * @return array|null Prepared attributes, or null. + */ + public function __get( $name ) { + if ( 'attributes' === $name ) { + $this->attributes = isset( $this->parsed_block['attrs'] ) ? + $this->parsed_block['attrs'] : + array(); + + if ( ! is_null( $this->block_type ) ) { + $this->attributes = $this->block_type->prepare_attributes_for_render( $this->attributes ); + } + + return $this->attributes; + } + + return null; + } + + /** + * Generates the render output for the block. + * + * @param array $options { + * Optional options object. + * + * @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback. + * } + * + * @return string Rendered block output. + */ + public function render( $options = array() ) { + global $post; + $options = array_replace( + array( + 'dynamic' => true, + ), + $options + ); + + $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); + $block_content = ''; + + if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) { + $index = 0; + foreach ( $this->inner_content as $chunk ) { + $block_content .= is_string( $chunk ) ? + $chunk : + $this->inner_blocks[ $index++ ]->render(); + } + } + + if ( $is_dynamic ) { + $global_post = $post; + $block_content = (string) call_user_func( $this->block_type->render_callback, $this->attributes, $block_content, $this ); + $post = $global_post; + } + + if ( ! empty( $this->block_type->script ) ) { + wp_enqueue_script( $this->block_type->script ); + } + + if ( ! empty( $this->block_type->style ) ) { + wp_enqueue_style( $this->block_type->style ); + } + + /** This filter is documented in src/wp-includes/blocks.php */ + return apply_filters( 'render_block', $block_content, $this->parsed_block ); + } + +} diff --git a/tests/phpunit/tests/blocks/block.php b/tests/phpunit/tests/blocks/block.php new file mode 100644 index 0000000000000..6fee1f4fb5897 --- /dev/null +++ b/tests/phpunit/tests/blocks/block.php @@ -0,0 +1,358 @@ +registry = new WP_Block_Type_Registry(); + } + + /** + * Tear down each test method. + */ + public function tearDown() { + parent::tearDown(); + + $this->registry = null; + } + + function filter_render_block( $content, $parsed_block ) { + return 'Original: "' . $content . '", from block "' . $parsed_block['blockName'] . '"'; + } + + function test_constructor_assigns_properties_from_parsed_block() { + $this->registry->register( 'core/example', array() ); + + $parsed_blocks = parse_blocks( 'ab' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( $parsed_block, $block->parsed_block ); + $this->assertEquals( $parsed_block['blockName'], $block->name ); + $this->assertEquals( $parsed_block['attrs'], $block->attributes ); + $this->assertEquals( $parsed_block['innerContent'], $block->inner_content ); + $this->assertEquals( $parsed_block['innerHTML'], $block->inner_html ); + } + + function test_constructor_assigns_block_type_from_registry() { + $block_type_settings = array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ); + $this->registry->register( 'core/example', $block_type_settings ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertInstanceOf( WP_Block_Type::class, $block->block_type ); + $this->assertEquals( + $block_type_settings['attributes'], + $block->block_type->attributes + ); + } + + function test_lazily_assigns_attributes_with_defaults() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ) + ); + + $parsed_block = array( + 'blockName' => 'core/example', + 'attrs' => array( + 'explicit' => 20, + ), + ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( + array( + 'defaulted' => 10, + 'explicit' => 20, + ), + $block->attributes + ); + } + + function test_lazily_assigns_attributes_with_only_defaults() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'defaulted' => array( + 'type' => 'number', + 'default' => 10, + ), + ), + ) + ); + + $parsed_block = array( + 'blockName' => 'core/example', + 'attrs' => array(), + ); + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( array( 'defaulted' => 10 ), $block->attributes ); + // Intentionally call a second time, to ensure property was assigned. + $this->assertEquals( array( 'defaulted' => 10 ), $block->attributes ); + } + + function test_constructor_assigns_context_from_block_type() { + $this->registry->register( + 'core/example', + array( + 'uses_context' => array( 'requested' ), + ) + ); + + $parsed_block = array( 'blockName' => 'core/example' ); + $context = array( + 'requested' => 'included', + 'unrequested' => 'not included', + ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( array( 'requested' => 'included' ), $block->context ); + } + + function test_constructor_maps_inner_blocks() { + $this->registry->register( 'core/example', array() ); + + $parsed_blocks = parse_blocks( 'ab' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertCount( 1, $block->inner_blocks ); + $this->assertInstanceOf( WP_Block::class, $block->inner_blocks[0] ); + $this->assertEquals( 'core/example', $block->inner_blocks[0]->name ); + } + + function test_constructor_prepares_context_for_inner_blocks() { + $this->registry->register( + 'core/outer', + array( + 'attributes' => array( + 'recordId' => array( + 'type' => 'number', + ), + ), + 'provides_context' => array( + 'core/recordId' => 'recordId', + ), + ) + ); + $this->registry->register( + 'core/inner', + array( + 'uses_context' => array( 'core/recordId' ), + ) + ); + + $parsed_blocks = parse_blocks( '' ); + $parsed_block = $parsed_blocks[0]; + $context = array( 'unrequested' => 'not included' ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertCount( 0, $block->context ); + $this->assertEquals( + array( 'core/recordId' => 10 ), + $block->inner_blocks[0]->context + ); + } + + function test_constructor_assigns_merged_context() { + $this->registry->register( + 'core/example', + array( + 'attributes' => array( + 'value' => array( + 'type' => array( 'string', 'null' ), + ), + ), + 'provides_context' => array( + 'core/value' => 'value', + ), + 'uses_context' => array( 'core/value' ), + ) + ); + + $parsed_blocks = parse_blocks( + '' . + '' . + '' . + '' . + '' + ); + $parsed_block = $parsed_blocks[0]; + $context = array( 'core/value' => 'original' ); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertEquals( + array( 'core/value' => 'original' ), + $block->context + ); + $this->assertEquals( + array( 'core/value' => 'merged' ), + $block->inner_blocks[0]->context + ); + $this->assertEquals( + array( 'core/value' => null ), + $block->inner_blocks[0]->inner_blocks[0]->context + ); + } + + function test_render_static_block_type_returns_own_content() { + $this->registry->register( 'core/static', array() ); + $this->registry->register( + 'core/dynamic', + array( + 'render_callback' => function() { + return 'b'; + }, + ) + ); + + $parsed_blocks = parse_blocks( 'ac' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'abc', $block->render() ); + } + + function test_render_passes_block_for_render_callback() { + $this->registry->register( + 'core/greeting', + array( + 'render_callback' => function( $attributes, $content, $block ) { + return sprintf( 'Hello from %s', $block->name ); + }, + ) + ); + + $parsed_blocks = parse_blocks( '' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'Hello from core/greeting', $block->render() ); + } + + function test_render_applies_render_block_filter() { + $this->registry->register( 'core/example', array() ); + + add_filter( 'render_block', array( $this, 'filter_render_block' ), 10, 2 ); + + $parsed_blocks = parse_blocks( 'StaticInner' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $rendered_content = $block->render(); + + remove_filter( 'render_block', array( $this, 'filter_render_block' ) ); + + $this->assertSame( 'Original: "StaticOriginal: "Inner", from block "core/example"", from block "core/example"', $rendered_content ); + + } + + function test_passes_attributes_to_render_callback() { + $this->registry->register( + 'core/greeting', + array( + 'attributes' => array( + 'toWhom' => array( + 'type' => 'string', + ), + 'punctuation' => array( + 'type' => 'string', + 'default' => '!', + ), + ), + 'render_callback' => function( $block_attributes ) { + return sprintf( + 'Hello %s%s', + $block_attributes['toWhom'], + $block_attributes['punctuation'] + ); + }, + ) + ); + + $parsed_blocks = parse_blocks( '' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'Hello world!', $block->render() ); + } + + function test_passes_content_to_render_callback() { + $this->registry->register( + 'core/outer', + array( + 'render_callback' => function( $block_attributes, $content ) { + return $content; + }, + ) + ); + $this->registry->register( + 'core/inner', + array( + 'render_callback' => function() { + return 'b'; + }, + ) + ); + + $parsed_blocks = parse_blocks( 'ac' ); + $parsed_block = $parsed_blocks[0]; + $context = array(); + $block = new WP_Block( $parsed_block, $context, $this->registry ); + + $this->assertSame( 'abc', $block->render() ); + } + +} From 878ef0bbfa5b9c88a5f945c60139f504f947fd9e Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 23 Jun 2020 21:56:10 +0200 Subject: [PATCH 2/7] Add WP_Block_List class --- src/wp-includes/class-wp-block-list.php | 188 ++++++++++++++++++++++ src/wp-includes/class-wp-block.php | 2 - src/wp-settings.php | 2 + tests/phpunit/tests/blocks/block-list.php | 112 +++++++++++++ tests/phpunit/tests/blocks/block.php | 39 +++++ 5 files changed, 341 insertions(+), 2 deletions(-) create mode 100644 src/wp-includes/class-wp-block-list.php create mode 100644 tests/phpunit/tests/blocks/block-list.php diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php new file mode 100644 index 0000000000000..1b970b85700dd --- /dev/null +++ b/src/wp-includes/class-wp-block-list.php @@ -0,0 +1,188 @@ +blocks = $blocks; + $this->available_context = $available_context; + $this->registry = $registry; + } + + /* + * ArrayAccess interface methods. + */ + + /** + * Returns true if a block exists by the specified block index, or false + * otherwise. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php + * + * @param string $index Index of block to check. + * @return bool Whether block exists. + */ + public function offsetExists( $index ) { + return isset( $this->blocks[ $index ] ); + } + + /** + * Returns the value by the specified block index. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetget.php + * + * @param string $index Index of block value to retrieve. + * @return mixed|null Block value if exists, or null. + */ + public function offsetGet( $index ) { + $block = $this->blocks[ $index ]; + + if ( isset( $block ) && is_array( $block ) ) { + $block = new WP_Block( $block, $this->available_context, $this->registry ); + $this->blocks[ $index ] = $block; + } + + return $block; + } + + /** + * Assign a block value by the specified block index. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetset.php + * + * @param string $index Index of block value to set. + * @param mixed $value Block value. + */ + public function offsetSet( $index, $value ) { + if ( is_null( $index ) ) { + $this->blocks[] = $value; + } else { + $this->blocks[ $index ] = $value; + } + } + + /** + * Unset a block. + * + * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php + * + * @param string $index Index of block value to unset. + */ + public function offsetUnset( $index ) { + unset( $this->blocks[ $index ] ); + } + + /* + * Iterator interface methods. + */ + + /** + * Rewinds back to the first element of the Iterator. + * + * @link https://www.php.net/manual/en/iterator.rewind.php + */ + public function rewind() { + reset( $this->blocks ); + } + + /** + * Returns the current element of the block list. + * + * @link https://www.php.net/manual/en/iterator.current.php + * + * @return mixed Current element. + */ + public function current() { + return $this->offsetGet( $this->key() ); + } + + /** + * Returns the key of the current element of the block list. + * + * @link https://www.php.net/manual/en/iterator.key.php + * + * @return mixed Key of the current element. + */ + public function key() { + return key( $this->blocks ); + } + + /** + * Moves the current position of the block list to the next element. + * + * @link https://www.php.net/manual/en/iterator.next.php + */ + public function next() { + next( $this->blocks ); + } + + /** + * Checks if current position is valid. + * + * @link https://www.php.net/manual/en/iterator.valid.php + */ + public function valid() { + return null !== key( $this->blocks ); + } + + /* + * Countable interface methods. + */ + + /** + * Returns the count of blocks in the list. + * + * @link https://www.php.net/manual/en/countable.count.php + * + * @return int Block count. + */ + public function count() { + return count( $this->blocks ); + } + +} diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 1165a82bd421d..23dbd6671c657 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -148,7 +148,6 @@ public function __construct( $block, $available_context = array(), $registry = n * value is returned. * * @param string $name Property name. - * * @return array|null Prepared attributes, or null. */ public function __get( $name ) { @@ -175,7 +174,6 @@ public function __get( $name ) { * * @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback. * } - * * @return string Rendered block output. */ public function render( $options = array() ) { diff --git a/src/wp-settings.php b/src/wp-settings.php index a78be1c0918c0..a1cec18559a21 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -276,6 +276,8 @@ require ABSPATH . WPINC . '/class-wp-block-type.php'; require ABSPATH . WPINC . '/class-wp-block-styles-registry.php'; require ABSPATH . WPINC . '/class-wp-block-type-registry.php'; +require ABSPATH . WPINC . '/class-wp-block.php'; +require ABSPATH . WPINC . '/class-wp-block-list.php'; require ABSPATH . WPINC . '/class-wp-block-parser.php'; require ABSPATH . WPINC . '/blocks.php'; require ABSPATH . WPINC . '/blocks/archives.php'; diff --git a/tests/phpunit/tests/blocks/block-list.php b/tests/phpunit/tests/blocks/block-list.php new file mode 100644 index 0000000000000..c5d5e543acdea --- /dev/null +++ b/tests/phpunit/tests/blocks/block-list.php @@ -0,0 +1,112 @@ +registry = new WP_Block_Type_Registry(); + $this->registry->register( 'core/example', array() ); + } + + /** + * Tear down each test method. + */ + public function tearDown() { + parent::tearDown(); + + $this->registry = null; + } + + /** + * @ticket 49927 + */ + function test_array_access() { + $parsed_blocks = parse_blocks( '' ); + $context = array(); + $blocks = new WP_Block_List( $parsed_blocks, $context, $this->registry ); + + // Test "offsetExists". + $this->assertTrue( isset( $blocks[0] ) ); + + // Test "offsetGet". + $this->assertEquals( 'core/example', $blocks[0]->name ); + + // Test "offsetSet". + $parsed_blocks[0]['blockName'] = 'core/updated'; + $blocks[0] = new WP_Block( $parsed_blocks[0], $context, $this->registry ); + $this->assertEquals( 'core/updated', $blocks[0]->name ); + + // Test "offsetUnset". + unset( $blocks[0] ); + $this->assertFalse( isset( $blocks[0] ) ); + } + + /** + * @ticket 49927 + */ + function test_iterable() { + $parsed_blocks = parse_blocks( '' ); + $context = array(); + $blocks = new WP_Block_List( $parsed_blocks, $context, $this->registry ); + $assertions = 0; + + foreach ( $blocks as $block ) { + $this->assertEquals( 'core/example', $block->name ); + $assertions++; + foreach ( $block->inner_blocks as $inner_block ) { + $this->assertEquals( 'core/example', $inner_block->name ); + $assertions++; + } + } + + $blocks->rewind(); + while ( $blocks->valid() ) { + $key = $blocks->key(); + $block = $blocks->current(); + $this->assertEquals( 0, $key ); + $assertions++; + $this->assertEquals( 'core/example', $block->name ); + $assertions++; + $blocks->next(); + } + + $this->assertEquals( 4, $assertions ); + } + + /** + * @ticket 49927 + */ + function test_countable() { + $parsed_blocks = parse_blocks( '' ); + $context = array(); + $blocks = new WP_Block_List( $parsed_blocks, $context, $this->registry ); + + $this->assertEquals( 1, count( $blocks ) ); + } + +} diff --git a/tests/phpunit/tests/blocks/block.php b/tests/phpunit/tests/blocks/block.php index 6fee1f4fb5897..2a702a5bc43c3 100644 --- a/tests/phpunit/tests/blocks/block.php +++ b/tests/phpunit/tests/blocks/block.php @@ -45,6 +45,9 @@ function filter_render_block( $content, $parsed_block ) { return 'Original: "' . $content . '", from block "' . $parsed_block['blockName'] . '"'; } + /** + * @ticket 49927 + */ function test_constructor_assigns_properties_from_parsed_block() { $this->registry->register( 'core/example', array() ); @@ -60,6 +63,9 @@ function test_constructor_assigns_properties_from_parsed_block() { $this->assertEquals( $parsed_block['innerHTML'], $block->inner_html ); } + /** + * @ticket 49927 + */ function test_constructor_assigns_block_type_from_registry() { $block_type_settings = array( 'attributes' => array( @@ -82,6 +88,9 @@ function test_constructor_assigns_block_type_from_registry() { ); } + /** + * @ticket 49927 + */ function test_lazily_assigns_attributes_with_defaults() { $this->registry->register( 'core/example', @@ -113,6 +122,9 @@ function test_lazily_assigns_attributes_with_defaults() { ); } + /** + * @ticket 49927 + */ function test_lazily_assigns_attributes_with_only_defaults() { $this->registry->register( 'core/example', @@ -138,6 +150,9 @@ function test_lazily_assigns_attributes_with_only_defaults() { $this->assertEquals( array( 'defaulted' => 10 ), $block->attributes ); } + /** + * @ticket 49927 + */ function test_constructor_assigns_context_from_block_type() { $this->registry->register( 'core/example', @@ -156,6 +171,9 @@ function test_constructor_assigns_context_from_block_type() { $this->assertEquals( array( 'requested' => 'included' ), $block->context ); } + /** + * @ticket 49927 + */ function test_constructor_maps_inner_blocks() { $this->registry->register( 'core/example', array() ); @@ -169,6 +187,9 @@ function test_constructor_maps_inner_blocks() { $this->assertEquals( 'core/example', $block->inner_blocks[0]->name ); } + /** + * @ticket 49927 + */ function test_constructor_prepares_context_for_inner_blocks() { $this->registry->register( 'core/outer', @@ -202,6 +223,9 @@ function test_constructor_prepares_context_for_inner_blocks() { ); } + /** + * @ticket 49927 + */ function test_constructor_assigns_merged_context() { $this->registry->register( 'core/example', @@ -243,6 +267,9 @@ function test_constructor_assigns_merged_context() { ); } + /** + * @ticket 49927 + */ function test_render_static_block_type_returns_own_content() { $this->registry->register( 'core/static', array() ); $this->registry->register( @@ -262,6 +289,9 @@ function test_render_static_block_type_returns_own_content() { $this->assertSame( 'abc', $block->render() ); } + /** + * @ticket 49927 + */ function test_render_passes_block_for_render_callback() { $this->registry->register( 'core/greeting', @@ -280,6 +310,9 @@ function test_render_passes_block_for_render_callback() { $this->assertSame( 'Hello from core/greeting', $block->render() ); } + /** + * @ticket 49927 + */ function test_render_applies_render_block_filter() { $this->registry->register( 'core/example', array() ); @@ -298,6 +331,9 @@ function test_render_applies_render_block_filter() { } + /** + * @ticket 49927 + */ function test_passes_attributes_to_render_callback() { $this->registry->register( 'core/greeting', @@ -329,6 +365,9 @@ function test_passes_attributes_to_render_callback() { $this->assertSame( 'Hello world!', $block->render() ); } + /** + * @ticket 49927 + */ function test_passes_content_to_render_callback() { $this->registry->register( 'core/outer', From 65cb095db38e652944e676e33dd73723355c773e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 24 Jun 2020 13:01:53 +0200 Subject: [PATCH 3/7] Update src/wp-includes/class-wp-block-list.php Co-authored-by: Timothy Jacobs --- src/wp-includes/class-wp-block-list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php index 1b970b85700dd..c44a5c11726d3 100644 --- a/src/wp-includes/class-wp-block-list.php +++ b/src/wp-includes/class-wp-block-list.php @@ -45,7 +45,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { * @param WP_Block_Type_Registry $registry Optional block type registry. */ public function __construct( $blocks, $available_context = array(), $registry = null ) { - if ( is_null( $registry ) ) { + if ( ! $registry instanced WP_Block_Type_Registry ) { $registry = WP_Block_Type_Registry::get_instance(); } From fd566358529260ca581225f2370833d4be1666ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 24 Jun 2020 13:09:35 +0200 Subject: [PATCH 4/7] Add since tag to code comments --- src/wp-includes/class-wp-block-list.php | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php index c44a5c11726d3..d4fb986ac29d0 100644 --- a/src/wp-includes/class-wp-block-list.php +++ b/src/wp-includes/class-wp-block-list.php @@ -14,6 +14,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { /** * Original array of parsed block data. * + * @since 5.5.0 * @var array|WP_Block[] * @access protected */ @@ -22,6 +23,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { /** * All available context of the current hierarchy. * + * @since 5.5.0 * @var array * @access protected */ @@ -30,6 +32,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { /** * Block type registry to use in constructing block instances. * + * @since 5.5.0 * @var WP_Block_Type_Registry * @access protected */ @@ -40,6 +43,8 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { * * Populates object properties from the provided block instance argument. * + * @since 5.5.0 + * * @param array|WP_Block[] $blocks Array of parsed block data, or block instances. * @param array $available_context Optional array of ancestry context values. * @param WP_Block_Type_Registry $registry Optional block type registry. @@ -54,14 +59,12 @@ public function __construct( $blocks, $available_context = array(), $registry = $this->registry = $registry; } - /* - * ArrayAccess interface methods. - */ - /** * Returns true if a block exists by the specified block index, or false * otherwise. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/arrayaccess.offsetexists.php * * @param string $index Index of block to check. @@ -74,6 +77,8 @@ public function offsetExists( $index ) { /** * Returns the value by the specified block index. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/arrayaccess.offsetget.php * * @param string $index Index of block value to retrieve. @@ -93,6 +98,8 @@ public function offsetGet( $index ) { /** * Assign a block value by the specified block index. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/arrayaccess.offsetset.php * * @param string $index Index of block value to set. @@ -109,6 +116,8 @@ public function offsetSet( $index, $value ) { /** * Unset a block. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/arrayaccess.offsetunset.php * * @param string $index Index of block value to unset. @@ -117,13 +126,11 @@ public function offsetUnset( $index ) { unset( $this->blocks[ $index ] ); } - /* - * Iterator interface methods. - */ - /** * Rewinds back to the first element of the Iterator. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/iterator.rewind.php */ public function rewind() { @@ -133,6 +140,8 @@ public function rewind() { /** * Returns the current element of the block list. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/iterator.current.php * * @return mixed Current element. @@ -144,6 +153,8 @@ public function current() { /** * Returns the key of the current element of the block list. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/iterator.key.php * * @return mixed Key of the current element. @@ -155,6 +166,8 @@ public function key() { /** * Moves the current position of the block list to the next element. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/iterator.next.php */ public function next() { @@ -164,6 +177,8 @@ public function next() { /** * Checks if current position is valid. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/iterator.valid.php */ public function valid() { @@ -177,6 +192,8 @@ public function valid() { /** * Returns the count of blocks in the list. * + * @since 5.5.0 + * * @link https://www.php.net/manual/en/countable.count.php * * @return int Block count. From 7385d1012759a6466ce2738d3d52f58b95b689d4 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 24 Jun 2020 14:01:39 +0200 Subject: [PATCH 5/7] Address feedback from review --- src/wp-includes/class-wp-block-list.php | 8 +++----- src/wp-includes/class-wp-block.php | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php index d4fb986ac29d0..1ab7dc5fdf80b 100644 --- a/src/wp-includes/class-wp-block-list.php +++ b/src/wp-includes/class-wp-block-list.php @@ -8,6 +8,8 @@ /** * Class representing a list of block instances. + * + * @since 5.5.0 */ class WP_Block_List implements Iterator, ArrayAccess, Countable { @@ -50,7 +52,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { * @param WP_Block_Type_Registry $registry Optional block type registry. */ public function __construct( $blocks, $available_context = array(), $registry = null ) { - if ( ! $registry instanced WP_Block_Type_Registry ) { + if ( ! $registry instanceof WP_Block_Type_Registry ) { $registry = WP_Block_Type_Registry::get_instance(); } @@ -185,10 +187,6 @@ public function valid() { return null !== key( $this->blocks ); } - /* - * Countable interface methods. - */ - /** * Returns the count of blocks in the list. * diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 23dbd6671c657..7a8cefd1a5e0a 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -9,6 +9,7 @@ /** * Class representing a parsed instance of a block. * + * @since 5.5.0 * @property array $attributes */ class WP_Block { @@ -16,6 +17,7 @@ class WP_Block { /** * Original parsed array representation of block. * + * @since 5.5.0 * @var array */ public $parsed_block; @@ -25,6 +27,7 @@ class WP_Block { * * @example "core/paragraph" * + * @since 5.5.0 * @var string */ public $name; @@ -32,6 +35,7 @@ class WP_Block { /** * Block type associated with the instance. * + * @since 5.5.0 * @var WP_Block_Type */ public $block_type; @@ -39,6 +43,7 @@ class WP_Block { /** * Block context values. * + * @since 5.5.0 * @var array */ public $context = array(); @@ -46,6 +51,7 @@ class WP_Block { /** * All available context of the current hierarchy. * + * @since 5.5.0 * @var array * @access protected */ @@ -54,6 +60,7 @@ class WP_Block { /** * List of inner blocks (of this same class) * + * @since 5.5.0 * @var WP_Block[] */ public $inner_blocks = array(); @@ -64,6 +71,7 @@ class WP_Block { * * @example "...Just testing..." -> "Just testing..." * + * @since 5.5.0 * @var string */ public $inner_html = ''; @@ -77,6 +85,7 @@ class WP_Block { * 'inner_content' => array( 'Before', null, 'Inner', null, 'After' ), * ) * + * @since 5.5.0 * @var array */ public $inner_content = array(); @@ -92,6 +101,8 @@ class WP_Block { * property. Only values which are configured to consumed by the block via * its registered type will be assigned to the block's `context` property. * + * @since 5.5.0 + * * @param array $block Array of parsed block properties. * @param array $available_context Optional array of ancestry context values. * @param WP_Block_Type_Registry $registry Optional block type registry. @@ -147,6 +158,8 @@ public function __construct( $block, $available_context = array(), $registry = n * the property is accessed. For all other inaccessible properties, a `null` * value is returned. * + * @since 5.5.0 + * * @param string $name Property name. * @return array|null Prepared attributes, or null. */ @@ -169,6 +182,8 @@ public function __get( $name ) { /** * Generates the render output for the block. * + * @since 5.5.0 + * * @param array $options { * Optional options object. * @@ -178,11 +193,11 @@ public function __get( $name ) { */ public function render( $options = array() ) { global $post; - $options = array_replace( + $options = wp_parse_args( + $options, array( 'dynamic' => true, ), - $options ); $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); From 5de69dd46ca925bd857e5fc2fe5f3917c27b1930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 24 Jun 2020 16:04:49 +0200 Subject: [PATCH 6/7] Update class-wp-block.php --- src/wp-includes/class-wp-block.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php index 7a8cefd1a5e0a..979fca90708f1 100644 --- a/src/wp-includes/class-wp-block.php +++ b/src/wp-includes/class-wp-block.php @@ -197,7 +197,7 @@ public function render( $options = array() ) { $options, array( 'dynamic' => true, - ), + ) ); $is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic(); From 4b11da6bb8261ed76b202e069576502e693531db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 24 Jun 2020 22:18:53 +0200 Subject: [PATCH 7/7] Update class-wp-block-list.php --- src/wp-includes/class-wp-block-list.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-block-list.php b/src/wp-includes/class-wp-block-list.php index 1ab7dc5fdf80b..378faba578b11 100644 --- a/src/wp-includes/class-wp-block-list.php +++ b/src/wp-includes/class-wp-block-list.php @@ -14,10 +14,10 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { /** - * Original array of parsed block data. + * Original array of parsed block data, or block instances. * * @since 5.5.0 - * @var array|WP_Block[] + * @var array[]|WP_Block[] * @access protected */ protected $blocks; @@ -47,7 +47,7 @@ class WP_Block_List implements Iterator, ArrayAccess, Countable { * * @since 5.5.0 * - * @param array|WP_Block[] $blocks Array of parsed block data, or block instances. + * @param array[]|WP_Block[] $blocks Array of parsed block data, or block instances. * @param array $available_context Optional array of ancestry context values. * @param WP_Block_Type_Registry $registry Optional block type registry. */