Plugin Updates
This commit is contained in:
@@ -191,10 +191,202 @@ class WP_Block {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the block bindings and updates the block attributes with the values from the sources.
|
||||
*
|
||||
* A block might contain bindings in its attributes. Bindings are mappings
|
||||
* between an attribute of the block and a source. A "source" is a function
|
||||
* registered with `register_block_bindings_source()` that defines how to
|
||||
* retrieve a value from outside the block, e.g. from post meta.
|
||||
*
|
||||
* This function will process those bindings and update the block's attributes
|
||||
* with the values coming from the bindings.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* The "bindings" property for an Image block might look like this:
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "metadata": {
|
||||
* "bindings": {
|
||||
* "title": {
|
||||
* "source": "core/post-meta",
|
||||
* "args": { "key": "text_custom_field" }
|
||||
* },
|
||||
* "url": {
|
||||
* "source": "core/post-meta",
|
||||
* "args": { "key": "url_custom_field" }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The above example will replace the `title` and `url` attributes of the Image
|
||||
* block with the values of the `text_custom_field` and `url_custom_field` post meta.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array The computed block attributes for the provided block bindings.
|
||||
*/
|
||||
private function process_block_bindings() {
|
||||
$parsed_block = $this->parsed_block;
|
||||
$computed_attributes = array();
|
||||
$supported_block_attributes = array(
|
||||
'core/paragraph' => array( 'content' ),
|
||||
'core/heading' => array( 'content' ),
|
||||
'core/image' => array( 'id', 'url', 'title', 'alt' ),
|
||||
'core/button' => array( 'url', 'text', 'linkTarget', 'rel' ),
|
||||
);
|
||||
|
||||
// If the block doesn't have the bindings property, isn't one of the supported
|
||||
// block types, or the bindings property is not an array, return the block content.
|
||||
if (
|
||||
! isset( $supported_block_attributes[ $this->name ] ) ||
|
||||
empty( $parsed_block['attrs']['metadata']['bindings'] ) ||
|
||||
! is_array( $parsed_block['attrs']['metadata']['bindings'] )
|
||||
) {
|
||||
return $computed_attributes;
|
||||
}
|
||||
|
||||
foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) {
|
||||
// If the attribute is not in the supported list, process next attribute.
|
||||
if ( ! in_array( $attribute_name, $supported_block_attributes[ $this->name ], true ) ) {
|
||||
continue;
|
||||
}
|
||||
// If no source is provided, or that source is not registered, process next attribute.
|
||||
if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$block_binding_source = get_block_bindings_source( $block_binding['source'] );
|
||||
if ( null === $block_binding_source ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
|
||||
$source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
|
||||
|
||||
// If the value is not null, process the HTML based on the block and the attribute.
|
||||
if ( ! is_null( $source_value ) ) {
|
||||
$computed_attributes[ $attribute_name ] = $source_value;
|
||||
}
|
||||
}
|
||||
|
||||
return $computed_attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on the block attribute name, replace its value in the HTML based on the value provided.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $block_content Block content.
|
||||
* @param string $attribute_name The attribute name to replace.
|
||||
* @param mixed $source_value The value used to replace in the HTML.
|
||||
* @return string The modified block content.
|
||||
*/
|
||||
private function replace_html( string $block_content, string $attribute_name, $source_value ) {
|
||||
$block_type = $this->block_type;
|
||||
if ( ! isset( $block_type->attributes[ $attribute_name ]['source'] ) ) {
|
||||
return $block_content;
|
||||
}
|
||||
|
||||
// Depending on the attribute source, the processing will be different.
|
||||
switch ( $block_type->attributes[ $attribute_name ]['source'] ) {
|
||||
case 'html':
|
||||
case 'rich-text':
|
||||
$block_reader = new WP_HTML_Tag_Processor( $block_content );
|
||||
|
||||
// TODO: Support for CSS selectors whenever they are ready in the HTML API.
|
||||
// In the meantime, support comma-separated selectors by exploding them into an array.
|
||||
$selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
|
||||
// Add a bookmark to the first tag to be able to iterate over the selectors.
|
||||
$block_reader->next_tag();
|
||||
$block_reader->set_bookmark( 'iterate-selectors' );
|
||||
|
||||
// TODO: This shouldn't be needed when the `set_inner_html` function is ready.
|
||||
// Store the parent tag and its attributes to be able to restore them later in the button.
|
||||
// The button block has a wrapper while the paragraph and heading blocks don't.
|
||||
if ( 'core/button' === $this->name ) {
|
||||
$button_wrapper = $block_reader->get_tag();
|
||||
$button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
|
||||
$button_wrapper_attrs = array();
|
||||
foreach ( $button_wrapper_attribute_names as $name ) {
|
||||
$button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $selectors as $selector ) {
|
||||
// If the parent tag, or any of its children, matches the selector, replace the HTML.
|
||||
if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag(
|
||||
array(
|
||||
'tag_name' => $selector,
|
||||
)
|
||||
) ) {
|
||||
$block_reader->release_bookmark( 'iterate-selectors' );
|
||||
|
||||
// TODO: Use `set_inner_html` method whenever it's ready in the HTML API.
|
||||
// Until then, it is hardcoded for the paragraph, heading, and button blocks.
|
||||
// Store the tag and its attributes to be able to restore them later.
|
||||
$selector_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
|
||||
$selector_attrs = array();
|
||||
foreach ( $selector_attribute_names as $name ) {
|
||||
$selector_attrs[ $name ] = $block_reader->get_attribute( $name );
|
||||
}
|
||||
$selector_markup = "<$selector>" . wp_kses_post( $source_value ) . "</$selector>";
|
||||
$amended_content = new WP_HTML_Tag_Processor( $selector_markup );
|
||||
$amended_content->next_tag();
|
||||
foreach ( $selector_attrs as $attribute_key => $attribute_value ) {
|
||||
$amended_content->set_attribute( $attribute_key, $attribute_value );
|
||||
}
|
||||
if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) {
|
||||
return $amended_content->get_updated_html();
|
||||
}
|
||||
if ( 'core/button' === $this->name ) {
|
||||
$button_markup = "<$button_wrapper>{$amended_content->get_updated_html()}</$button_wrapper>";
|
||||
$amended_button = new WP_HTML_Tag_Processor( $button_markup );
|
||||
$amended_button->next_tag();
|
||||
foreach ( $button_wrapper_attrs as $attribute_key => $attribute_value ) {
|
||||
$amended_button->set_attribute( $attribute_key, $attribute_value );
|
||||
}
|
||||
return $amended_button->get_updated_html();
|
||||
}
|
||||
} else {
|
||||
$block_reader->seek( 'iterate-selectors' );
|
||||
}
|
||||
}
|
||||
$block_reader->release_bookmark( 'iterate-selectors' );
|
||||
return $block_content;
|
||||
|
||||
case 'attribute':
|
||||
$amended_content = new WP_HTML_Tag_Processor( $block_content );
|
||||
if ( ! $amended_content->next_tag(
|
||||
array(
|
||||
// TODO: build the query from CSS selector.
|
||||
'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
|
||||
)
|
||||
) ) {
|
||||
return $block_content;
|
||||
}
|
||||
$amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], $source_value );
|
||||
return $amended_content->get_updated_html();
|
||||
break;
|
||||
|
||||
default:
|
||||
return $block_content;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the render output for the block.
|
||||
*
|
||||
* @since 5.5.0
|
||||
* @since 6.5.0 Added block bindings processing.
|
||||
*
|
||||
* @global WP_Post $post Global post object.
|
||||
*
|
||||
@@ -214,6 +406,13 @@ class WP_Block {
|
||||
)
|
||||
);
|
||||
|
||||
// Process the block bindings and get attributes updated with the values from the sources.
|
||||
$computed_attributes = $this->process_block_bindings();
|
||||
if ( ! empty( $computed_attributes ) ) {
|
||||
// Merge the computed attributes with the original attributes.
|
||||
$this->attributes = array_merge( $this->attributes, $computed_attributes );
|
||||
}
|
||||
|
||||
$is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
|
||||
$block_content = '';
|
||||
|
||||
@@ -249,6 +448,12 @@ class WP_Block {
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $computed_attributes ) && ! empty( $block_content ) ) {
|
||||
foreach ( $computed_attributes as $attribute_name => $source_value ) {
|
||||
$block_content = $this->replace_html( $block_content, $attribute_name, $source_value );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_dynamic ) {
|
||||
$global_post = $post;
|
||||
$parent = WP_Block_Supports::$block_to_render;
|
||||
@@ -274,12 +479,24 @@ class WP_Block {
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $this->block_type->view_script_module_ids ) ) {
|
||||
foreach ( $this->block_type->view_script_module_ids as $view_script_module_id ) {
|
||||
wp_enqueue_script_module( $view_script_module_id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( ! empty( $this->block_type->style_handles ) ) ) {
|
||||
foreach ( $this->block_type->style_handles as $style_handle ) {
|
||||
wp_enqueue_style( $style_handle );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( ! empty( $this->block_type->view_style_handles ) ) ) {
|
||||
foreach ( $this->block_type->view_style_handles as $view_style_handle ) {
|
||||
wp_enqueue_style( $view_style_handle );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the content of a single block.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user