diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index f5ea0774..d7f04d55 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -46,7 +46,7 @@
-
+
diff --git a/src/parser/content-parser.php b/src/parser/content-parser.php
index 7d26b950..c9fab6c2 100644
--- a/src/parser/content-parser.php
+++ b/src/parser/content-parser.php
@@ -11,9 +11,11 @@
use Throwable;
use WP_Error;
-use WP_Block_Type;
+use WP_Block;
use WP_Block_Type_Registry;
use Symfony\Component\DomCrawler\Crawler;
+use function apply_filters;
+use function parse_blocks;
/**
* The content parser that would be used to transform a post into an array of blocks, along with their attributes.
@@ -61,21 +63,28 @@ public function __construct( $block_registry = null ) {
* Filter out a block from the blocks output based on:
*
* - include parameter, if it is set or
- * - exclude parameter, if it is set.
+ * - exclude parameter, if it is set or
+ * - whether it is an empty whitespace block
*
* and finally, based on a filter vip_block_data_api__allow_block
*
- * @param array $block Current block.
- * @param string $block_name Name of the block.
- * @param array $filter_options Options to be used for filtering, if any.
+ * @param WP_Block $block Current block.
+ * @param array $filter_options Options to be used for filtering, if any.
*
* @return bool true, if the block should be included or false otherwise
*
* @access private
*/
- public function should_block_be_included( $block, $block_name, $filter_options ) {
+ protected function should_block_be_included( WP_Block $block, array $filter_options ) {
+ $block_name = $block->name;
$is_block_included = true;
+ // Whitespace blocks are always excluded.
+ $is_whitespace_block = null === $block_name && empty( trim( $block->inner_html ) );
+ if ( $is_whitespace_block ) {
+ return false;
+ }
+
if ( ! empty( $filter_options['include'] ) ) {
$is_block_included = in_array( $block_name, $filter_options['include'] );
} elseif ( ! empty( $filter_options['exclude'] ) ) {
@@ -86,11 +95,11 @@ public function should_block_be_included( $block, $block_name, $filter_options )
* Filter out blocks from the blocks output
*
* @param bool $is_block_included True if the block should be included, or false to filter it out.
- * @param string $block_name Name of the parsed block, e.g. 'core/paragraph'.
- * @param string $block Result of parse_blocks() for this block.
+ * @param string $block_name Name of the parsed block, e.g. 'core/paragraph'.
+ * @param array $block Result of parse_blocks() for this block.
* Contains 'blockName', 'attrs', 'innerHTML', and 'innerBlocks' keys.
*/
- return apply_filters( 'vip_block_data_api__allow_block', $is_block_included, $block_name, $block );
+ return apply_filters( 'vip_block_data_api__allow_block', $is_block_included, $block_name, $block->parsed_block );
}
/**
@@ -137,16 +146,14 @@ public function parse( $post_content, $post_id = null, $filter_options = [] ) {
$post_content = apply_filters( 'vip_block_data_api__before_parse_post_content', $post_content, $post_id );
$blocks = parse_blocks( $post_content );
- $blocks = array_values( array_filter( $blocks, function ( $block ) {
- $is_whitespace_block = ( null === $block['blockName'] && empty( trim( $block['innerHTML'] ) ) );
- return ! $is_whitespace_block;
- } ) );
- $registered_blocks = $this->block_registry->get_all_registered();
+ $sourced_blocks = array_map( function ( $block ) use ( $filter_options ) {
+ // Render the block, then walk the tree using source_block to apply our
+ // sourced attribute logic.
+ $rendered_block = $this->render_parsed_block( $block );
- $sourced_blocks = array_map(function ( $block ) use ( $registered_blocks, $filter_options ) {
- return $this->source_block( $block, $registered_blocks, $filter_options );
- }, $blocks);
+ return $this->source_block( $rendered_block, $filter_options );
+ }, $blocks );
$sourced_blocks = array_values( array_filter( $sourced_blocks ) );
@@ -189,37 +196,113 @@ public function parse( $post_content, $post_id = null, $filter_options = [] ) {
}
}
+ /**
+ * Helper function to render a parsed block, so that we can benefit from
+ * core-powered functions like block bindings and synced patterns.
+ *
+ * This loosely mirrors the code in the `render_block` function in core, but
+ * allows us to capture the block instance so that we can traverse the tree:
+ * https://github.com/WordPress/WordPress/blob/01d2199622d52b08d1704871770c68e35d2a80dc/wp-includes/blocks.php#L2012
+ *
+ * @param array $parsed_block Parsed block (result of `parse_blocks`).
+ * @return WP_Block
+ */
+ protected function render_parsed_block( array $parsed_block ): WP_Block {
+ $context = [];
+ if ( is_int( $this->post_id ) ) {
+ $context['postId'] = $this->post_id;
+ $context['postType'] = get_post_type( $this->post_id );
+ }
+
+ $context = apply_filters( 'render_block_context', $context, $parsed_block, null );
+
+ $block_instance = new WP_Block( $parsed_block, $context, $this->block_registry );
+ $block_instance->render();
+
+ return $block_instance;
+ }
+
/**
* Processes a single block, and returns the sourced block data.
*
- * @param array $block Block to be processed.
- * @param WP_Block_Type[] $registered_blocks Blocks that have been registered.
- * @param array $filter_options Options to filter using, if any.
+ * @param WP_Block $block Block to be processed.
+ * @param array $filter_options Options to filter using, if any.
*
* @return array|null
*
* @access private
*/
- protected function source_block( $block, $registered_blocks, $filter_options ) {
- $block_name = $block['blockName'];
+ protected function source_block( WP_Block $block, array $filter_options ) {
+ $block_name = $block->name;
- if ( ! $this->should_block_be_included( $block, $block_name, $filter_options ) ) {
+ if ( ! $this->should_block_be_included( $block, $filter_options ) ) {
return null;
}
- if ( ! isset( $registered_blocks[ $block_name ] ) ) {
+ if ( ! $this->block_registry->is_registered( $block_name ) ) {
$this->add_missing_block_warning( $block_name );
}
- $block_definition = $registered_blocks[ $block_name ] ?? null;
- $block_definition_attributes = $block_definition->attributes ?? [];
+ $sourced_block = [
+ 'name' => $block->name,
+ 'attributes' => $this->apply_sourced_attributes( $block ),
+ ];
- $block_attributes = $block['attrs'];
+ // WP_Block#inner_blocks can be an array or WP_Block_List (iterable).
+ $inner_blocks = iterator_to_array( $block->inner_blocks );
+
+ // Recursively iterate over inner blocks.
+ $sourced_inner_blocks = array_values( array_filter( array_map( function ( $inner_block ) use ( $filter_options ) {
+ return $this->source_block( $inner_block, $filter_options );
+ }, $inner_blocks ) ) );
+
+ // Only set innerBlocks if entries are present to match prior version behavior.
+ if ( ! empty( $sourced_inner_blocks ) ) {
+ $sourced_block['innerBlocks'] = $sourced_inner_blocks;
+ }
+
+ /**
+ * Filters a block when parsing is complete.
+ *
+ * @param array $sourced_block An associative array of parsed block data with keys 'name' and 'attribute'.
+ * @param string $block_name Name of the parsed block, e.g. 'core/paragraph'.
+ * @param int $post_id Post ID associated with the parsed block.
+ * @param array $block Result of parse_blocks() for this block. Contains 'blockName', 'attrs', 'innerHTML', and 'innerBlocks' keys.
+ */
+ $sourced_block = apply_filters( 'vip_block_data_api__sourced_block_result', $sourced_block, $block_name, $this->post_id, $block->parsed_block );
+
+ // If attributes are empty, explicitly use an object to avoid encoding an empty array in JSON.
+ if ( empty( $sourced_block['attributes'] ) ) {
+ $sourced_block['attributes'] = (object) [];
+ }
+
+ return $sourced_block;
+ }
+
+ /**
+ * Source the attributes of a block and return a merged attribute array.
+ *
+ * @param WP_Block $block Block to be processed.
+ * @return array Attribute array
+ */
+ protected function apply_sourced_attributes( WP_Block $block ): array {
+ $block_definition = $this->block_registry->get_registered( $block->name ) ?? null;
+ $block_definition_attributes = $block_definition->attributes ?? [];
+ $block_attributes = $block->attributes;
foreach ( $block_definition_attributes as $block_attribute_name => $block_attribute_definition ) {
$attribute_source = $block_attribute_definition['source'] ?? null;
$attribute_default_value = $block_attribute_definition['default'] ?? null;
+ // If the attribute was resolved from a block binding, it has a value, and it's not the default value, skip.
+ if (
+ isset( $block_attributes['metadata']['bindings'][ $block_attribute_name ], $block_attributes[ $block_attribute_name ] ) &&
+ ! empty( $block_attributes[ $block_attribute_name ] ) &&
+ $block_attributes[ $block_attribute_name ] !== $attribute_default_value
+ ) {
+ continue;
+ }
+
if ( null === $attribute_source ) {
// Unsourced attributes are stored in the block's delimiter attributes, skip DOM parser.
@@ -237,7 +320,7 @@ protected function source_block( $block, $registered_blocks, $filter_options ) {
}
// Specify a manual doctype so that the parser will use the HTML5 parser.
- $crawler = new Crawler( sprintf( '%s', $block['innerHTML'] ) );
+ $crawler = new Crawler( sprintf( '%s', $block->inner_html ) );
// Enter the tag for block parsing.
$crawler = $crawler->filter( 'body' )->children();
@@ -249,45 +332,10 @@ protected function source_block( $block, $registered_blocks, $filter_options ) {
}
}
- $sourced_block = [
- 'name' => $block_name,
- 'attributes' => $block_attributes,
- ];
-
- if ( isset( $block['innerBlocks'] ) ) {
- $inner_blocks = array_map( function ( $block ) use ( $registered_blocks, $filter_options ) {
- return $this->source_block( $block, $registered_blocks, $filter_options );
- }, $block['innerBlocks'] );
-
- $inner_blocks = array_values( array_filter( $inner_blocks ) );
-
- if ( ! empty( $inner_blocks ) ) {
- $sourced_block['innerBlocks'] = $inner_blocks;
- }
- }
+ // Sort attributes by key to ensure consistent output.
+ ksort( $block_attributes );
- if ( $this->is_debug_enabled() ) {
- $sourced_block['debug'] = [
- 'block_definition_attributes' => $block_definition->attributes,
- ];
- }
-
- /**
- * Filters a block when parsing is complete.
- *
- * @param array $sourced_block An associative array of parsed block data with keys 'name' and 'attribute'.
- * @param string $block_name Name of the parsed block, e.g. 'core/paragraph'.
- * @param int $post_id Post ID associated with the parsed block.
- * @param array $block Result of parse_blocks() for this block. Contains 'blockName', 'attrs', 'innerHTML', and 'innerBlocks' keys.
- */
- $sourced_block = apply_filters( 'vip_block_data_api__sourced_block_result', $sourced_block, $block_name, $this->post_id, $block );
-
- // If attributes are empty, explicitly use an object to avoid encoding an empty array in JSON.
- if ( empty( $sourced_block['attributes'] ) ) {
- $sourced_block['attributes'] = (object) [];
- }
-
- return $sourced_block;
+ return $block_attributes;
}
/**
diff --git a/tests/graphql/test-graphql-api-v1.php b/tests/graphql/test-graphql-api-v1.php
index 9a5d74f2..5380e96c 100644
--- a/tests/graphql/test-graphql-api-v1.php
+++ b/tests/graphql/test-graphql-api-v1.php
@@ -37,7 +37,7 @@ public function test_is_graphql_enabled_false() {
// get_blocks_data() tests
public function test_get_blocks_data() {
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -53,7 +53,7 @@ public function test_get_blocks_data() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-quote', [
+ $this->register_block_with_attributes( 'test/custom-quote', [
'value' => [
'type' => 'string',
'source' => 'html',
@@ -70,7 +70,7 @@ public function test_get_blocks_data() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-heading', [
+ $this->register_block_with_attributes( 'test/custom-heading', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -192,7 +192,7 @@ public function test_get_blocks_data() {
// get_blocks_data() attribute type tests
public function test_array_data_in_attribute() {
- $this->register_global_block_with_attributes( 'test/custom-table', [
+ $this->register_block_with_attributes( 'test/custom-table', [
'head' => [
'type' => 'array',
'default' => [],
@@ -306,11 +306,6 @@ public function test_array_data_in_attribute() {
[
'name' => 'test/custom-table',
'attributes' => [
- [
- 'name' => 'head',
- 'value' => '[{"cells":[{"content":"Header A","tag":"th"},{"content":"Header B","tag":"th"}]}]',
- 'isValueJsonEncoded' => true,
- ],
[
'name' => 'body',
'value' => '[{"cells":[{"content":"Value A","tag":"td"},{"content":"Value B","tag":"td"}]},{"cells":[{"content":"Value C","tag":"td"},{"content":"Value D","tag":"td"}]}]',
@@ -321,6 +316,11 @@ public function test_array_data_in_attribute() {
'value' => '[{"cells":[{"content":"Footer A","tag":"td"},{"content":"Footer B","tag":"td"}]}]',
'isValueJsonEncoded' => true,
],
+ [
+ 'name' => 'head',
+ 'value' => '[{"cells":[{"content":"Header A","tag":"th"},{"content":"Header B","tag":"th"}]}]',
+ 'isValueJsonEncoded' => true,
+ ],
],
'id' => '1',
],
diff --git a/tests/graphql/test-graphql-api-v2.php b/tests/graphql/test-graphql-api-v2.php
index 326c35eb..53e5e2c1 100644
--- a/tests/graphql/test-graphql-api-v2.php
+++ b/tests/graphql/test-graphql-api-v2.php
@@ -37,7 +37,7 @@ public function test_is_graphql_enabled_false() {
// get_blocks_data() tests
public function test_get_blocks_data() {
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -53,7 +53,7 @@ public function test_get_blocks_data() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-quote', [
+ $this->register_block_with_attributes( 'test/custom-quote', [
'value' => [
'type' => 'string',
'source' => 'html',
@@ -70,7 +70,7 @@ public function test_get_blocks_data() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-heading', [
+ $this->register_block_with_attributes( 'test/custom-heading', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -193,7 +193,7 @@ public function test_get_blocks_data() {
// get_blocks_data() attribute type tests
public function test_array_data_in_attribute() {
- $this->register_global_block_with_attributes( 'test/custom-table', [
+ $this->register_block_with_attributes( 'test/custom-table', [
'head' => [
'type' => 'array',
'default' => [],
@@ -309,11 +309,6 @@ public function test_array_data_in_attribute() {
'id' => '1',
'parentId' => null,
'attributes' => [
- [
- 'name' => 'head',
- 'value' => '[{"cells":[{"content":"Header A","tag":"th"},{"content":"Header B","tag":"th"}]}]',
- 'isValueJsonEncoded' => true,
- ],
[
'name' => 'body',
'value' => '[{"cells":[{"content":"Value A","tag":"td"},{"content":"Value B","tag":"td"}]},{"cells":[{"content":"Value C","tag":"td"},{"content":"Value D","tag":"td"}]}]',
@@ -324,6 +319,11 @@ public function test_array_data_in_attribute() {
'value' => '[{"cells":[{"content":"Footer A","tag":"td"},{"content":"Footer B","tag":"td"}]}]',
'isValueJsonEncoded' => true,
],
+ [
+ 'name' => 'head',
+ 'value' => '[{"cells":[{"content":"Header A","tag":"th"},{"content":"Header B","tag":"th"}]}]',
+ 'isValueJsonEncoded' => true,
+ ],
],
],
],
@@ -339,7 +339,7 @@ public function test_array_data_in_attribute() {
}
public function test_get_block_data_with_boolean_attributes() {
- $this->register_global_block_with_attributes( 'test/toggle-text', [
+ $this->register_block_with_attributes( 'test/toggle-text', [
'isVisible' => [
'type' => 'boolean',
],
@@ -362,13 +362,13 @@ public function test_get_block_data_with_boolean_attributes() {
'name' => 'test/toggle-text',
'attributes' => [
[
- 'name' => 'isVisible',
- 'value' => 'true',
+ 'name' => 'isBordered',
+ 'value' => 'false',
'isValueJsonEncoded' => true,
],
[
- 'name' => 'isBordered',
- 'value' => 'false',
+ 'name' => 'isVisible',
+ 'value' => 'true',
'isValueJsonEncoded' => true,
],
],
@@ -386,7 +386,7 @@ public function test_get_block_data_with_boolean_attributes() {
}
public function test_get_block_data_with_number_attributes() {
- $this->register_global_block_with_attributes( 'test/gallery-block', [
+ $this->register_block_with_attributes( 'test/gallery-block', [
'tileCount' => [
'type' => 'number',
],
@@ -417,13 +417,13 @@ public function test_get_block_data_with_number_attributes() {
'isValueJsonEncoded' => true,
],
[
- 'name' => 'tileWidthPx',
- 'value' => '300',
+ 'name' => 'tileOpacity',
+ 'value' => '0.5',
'isValueJsonEncoded' => true,
],
[
- 'name' => 'tileOpacity',
- 'value' => '0.5',
+ 'name' => 'tileWidthPx',
+ 'value' => '300',
'isValueJsonEncoded' => true,
],
],
@@ -441,7 +441,7 @@ public function test_get_block_data_with_number_attributes() {
}
public function test_get_block_data_with_string_attribute() {
- $this->register_global_block_with_attributes( 'test/custom-block', [
+ $this->register_block_with_attributes( 'test/custom-block', [
'myComment' => [
'type' => 'string',
],
diff --git a/tests/parser/blocks/test-unregistered-block.php b/tests/parser/blocks/test-unregistered-block.php
index e884d37d..2cc5a39a 100644
--- a/tests/parser/blocks/test-unregistered-block.php
+++ b/tests/parser/blocks/test-unregistered-block.php
@@ -31,7 +31,7 @@ public function test_parse_unregistered_block() {
'Block type "test/unknown-block" is not server-side registered. Sourced block attributes will not be available.',
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArrayHasKey( 'warnings', $blocks, sprintf( 'Expected parser to have warnings, none received: %s', wp_json_encode( $blocks ) ) );
diff --git a/tests/parser/sources/test-source-attribute.php b/tests/parser/sources/test-source-attribute.php
index 5214695a..2273127b 100644
--- a/tests/parser/sources/test-source-attribute.php
+++ b/tests/parser/sources/test-source-attribute.php
@@ -37,7 +37,7 @@ public function test_parse_attribute_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -69,7 +69,7 @@ public function test_parse_attribute_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -100,7 +100,7 @@ public function test_parse_attribute_source__with_asterisk_selector() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-children.php b/tests/parser/sources/test-source-children.php
index d5a5506e..198fd61f 100644
--- a/tests/parser/sources/test-source-children.php
+++ b/tests/parser/sources/test-source-children.php
@@ -52,7 +52,7 @@ public function test_parse_children__with_list_elements() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -86,7 +86,7 @@ public function test_parse_children__with_single_child() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -126,7 +126,7 @@ public function test_parse_children__with_mixed_nodes_and_text() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -157,7 +157,7 @@ public function test_parse_children__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-delimiter.php b/tests/parser/sources/test-source-delimiter.php
index 5ee0b5fe..93e08cf2 100644
--- a/tests/parser/sources/test-source-delimiter.php
+++ b/tests/parser/sources/test-source-delimiter.php
@@ -45,7 +45,7 @@ public function test_parse_block_delimiter_attributes() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -75,7 +75,7 @@ public function test_parse_block_delimiter_attributes__are_overridden_by_sourced
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-html.php b/tests/parser/sources/test-source-html.php
index 3b5ef245..61d6d87c 100644
--- a/tests/parser/sources/test-source-html.php
+++ b/tests/parser/sources/test-source-html.php
@@ -36,7 +36,7 @@ public function test_parse_html_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -71,7 +71,7 @@ public function test_parse_html_source__with_multiline_selector() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -102,7 +102,7 @@ public function test_parse_html_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-meta.php b/tests/parser/sources/test-source-meta.php
index 972fd3e1..758d6704 100644
--- a/tests/parser/sources/test-source-meta.php
+++ b/tests/parser/sources/test-source-meta.php
@@ -39,7 +39,7 @@ public function test_parse_meta_source() {
return $post_id;
};
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html, $post_id );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
@@ -69,7 +69,7 @@ public function test_parse_meta_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html, $post_id );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
diff --git a/tests/parser/sources/test-source-node.php b/tests/parser/sources/test-source-node.php
index 602532e7..875277ea 100644
--- a/tests/parser/sources/test-source-node.php
+++ b/tests/parser/sources/test-source-node.php
@@ -43,7 +43,7 @@ public function test_parse_node__with_object_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-query.php b/tests/parser/sources/test-source-query.php
index 42b9263c..58548c1c 100644
--- a/tests/parser/sources/test-source-query.php
+++ b/tests/parser/sources/test-source-query.php
@@ -59,7 +59,7 @@ public function test_parse_query_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
@@ -145,7 +145,7 @@ public function test_parse_query_source__with_nested_query() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
@@ -193,7 +193,7 @@ public function test_parse_query_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
diff --git a/tests/parser/sources/test-source-raw.php b/tests/parser/sources/test-source-raw.php
index 1fd4723b..f6d52b97 100644
--- a/tests/parser/sources/test-source-raw.php
+++ b/tests/parser/sources/test-source-raw.php
@@ -33,7 +33,7 @@ public function test_parse_raw_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -74,7 +74,7 @@ public function test_parse_raw_source__nested() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-rich-text.php b/tests/parser/sources/test-source-rich-text.php
index 286bc691..26421cc3 100644
--- a/tests/parser/sources/test-source-rich-text.php
+++ b/tests/parser/sources/test-source-rich-text.php
@@ -36,7 +36,7 @@ public function test_parse_rich_text_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -69,7 +69,7 @@ public function test_parse_rich_text_source__with_formatting() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -100,7 +100,7 @@ public function test_parse_rich_text_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -131,7 +131,7 @@ public function test_parse_rich_text_source__with_default_value_with_formatting(
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-tag.php b/tests/parser/sources/test-source-tag.php
index 93f4c4a9..51cfb2e1 100644
--- a/tests/parser/sources/test-source-tag.php
+++ b/tests/parser/sources/test-source-tag.php
@@ -35,7 +35,7 @@ public function test_parse_tag_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -79,7 +79,7 @@ public function test_parse_tag_source__in_query() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -106,7 +106,7 @@ public function test_parse_tag_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/sources/test-source-text.php b/tests/parser/sources/test-source-text.php
index 6432d8eb..b63e12ce 100644
--- a/tests/parser/sources/test-source-text.php
+++ b/tests/parser/sources/test-source-text.php
@@ -38,7 +38,7 @@ public function test_parse_text_source() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -72,7 +72,7 @@ public function test_parse_text_source__with_html_tags() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -104,7 +104,7 @@ public function test_parse_text_source__with_default_value() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/test-block-bindings.php b/tests/parser/test-block-bindings.php
new file mode 100644
index 00000000..757add11
--- /dev/null
+++ b/tests/parser/test-block-bindings.php
@@ -0,0 +1,295 @@
+markTestSkipped( 'This test suite requires WP_Block_Bindings_Registry (WordPress 6.5 or higher).' );
+ }
+ }
+
+ /* Single paragraph block binding */
+
+ public function test_single_paragraph_block_binding() {
+
+ $this->register_block_bindings_source(
+ 'test/block-binding',
+ [
+ 'label' => 'Test paragraph block binding',
+ 'get_value_callback' => static function ( array $args, WP_Block $block ) {
+ return sprintf( 'Block binding for %s with arg foo=%s', $block->name, $args['foo'] );
+ },
+ ]
+ );
+
+ $html = '
+
+ Fallback content
+
+ ';
+
+ $expected_blocks = [
+ [
+ 'name' => 'core/paragraph',
+ 'attributes' => [
+ 'content' => 'Block binding for core/paragraph with arg foo=bar',
+ 'metadata' => [
+ 'bindings' => [
+ 'content' => [
+ 'source' => 'test/block-binding',
+ 'args' => [ 'foo' => 'bar' ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+
+ // Block bindings are currently only supported for specific core blocks.
+ // https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/
+ //
+ // Core block attributes can change, so we use assertArraySubset to avoid
+ // brittle assertions.
+ $this->assertArraySubset( $expected_blocks, $blocks['blocks'], false, wp_json_encode( $blocks['blocks'] ) );
+ $this->assertEquals( 1, count( $blocks['blocks'] ), 'Too many blocks in result set' );
+ }
+
+ /* Image block with multiple bindings */
+
+ public function test_image_block_with_multiple_bindings() {
+ $this->register_block_bindings_source(
+ 'test/block-binding-image-url',
+ [
+ 'label' => 'Test image block binding for URL',
+ 'get_value_callback' => static function ( array $args, WP_Block $block ) {
+ return sprintf( 'https://example.com/image.webp?block=%s&foo=%s', $block->name, $args['foo'] );
+ },
+ ]
+ );
+
+ $this->register_block_bindings_source(
+ 'test/block-binding-image-alt',
+ [
+ 'label' => 'Test image block binding for alt text',
+ 'get_value_callback' => static function ( array $args, WP_Block $block ) {
+ return sprintf( 'Block binding for %s with arg foo=%s', $block->name, $args['foo'] );
+ },
+ ]
+ );
+
+ $html = '
+
+
+
+ ';
+
+ $expected_blocks = [
+ [
+ 'name' => 'core/image',
+ 'attributes' => [
+ 'alt' => 'Block binding for core/image with arg foo=bar',
+ 'url' => 'https://example.com/image.webp?block=core/image&foo=bar',
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+
+ // Block bindings are currently only supported for specific core blocks.
+ // https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/
+ //
+ // Core block attributes can change, so we use assertArraySubset to avoid
+ // brittle assertions.
+ $this->assertArraySubset( $expected_blocks, $blocks['blocks'], false, wp_json_encode( $blocks['blocks'] ) );
+ $this->assertEquals( 1, count( $blocks['blocks'] ), 'Too many blocks in result set' );
+ }
+
+ /* Paragraph block binding with default post context */
+
+ public function test_button_block_binding_with_default_context() {
+ $this->register_block_bindings_source(
+ 'test/block-binding-with-default-context', [
+ 'label' => 'Test paragraph block binding with default context',
+ 'get_value_callback' => static function ( array $args, WP_Block $block ) {
+ return sprintf( 'Block binding for %s with arg foo=%s in %s %d', $block->name, $args['foo'], $block->context['postType'], $block->context['postId'] );
+ },
+ 'uses_context' => [ 'postId', 'postType' ],
+ ]
+ );
+
+ $html = '
+
+ Fallback content
+
+ ';
+
+ $post = $this->factory()->post->create_and_get();
+
+ $expected_blocks = [
+ [
+ 'name' => 'core/paragraph',
+ 'attributes' => [
+ 'content' => sprintf( 'Block binding for core/paragraph with arg foo=bar in post %d', $post->ID ),
+ 'metadata' => [
+ 'bindings' => [
+ 'content' => [
+ 'source' => 'test/block-binding-with-default-context',
+ 'args' => [ 'foo' => 'bar' ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html, $post->ID );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+
+ // Block bindings are currently only supported for specific core blocks.
+ // https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/
+ //
+ // Core block attributes can change, so we use assertArraySubset to avoid
+ // brittle assertions.
+ $this->assertArraySubset( $expected_blocks, $blocks['blocks'], false, wp_json_encode( $blocks['blocks'] ) );
+ $this->assertEquals( 1, count( $blocks['blocks'] ), 'Too many blocks in result set' );
+ }
+
+ /* Nested paragraph block binding with context */
+
+ public function test_nested_paragraph_block_binding_with_custom_context() {
+ $this->register_block_bindings_source(
+ 'test/block-binding-with-custom-context', [
+ 'label' => 'Test paragraph block binding with custom context',
+ 'get_value_callback' => static function ( array $args, WP_Block $block ) {
+ return sprintf( 'Block binding for %s with arg foo=%s and context fizz=%s', $block->name, $args['foo'], $block->context['my-context/fizz'] ?? 'missing' );
+ },
+ 'uses_context' => [ 'my-context/fizz' ],
+ ]
+ );
+
+ $this->register_block_with_attributes(
+ 'test/context-provider',
+ [
+ 'fizz' => [
+ 'type' => 'string',
+ ],
+ ],
+ [
+ 'provides_context' => [
+ 'my-context/fizz' => 'fizz',
+ ],
+ ]
+ );
+
+ $html = '
+
+
+ Fallback content
+
+
+ ';
+
+ $expected_blocks = [
+ [
+ 'name' => 'test/context-provider',
+ 'attributes' => [
+ 'fizz' => 'buzz',
+ ],
+ 'innerBlocks' => [
+ [
+ 'name' => 'core/paragraph',
+ 'attributes' => [
+ 'content' => 'Block binding for core/paragraph with arg foo=bar and context fizz=buzz',
+ 'metadata' => [
+ 'bindings' => [
+ 'content' => [
+ 'source' => 'test/block-binding-with-custom-context',
+ 'args' => [ 'foo' => 'bar' ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+
+ // Block bindings are currently only supported for specific core blocks.
+ // https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/
+ //
+ // Core block attributes can change, so we use assertArraySubset to avoid
+ // brittle assertions.
+ $this->assertArraySubset( $expected_blocks, $blocks['blocks'], false, wp_json_encode( $blocks['blocks'] ) );
+ $this->assertEquals( 1, count( $blocks['blocks'] ), 'Too many blocks in result set' );
+ $this->assertEquals( 1, count( $blocks['blocks'][0]['innerBlocks'] ), 'Too many inner blocks in result set' );
+ }
+
+ /* Missing block binding */
+
+ public function test_missing_block_binding() {
+
+ $html = '
+
+ Fallback content
+
+ ';
+
+ $expected_blocks = [
+ [
+ 'name' => 'core/paragraph',
+ 'attributes' => [
+ 'content' => 'Fallback content',
+ 'metadata' => [
+ 'bindings' => [
+ 'content' => [
+ 'source' => 'test/missing-block-binding',
+ 'args' => [ 'foo' => 'bar' ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+
+ // Block bindings are currently only supported for specific core blocks.
+ // https://make.wordpress.org/core/2024/03/06/new-feature-the-block-bindings-api/
+ //
+ // Core block attributes can change, so we use assertArraySubset to avoid
+ // brittle assertions.
+ $this->assertArraySubset( $expected_blocks, $blocks['blocks'], false, wp_json_encode( $blocks['blocks'] ) );
+ $this->assertEquals( 1, count( $blocks['blocks'] ), 'Too many blocks in result set' );
+ }
+}
diff --git a/tests/parser/test-content-parser.php b/tests/parser/test-content-parser.php
index d11b65ec..9852b7c0 100644
--- a/tests/parser/test-content-parser.php
+++ b/tests/parser/test-content-parser.php
@@ -47,7 +47,7 @@ public function test_parse_multiple_attributes_from_block() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -98,7 +98,7 @@ public function test_parse_multiple_blocks() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -157,9 +157,62 @@ public function test_parse_block_missing_attributes_and_defaults() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
}
+
+ /* Whitespace block removal */
+
+ public function test_parse_whitespace_block_removal() {
+ $this->register_block_with_attributes( 'test/block', [
+ 'content' => [
+ 'type' => 'string',
+ 'source' => 'html',
+ 'selector' => 'p',
+ ],
+ ] );
+
+ $html = join( [
+ // Some intentional whitespace
+ '
+ ',
+ '
+ Block 1
+
+ ',
+ // Some intentional whitespace
+ '
+ ',
+ '
+ Block 2
+
+ ',
+ // Some intentional whitespace
+ '
+ ',
+ ] );
+
+ $expected_blocks = [
+ [
+ 'name' => 'test/block',
+ 'attributes' => [
+ 'content' => 'Block 1',
+ ],
+ ],
+ [
+ 'name' => 'test/block',
+ 'attributes' => [
+ 'content' => 'Block 2',
+ ],
+ ],
+ ];
+
+ $content_parser = new ContentParser( $this->get_block_registry() );
+ $blocks = $content_parser->parse( $html );
+
+ $this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
+ $this->assertEquals( $expected_blocks, $blocks['blocks'], sprintf( 'Blocks do not match: %s', wp_json_encode( $blocks ) ) );
+ }
}
diff --git a/tests/parser/test-inner-blocks.php b/tests/parser/test-inner-blocks.php
index 07f5d016..2348761c 100644
--- a/tests/parser/test-inner-blocks.php
+++ b/tests/parser/test-inner-blocks.php
@@ -88,7 +88,7 @@ public function test_parse_inner_blocks__one_layer() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
@@ -181,7 +181,7 @@ public function test_parse_inner_blocks__two_layers() {
],
];
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
$this->assertArrayHasKey( 'blocks', $blocks, sprintf( 'Unexpected parser output: %s', wp_json_encode( $blocks ) ) );
$this->assertArraySubset( $expected_blocks, $blocks['blocks'], true );
diff --git a/tests/parser/test-parser-filters.php b/tests/parser/test-parser-filters.php
index de99543f..8b993e8e 100644
--- a/tests/parser/test-parser-filters.php
+++ b/tests/parser/test-parser-filters.php
@@ -59,7 +59,7 @@ public function test_allow_block_filter_via_code() {
};
add_filter( 'vip_block_data_api__allow_block', $block_filter_function, 10, 2 );
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
remove_filter( 'vip_block_data_api__allow_block', $block_filter_function, 10, 2 );
@@ -100,7 +100,7 @@ public function test_before_parse_post_content_filter() {
};
add_filter( 'vip_block_data_api__before_parse_post_content', $replace_post_content_filter );
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$blocks = $content_parser->parse( $html );
remove_filter( 'vip_block_data_api__before_parse_post_content', $replace_post_content_filter );
@@ -143,7 +143,7 @@ public function test_after_parse_filter() {
};
add_filter( 'vip_block_data_api__after_parse_blocks', $add_extra_data_filter );
- $content_parser = new ContentParser( $this->registry );
+ $content_parser = new ContentParser( $this->get_block_registry() );
$result = $content_parser->parse( $html );
remove_filter( 'vip_block_data_api__after_parse_blocks', $add_extra_data_filter );
diff --git a/tests/registry-test-case.php b/tests/registry-test-case.php
index d2d4004c..7abfafbf 100644
--- a/tests/registry-test-case.php
+++ b/tests/registry-test-case.php
@@ -3,6 +3,7 @@
namespace WPCOMVIP\BlockDataApi;
use WP_Block_Type_Registry;
+use WP_Block_Bindings_Registry;
use WP_UnitTestCase;
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
@@ -12,18 +13,27 @@
class RegistryTestCase extends WP_UnitTestCase {
use ArraySubsetAsserts;
- protected $registry;
- protected $globally_registered_blocks = [];
-
- protected function setUp(): void {
- parent::setUp();
+ protected function tearDown(): void {
+ // Unregister non-core blocks.
+ $block_registry = WP_Block_Type_Registry::get_instance();
+ foreach ( $block_registry->get_all_registered() as $block_type ) {
+ if ( 'core/' === substr( $block_type->name, 0, 5 ) ) {
+ continue;
+ }
+
+ $block_registry->unregister( $block_type->name );
+ }
- $this->registry = new WP_Block_Type_Registry();
- }
+ if ( class_exists( 'WP_Block_Bindings_Registry' ) ) {
+ // Unregister non-core block bindings.
+ $block_bindings_registry = WP_Block_Bindings_Registry::get_instance();
+ foreach ( $block_bindings_registry->get_all_registered() as $source ) {
+ if ( 'core/' === substr( $source->name, 0, 5 ) ) {
+ continue;
+ }
- protected function tearDown(): void {
- foreach ( $this->globally_registered_blocks as $block_name ) {
- $this->unregister_global_block( $block_name );
+ $block_bindings_registry->unregister( $source->name );
+ }
}
parent::tearDown();
@@ -31,31 +41,20 @@ protected function tearDown(): void {
/* Helper methods */
- protected function register_block_with_attributes( $block_name, $attributes ) {
- $this->registry->register( $block_name, [
- 'apiVersion' => 2,
- 'attributes' => $attributes,
- ] );
+ protected function get_block_registry(): WP_Block_Type_Registry {
+ return WP_Block_Type_Registry::get_instance();
}
- /* Global registrations */
-
- protected function register_global_block_with_attributes( $block_name, $attributes ) {
- // Use this function for mocking blocks definitions that need to persist across HTTP requests, like GraphQL tests.
-
- WP_Block_Type_Registry::get_instance()->register( $block_name, [
+ protected function register_block_with_attributes( string $block_name, array $attributes, array $additional_args = [] ): void {
+ $block_type_args = array_merge( [
'apiVersion' => 2,
'attributes' => $attributes,
- ] );
+ ], $additional_args );
- $this->globally_registered_blocks[] = $block_name;
+ $this->get_block_registry()->register( $block_name, $block_type_args );
}
- protected function unregister_global_block( $block_name ) {
- $registry = WP_Block_Type_Registry::get_instance();
-
- if ( $registry->is_registered( $block_name ) ) {
- $registry->unregister( $block_name );
- }
+ protected function register_block_bindings_source( string $source, array $args ): void {
+ WP_Block_Bindings_Registry::get_instance()->register( $source, $args );
}
}
diff --git a/tests/rest/test-rest-api.php b/tests/rest/test-rest-api.php
index 0955bdb4..bc6b5386 100644
--- a/tests/rest/test-rest-api.php
+++ b/tests/rest/test-rest-api.php
@@ -8,17 +8,14 @@
namespace WPCOMVIP\BlockDataApi;
use Exception;
-use WP_Block_Type_Registry;
-use WP_UnitTestCase;
use WP_REST_Server;
use WP_REST_Request;
/**
* e2e tests to ensure that the REST API endpoint is available.
*/
-class RestApiTest extends WP_UnitTestCase {
+class RestApiTest extends RegistryTestCase {
private $server;
- private $globally_registered_blocks = [];
protected function setUp(): void {
parent::setUp();
@@ -34,15 +31,11 @@ protected function tearDown(): void {
global $wp_rest_server;
$wp_rest_server = null;
- foreach ( $this->globally_registered_blocks as $block_name ) {
- $this->unregister_global_block( $block_name );
- }
-
parent::tearDown();
}
public function test_rest_api_returns_blocks_for_post() {
- $this->register_global_block_with_attributes( 'test/custom-heading', [
+ $this->register_block_with_attributes( 'test/custom-heading', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -55,7 +48,7 @@ public function test_rest_api_returns_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-quote', [
+ $this->register_block_with_attributes( 'test/custom-quote', [
'value' => [
'type' => 'string',
'source' => 'html',
@@ -72,7 +65,7 @@ public function test_rest_api_returns_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -88,14 +81,14 @@ public function test_rest_api_returns_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-separator', [
+ $this->register_block_with_attributes( 'test/custom-separator', [
'opacity' => [
'type' => 'string',
'default' => 'alpha-channel',
],
] );
- $this->register_global_block_with_attributes( 'test/custom-media-text', [
+ $this->register_block_with_attributes( 'test/custom-media-text', [
'align' => [
'type' => 'string',
'default' => 'none',
@@ -245,7 +238,7 @@ public function test_rest_api_returns_blocks_for_post() {
}
public function test_rest_api_does_not_return_excluded_blocks_for_post() {
- $this->register_global_block_with_attributes( 'test/custom-heading', [
+ $this->register_block_with_attributes( 'test/custom-heading', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -258,7 +251,7 @@ public function test_rest_api_does_not_return_excluded_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-quote', [
+ $this->register_block_with_attributes( 'test/custom-quote', [
'value' => [
'type' => 'string',
'source' => 'html',
@@ -275,7 +268,7 @@ public function test_rest_api_does_not_return_excluded_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -291,14 +284,14 @@ public function test_rest_api_does_not_return_excluded_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-separator', [
+ $this->register_block_with_attributes( 'test/custom-separator', [
'opacity' => [
'type' => 'string',
'default' => 'alpha-channel',
],
] );
- $this->register_global_block_with_attributes( 'test/custom-media-text', [
+ $this->register_block_with_attributes( 'test/custom-media-text', [
'align' => [
'type' => 'string',
'default' => 'none',
@@ -426,7 +419,7 @@ public function test_rest_api_does_not_return_excluded_blocks_for_post() {
}
public function test_rest_api_only_returns_included_blocks_for_post() {
- $this->register_global_block_with_attributes( 'test/custom-heading', [
+ $this->register_block_with_attributes( 'test/custom-heading', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -439,7 +432,7 @@ public function test_rest_api_only_returns_included_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-quote', [
+ $this->register_block_with_attributes( 'test/custom-quote', [
'value' => [
'type' => 'string',
'source' => 'html',
@@ -456,7 +449,7 @@ public function test_rest_api_only_returns_included_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -472,14 +465,14 @@ public function test_rest_api_only_returns_included_blocks_for_post() {
],
] );
- $this->register_global_block_with_attributes( 'test/custom-separator', [
+ $this->register_block_with_attributes( 'test/custom-separator', [
'opacity' => [
'type' => 'string',
'default' => 'alpha-channel',
],
] );
- $this->register_global_block_with_attributes( 'test/custom-media-text', [
+ $this->register_block_with_attributes( 'test/custom-media-text', [
'align' => [
'type' => 'string',
'default' => 'none',
@@ -590,7 +583,7 @@ public function test_rest_api_returns_blocks_for_custom_post_type() {
'show_in_rest' => true,
]);
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -645,7 +638,7 @@ public function test_rest_api_returns_error_for_non_public_post_type() {
'public' => false,
]);
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -681,7 +674,7 @@ public function test_rest_api_returns_error_for_non_rest_post_type() {
'show_in_rest' => false,
]);
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -712,7 +705,7 @@ public function test_rest_api_returns_error_for_non_rest_post_type() {
}
public function test_rest_api_returns_error_for_unpublished_post() {
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -763,7 +756,7 @@ public function test_rest_api_returns_error_for_classic_content() {
}
public function test_rest_api_returns_error_for_include_and_exclude_filter() {
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -798,7 +791,7 @@ public function test_rest_api_returns_error_for_include_and_exclude_filter() {
}
public function test_rest_api_returns_error_for_unexpected_exception() {
- $this->register_global_block_with_attributes( 'test/custom-paragraph', [
+ $this->register_block_with_attributes( 'test/custom-paragraph', [
'content' => [
'type' => 'rich-text',
'source' => 'rich-text',
@@ -857,21 +850,4 @@ static function ( int $errno, string $errstr ): never {
E_USER_WARNING
);
}
-
- private function register_global_block_with_attributes( $block_name, $attributes ) {
- WP_Block_Type_Registry::get_instance()->register( $block_name, [
- 'apiVersion' => 2,
- 'attributes' => $attributes,
- ] );
-
- $this->globally_registered_blocks[] = $block_name;
- }
-
- private function unregister_global_block( $block_name ) {
- $registry = WP_Block_Type_Registry::get_instance();
-
- if ( $registry->is_registered( $block_name ) ) {
- $registry->unregister( $block_name );
- }
- }
}