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

Add block bindings API basis and metadata source #56867

Closed
Closed
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4100933
Add the basis of the Block Bindings API
SantosGuillamot Nov 29, 2023
edee28a
Add the first PHP logic of the `metadata` source
SantosGuillamot Nov 29, 2023
01189c7
Update metadata folder structure
SantosGuillamot Nov 30, 2023
5e38246
Add initial version of the block bindings editor UI
SantosGuillamot Nov 30, 2023
35d03dd
Filter to add the bindings attribute automatically
SantosGuillamot Nov 30, 2023
a19009c
Logic to handle different attributes in the editor
SantosGuillamot Nov 30, 2023
87e333d
Fetch metadata from REST API correctly
SantosGuillamot Nov 30, 2023
081ed5c
Use const instead of let
SantosGuillamot Nov 30, 2023
ecd1377
Move bindings inside metadata attribute
SantosGuillamot Dec 1, 2023
7543606
Use getEntityRecord to fetch the REST API
SantosGuillamot Dec 1, 2023
1017d4d
Merge branch `trunk` into `add/block-bindings-api-basis-and-metadata-…
SantosGuillamot Dec 1, 2023
8096402
Add helper to update bindings in the editor
SantosGuillamot Dec 1, 2023
5d5c68c
Use editor helper in metadata source
SantosGuillamot Dec 1, 2023
24ff0d2
Adapt pattern source PHP side
SantosGuillamot Dec 1, 2023
6c7fe63
Adapt pattern source editor side
SantosGuillamot Dec 1, 2023
6176f15
Change bindings format to be an object
SantosGuillamot Dec 3, 2023
feaf22d
Fix selected metadata attribute
SantosGuillamot Dec 3, 2023
4689e76
Slightly modify the bindings property syntax
SantosGuillamot Dec 3, 2023
f6bc2c0
Add support for heading and button blocks
SantosGuillamot Dec 4, 2023
3590330
Add post and site data
SantosGuillamot Dec 4, 2023
5b5546f
Support for button and heading selectors
SantosGuillamot Dec 18, 2023
01d834b
Change bindings syntax to use name and attributes
SantosGuillamot Dec 18, 2023
d215035
Add extensibility to the Block Bindings UI in the editor
SantosGuillamot Dec 18, 2023
159cb0a
Add post-data and site-data sources in the editor
SantosGuillamot Dec 18, 2023
1178ba8
Add core sources in PHP
SantosGuillamot Dec 18, 2023
006872f
Abstract block bindings UI
SantosGuillamot Dec 19, 2023
cc59e1b
Remove extra dependency
SantosGuillamot Dec 19, 2023
4f651c2
Modify `register_block_bindings_source` syntax
SantosGuillamot Dec 20, 2023
7dd4368
Change block bindings experiment name
SantosGuillamot Dec 20, 2023
62a8bc1
Remove old UI
SantosGuillamot Dec 20, 2023
b95ac5e
Change variables names
SantosGuillamot Dec 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/block-supports/pattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @param WP_Block_Type $block_type Block Type.
*/
function gutenberg_register_pattern_support( $block_type ) {
$pattern_support = property_exists( $block_type, 'supports' ) ? _wp_array_get( $block_type->supports, array( '__experimentalConnections' ), false ) : false;
$pattern_support = property_exists( $block_type, 'supports' ) ? _wp_array_get( $block_type->supports, array( '__experimentalBlockBindings' ), false ) : false;

if ( $pattern_support ) {
if ( ! $block_type->uses_context ) {
Expand Down
112 changes: 112 additions & 0 deletions lib/experimental/block-bindings-api/html-processing.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php
/**
* Define the mechanism to replpace the HTML depending on the block attributes.
*
* @package gutenberg
*/

if ( ! function_exists( 'block_bindings_replace_html' ) ) {
/**
* Depending on the block attributes, replace the proper HTML based on the value returned by the source.
*
* @param string $block_content Block Content.
* @param string $block_name The name of the block to process.
* @param string $block_attr The attribute of the block we want to process.
* @param string $source_value The value used to replace the HTML.
*/
function block_bindings_replace_html( $block_content, $block_name, $block_attr, $source_value ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name );
if ( null === $block_type ) {
return;
}

// Depending on the attribute source, the processing will be different.
// TODO: Get the type from the block attribute definition and modify/validate the value returned by the source if needed.
switch ( $block_type->attributes[ $block_attr ]['source'] ) {
case 'html':
case 'rich-text':
$p = 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[ $block_attr ]['selector'] );
// Add a bookmark to the first tag to be able to iterate over the selectors.
$p->next_tag();
$p->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' === $block_name ) {
$parent_tag = $p->get_tag();
$parent_tag_names = $p->get_attribute_names_with_prefix( '' );
$parent_tag_attrs = array();
foreach ( $parent_tag_names as $name ) {
$parent_tag_attrs[ $name ] = $p->get_attribute( $name );
}
}

foreach ( $selectors as $selector ) {
// If the parent tag, or any of its children, matches the selector, replace the HTML.
if ( strcasecmp( $p->get_tag( $selector ), $selector ) === 0 || $p->next_tag(
array(
'tag_name' => $selector,
)
) ) {
$p->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_tag_names = $p->get_attribute_names_with_prefix( '' );
$selector_tag_attrs = array();
foreach ( $selector_tag_names as $name ) {
$selector_tag_attrs[ $name ] = $p->get_attribute( $name );
}
$selector_markup = "<$selector>" . esc_html( $source_value ) . "</$selector>";
$p2 = new WP_HTML_Tag_Processor( $selector_markup );
$p2->next_tag();
foreach ( $selector_tag_attrs as $attribute_key => $attribute_value ) {
$p2->set_attribute( $attribute_key, $attribute_value );
}
$selector_updated_html = $p2->get_updated_html();
if ( 'core/paragraph' === $block_name || 'core/heading' === $block_name ) {
return $selector_updated_html;
}
if ( 'core/button' === $block_name ) {
$markup = "<$parent_tag>$selector_updated_html</$parent_tag>";
$p3 = new WP_HTML_Tag_Processor( $markup );
$p3->next_tag();
foreach ( $parent_tag_attrs as $attribute_key => $attribute_value ) {
$p3->set_attribute( $attribute_key, $attribute_value );
}
return $p3->get_updated_html();
}
} else {
$p->seek( 'iterate-selectors' );
}
}
$p->release_bookmark( 'iterate-selectors' );
return $block_content;

case 'attribute':
$p = new WP_HTML_Tag_Processor( $block_content );
if ( ! $p->next_tag(
array(
// TODO: build the query from CSS selector.
'tag_name' => $block_type->attributes[ $block_attr ]['selector'],
)
) ) {
return $block_content;
}
$p->set_attribute( $block_type->attributes[ $block_attr ]['attribute'], esc_attr( $source_value ) );
return $p->get_updated_html();
break;

default:
return $block_content;
break;
}
return;
}
}
22 changes: 22 additions & 0 deletions lib/experimental/block-bindings-api/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* Require the necessary files.
*
* @package gutenberg
*/

require_once __DIR__ . '/sources/index.php';
require_once __DIR__ . '/html-processing.php';

// Register the sources.
$gutenberg_experiments = get_option( 'gutenberg-experiments' );
if ( $gutenberg_experiments ) {
if ( array_key_exists( 'gutenberg-pattern-partial-syncing', $gutenberg_experiments ) ) {
require_once __DIR__ . '/sources/pattern.php';
}
if ( array_key_exists( 'gutenberg-block-bindings', $gutenberg_experiments ) ) {
require_once __DIR__ . '/sources/post-meta.php';
require_once __DIR__ . '/sources/post-data.php';
require_once __DIR__ . '/sources/site-data.php';
}
}
24 changes: 24 additions & 0 deletions lib/experimental/block-bindings-api/sources/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/**
* Define the mechanism to add new sources available in the block bindings API.
*
* @package gutenberg
*/

global $block_bindings_sources;
$block_bindings_sources = array();
if ( ! function_exists( 'register_block_bindings_source' ) ) {
/**
* Function to register a new source.
*
* @param string $source_name The name of the source.
* @param function $source_args List of arguments for the block bindings source:
* - label: The label of the source.
* - apply: The callback executed when the source is processed in the server.
* @return void
*/
function register_block_bindings_source( $source_name, $source_args ) {
global $block_bindings_sources;
$block_bindings_sources[ $source_name ] = $source_args;
}
}
23 changes: 23 additions & 0 deletions lib/experimental/block-bindings-api/sources/pattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
/**
* Add the metadata source to the block bindings API.
*
* @package gutenberg
*/

if ( function_exists( 'register_block_bindings_source' ) ) {
$pattern_source_callback = function ( $source_attrs, $block_content, $block, $block_instance ) {
if ( ! _wp_array_get( $block_instance->attributes, array( 'metadata', 'id' ), false ) ) {
return;
}
$block_id = $block_instance->attributes['metadata']['id'];
return _wp_array_get( $block_instance->context, array( 'pattern/overrides', $block_id ), false );
};
register_block_bindings_source(
'pattern_attributes',
array(
'label' => __( 'Pattern Attributes' ),
'apply' => $pattern_source_callback,
)
);
}
26 changes: 26 additions & 0 deletions lib/experimental/block-bindings-api/sources/post-data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
/**
* Add the site_data source to the block bindings API.
*
* @package gutenberg
*/

if ( function_exists( 'register_block_bindings_source' ) ) {
$post_data_source_callback = function ( $source_attrs, $block_content, $block, $block_instance ) {
// Use the postId attribute if available, otherwise use the context.
if ( isset( $source_attrs['postId'] ) ) {
$post_id = $source_attrs['postId'];
} else {
// I tried using $block_instance->context['postId'] but it wasn't available in the image block.
$post_id = get_the_ID();
}
return get_post( $post_id )->{$source_attrs['value']};
};
register_block_bindings_source(
'post_data',
array(
'label' => __( 'Post Data' ),
'apply' => $post_data_source_callback,
)
);
}
27 changes: 27 additions & 0 deletions lib/experimental/block-bindings-api/sources/post-meta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* Add the post_meta source to the block bindings API.
*
* @package gutenberg
*/

if ( function_exists( 'register_block_bindings_source' ) ) {
$post_meta_source_callback = function ( $source_attrs, $block_content, $block, $block_instance ) {
// Use the postId attribute if available, otherwise use the context.
if ( isset( $source_attrs['postId'] ) ) {
$post_id = $source_attrs['postId'];
} else {
// I tried using $block_instance->context['postId'] but it wasn't available in the image block.
$post_id = get_the_ID();
}

return get_post_meta( $post_id, $source_attrs['value'], true );
};
register_block_bindings_source(
'post_meta',
array(
'label' => __( 'Post Meta' ),
'apply' => $post_meta_source_callback,
)
);
}
19 changes: 19 additions & 0 deletions lib/experimental/block-bindings-api/sources/site-data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
/**
* Add the site_data source to the block bindings API.
*
* @package gutenberg
*/

if ( function_exists( 'register_block_bindings_source' ) ) {
$site_data_source_callback = function ( $source_attrs, $block_content, $block, $block_instance ) {
return get_option( $source_attrs['value'] );
};
register_block_bindings_source(
'site_data',
array(
'label' => __( 'Site Data' ),
'apply' => $site_data_source_callback,
)
);
}
Loading
Loading