Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: Move Interactivity directives processing to WP_Block class #6331

Closed
22 changes: 22 additions & 0 deletions src/wp-includes/class-wp-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,22 @@ private function replace_html( string $block_content, string $attribute_name, $s
*/
public function render( $options = array() ) {
global $post;

/*
* There can be only one root interactive block at a time because the rendered HTML of that block contains
* the rendered HTML of all its inner blocks, including any interactive block.
*/
static $root_interactive_block = null;
$wp_interactivity_process_directives_enabled = apply_filters( 'wp_interactivity_process_directives', true );
if (
null === $root_interactive_block && $wp_interactivity_process_directives_enabled && (
gziolo marked this conversation as resolved.
Show resolved Hide resolved
( isset( $this->block_type->supports['interactivity'] ) && true === $this->block_type->supports['interactivity'] ) ||
! empty( $this->block_type->supports['interactivity']['interactive'] )
)
) {
$root_interactive_block = $this;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be more efficient to add an extra attribute to parsed_block than to compare the entire block?

I remember that the problem comparing $parsed_block attribute in layout has been fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this change would require some testing, so better leave for a follow-up PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Objects are stored and compared by reference, right? How would be any alternative more efficient in that case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking a object property is more performant than checking the entire object, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you share a code example to illustrate the idea?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbravobernal, I think you're confusing arrays with objects here in PHP.

The problem lies in arrays, as PHP doesn't compare them by reference, and instead compares the entire array. In this case, checking a property of the array is more performant than checking the entire array.

However, in the case of objects, they are instances of a class and are compared by reference. So there's no performance problem.

Is that correct, @gziolo?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cbravobernal, I think you're confusing arrays with objects here in PHP.

Yep, as we were comparing arrays back then in $parsed_block if I remember correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but that's no longer the case, right? So we no longer have that problem.

}

$options = wp_parse_args(
$options,
array(
Expand Down Expand Up @@ -533,6 +549,12 @@ public function render( $options = array() ) {
*/
$block_content = apply_filters( "render_block_{$this->name}", $block_content, $this->parsed_block, $this );

if ( $root_interactive_block === $this ) {
// The root interactive block has finished rendering. Time to process directives.
$block_content = wp_interactivity_process_directives( $block_content );
$root_interactive_block = null;
}

return $block_content;
}
}
19 changes: 19 additions & 0 deletions src/wp-includes/deprecated.php
Original file line number Diff line number Diff line change
Expand Up @@ -6318,3 +6318,22 @@ function wp_render_elements_support( $block_content, $block ) {
_deprecated_function( __FUNCTION__, '6.6.0', 'wp_render_elements_class_name' );
return $block_content;
}

/**
* Processes the directives on the rendered HTML of the interactive blocks.
*
* This processes only one root interactive block at a time because the
* rendered HTML of that block contains the rendered HTML of all its inner
* blocks, including any interactive block. It does so by ignoring all the
* interactive inner blocks until the root interactive block is processed.
*
* @since 6.5.0
* @deprecated 6.6.0
*
* @param array $parsed_block The parsed block.
* @return array The same parsed block.
*/
function wp_interactivity_process_directives_of_interactive_blocks( array $parsed_block ): array {
_deprecated_function( __FUNCTION__, '6.6.0' );
return $parsed_block;
}
65 changes: 0 additions & 65 deletions src/wp-includes/interactivity-api/interactivity-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,71 +7,6 @@
* @since 6.5.0
*/

/**
* Processes the directives on the rendered HTML of the interactive blocks.
*
* This processes only one root interactive block at a time because the
* rendered HTML of that block contains the rendered HTML of all its inner
* blocks, including any interactive block. It does so by ignoring all the
* interactive inner blocks until the root interactive block is processed.
*
* @since 6.5.0
*
* @param array $parsed_block The parsed block.
* @return array The same parsed block.
*/
function wp_interactivity_process_directives_of_interactive_blocks( array $parsed_block ): array {
static $root_interactive_block = null;

/*
* Checks whether a root interactive block is already annotated for
* processing, and if it is, it ignores the subsequent ones.
*/
if ( null === $root_interactive_block ) {
$block_name = $parsed_block['blockName'];
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name );

if (
isset( $block_name ) &&
( ( isset( $block_type->supports['interactivity'] ) && true === $block_type->supports['interactivity'] ) ||
( isset( $block_type->supports['interactivity']['interactive'] ) && true === $block_type->supports['interactivity']['interactive'] ) )
) {
// Annotates the root interactive block for processing.
$root_interactive_block = array( $block_name, $parsed_block );

/*
* Adds a filter to process the root interactive block once it has
* finished rendering.
*/
$process_interactive_blocks = static function ( string $content, array $parsed_block ) use ( &$root_interactive_block, &$process_interactive_blocks ): string {
// Checks whether the current block is the root interactive block.
list($root_block_name, $root_parsed_block) = $root_interactive_block;
if ( $root_block_name === $parsed_block['blockName'] && $parsed_block === $root_parsed_block ) {
// The root interactive blocks has finished rendering, process it.
$content = wp_interactivity_process_directives( $content );
// Removes the filter and reset the root interactive block.
remove_filter( 'render_block_' . $parsed_block['blockName'], $process_interactive_blocks );
$root_interactive_block = null;
}
return $content;
};

/*
* Uses a priority of 100 to ensure that other filters can add additional
* directives before the processing starts.
*/
add_filter( 'render_block_' . $block_name, $process_interactive_blocks, 100, 2 );
}
}

return $parsed_block;
}
/*
* Uses a priority of 100 to ensure that other filters can add additional attributes to
* $parsed_block before the processing starts.
*/
add_filter( 'render_block_data', 'wp_interactivity_process_directives_of_interactive_blocks', 100, 1 );

/**
* Retrieves the main WP_Interactivity_API instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,4 +525,40 @@ public function test_process_interactive_directive_in_void_tags() {
unregister_block_type( 'test/custom-directive-block' );
$this->assertNull( $input_value );
}

/**
* Tests wp_interactivity_process_directives_enabled filter.
gziolo marked this conversation as resolved.
Show resolved Hide resolved
*
* @ticket 61185
*
* @covers wp_interactivity_process_directives_of_interactive_blocks
gziolo marked this conversation as resolved.
Show resolved Hide resolved
*/
public function test_not_processing_directives_filter() {
wp_interactivity_state(
'dont-process',
array(
'text' => 'text',
)
);
register_block_type(
'test/custom-directive-block',
array(
'render_callback' => function () {
return '<div data-wp-interactive="dont-process"><input data-wp-bind--value="state.text" /></div>';
},
'supports' => array(
'interactivity' => true,
),
)
);
$post_content = '<!-- wp:test/custom-directive-block /-->';
add_filter( 'wp_interactivity_process_directives', '__return_false' );
gziolo marked this conversation as resolved.
Show resolved Hide resolved
$processed_content = do_blocks( $post_content );
$processor = new WP_HTML_Tag_Processor( $processed_content );
$processor->next_tag( array( 'tag_name' => 'input' ) );
$input_value = $processor->get_attribute( 'value' );
remove_filter( 'wp_interactivity_process_directives', '__return_false' );
gziolo marked this conversation as resolved.
Show resolved Hide resolved
unregister_block_type( 'test/custom-directive-block' );
$this->assertNull( $input_value );
}
}
Loading