<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[57526] trunk: Editor: Refactor the way block bindings sources are handled</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/57526">57526</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/57526","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>gziolo</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-02-02 20:22:11 +0000 (Fri, 02 Feb 2024)</dd>
</dl>
<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Editor: Refactor the way block bindings sources are handled
It fixes the coding style issues reported. It goes further and improves the code quality it other places where the logic for block bindings was added.
Follow-up for <a href="https://core.trac.wordpress.org/changeset/57514">[57514]</a>.
Props: gziolo, mukesh27, youknowriad, santosguillamot.
See <a href="https://core.trac.wordpress.org/ticket/60282">#60282</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesblockbindingsphp">trunk/src/wp-includes/block-bindings.php</a></li>
<li><a href="#trunksrcwpincludesclasswpblockbindingsregistryphp">trunk/src/wp-includes/class-wp-block-bindings-registry.php</a></li>
<li><a href="#trunksrcwpincludesclasswpblockphp">trunk/src/wp-includes/class-wp-block.php</a></li>
<li><a href="#trunksrcwpsettingsphp">trunk/src/wp-settings.php</a></li>
<li><a href="#trunktestsphpunittestsblockbindingsregisterphp">trunk/tests/phpunit/tests/block-bindings/register.php</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesblockbindingspatternoverridesphp">trunk/src/wp-includes/block-bindings/pattern-overrides.php</a></li>
<li><a href="#trunksrcwpincludesblockbindingspostmetaphp">trunk/src/wp-includes/block-bindings/post-meta.php</a></li>
<li><a href="#trunktestsphpunittestsblockbindingsrenderphp">trunk/tests/phpunit/tests/block-bindings/render.php</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li>trunk/src/wp-includes/block-bindings/sources/</li>
<li><a href="#trunktestsphpunittestsblockbindingsblockbindingsphp">trunk/tests/phpunit/tests/block-bindings/block-bindings.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludesblockbindingspatternoverridesphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/block-bindings/pattern-overrides.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/block-bindings/pattern-overrides.php (rev 0)
+++ trunk/src/wp-includes/block-bindings/pattern-overrides.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,46 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Pattern Overrides source for the Block Bindings.
+ *
+ * @since 6.5.0
+ * @package WordPress
+ * @subpackage Block Bindings
+ */
+
+/**
+ * Gets value for the Pattern Overrides source.
+ *
+ * @since 6.5.0
+ * @access private
+ *
+ * @param array $source_args Array containing source arguments used to look up the override value.
+ * Example: array( "key" => "foo" ).
+ * @param WP_Block $block_instance The block instance.
+ * @param string $attribute_name The name of the target attribute.
+ * @return mixed The value computed for the source.
+ */
+function _block_bindings_pattern_overrides_get_value( array $source_args, $block_instance, string $attribute_name ) {
+ if ( empty( $block_instance->attributes['metadata']['id'] ) ) {
+ return null;
+ }
+ $block_id = $block_instance->attributes['metadata']['id'];
+ return _wp_array_get( $block_instance->context, array( 'pattern/overrides', $block_id, $attribute_name ), null );
+}
+
+/**
+ * Registers Pattern Overrides source in the Block Bindings registry.
+ *
+ * @since 6.5.0
+ * @access private
+ */
+function _register_block_bindings_pattern_overrides_source() {
+ register_block_bindings_source(
+ 'core/pattern-overrides',
+ array(
+ 'label' => _x( 'Pattern Overrides', 'block bindings source' ),
+ 'get_value_callback' => '_block_bindings_pattern_overrides_get_value',
+ )
+ );
+}
+
+add_action( 'init', '_register_block_bindings_pattern_overrides_source' );
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/src/wp-includes/block-bindings/pattern-overrides.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunksrcwpincludesblockbindingspostmetaphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/block-bindings/post-meta.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/block-bindings/post-meta.php (rev 0)
+++ trunk/src/wp-includes/block-bindings/post-meta.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,58 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Post Meta source for the block bindings.
+ *
+ * @since 6.5.0
+ * @package WordPress
+ * @subpackage Block Bindings
+ */
+
+/**
+ * Gets value for Post Meta source.
+ *
+ * @since 6.5.0
+ * @access private
+ *
+ * @param array $source_args Array containing source arguments used to look up the override value.
+ * Example: array( "key" => "foo" ).
+ * @return mixed The value computed for the source.
+ */
+function _block_bindings_post_meta_get_value( array $source_args ) {
+ if ( ! isset( $source_args['key'] ) ) {
+ return null;
+ }
+
+ // Use the postId attribute if available.
+ if ( isset( $source_args['postId'] ) ) {
+ $post_id = $source_args['postId'];
+ } else {
+ // $block_instance->context['postId'] is not available in the Image block.
+ $post_id = get_the_ID();
+ }
+
+ // If a post isn't public, we need to prevent unauthorized users from accessing the post meta.
+ $post = get_post( $post_id );
+ if ( ( ! is_post_publicly_viewable( $post ) && ! current_user_can( 'read_post', $post_id ) ) || post_password_required( $post ) ) {
+ return null;
+ }
+
+ return get_post_meta( $post_id, $source_args['key'], true );
+}
+
+/**
+ * Registers Post Meta source in the block bindings registry.
+ *
+ * @since 6.5.0
+ * @access private
+ */
+function _register_block_bindings_post_meta_source() {
+ register_block_bindings_source(
+ 'core/post-meta',
+ array(
+ 'label' => _x( 'Post Meta', 'block bindings source' ),
+ 'get_value_callback' => '_block_bindings_post_meta_get_value',
+ )
+ );
+}
+
+add_action( 'init', '_register_block_bindings_post_meta_source' );
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: trunk/src/wp-includes/block-bindings/post-meta.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="trunksrcwpincludesblockbindingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/block-bindings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/block-bindings.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/src/wp-includes/block-bindings.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -19,10 +19,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.5.0
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @param string $source_name The name of the source. It must be a string containing a namespace prefix, i.e.
- * `my-plugin/my-custom-source`. It must only contain lowercase alphanumeric
- * characters, the forward slash `/` and dashes.
- * @param array $source_properties {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param string $source_name The name of the source. It must be a string containing a namespace prefix, i.e.
+ * `my-plugin/my-custom-source`. It must only contain lowercase alphanumeric
+ * characters, the forward slash `/` and dashes.
+ * @param array $source_properties {
</ins><span class="cx" style="display: block; padding: 0 10px"> * The array of arguments that are used to register a source.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @type string $label The label of the source.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40,7 +40,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * }
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array|false Source when the registration was successful, or `false` on failure.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function register_block_bindings_source( $source_name, array $source_properties ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+function register_block_bindings_source( string $source_name, array $source_properties ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return WP_Block_Bindings_Registry::get_instance()->register( $source_name, $source_properties );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -52,7 +52,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $source_name Block bindings source name including namespace.
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array|false The unregistered block bindings source on success and `false` otherwise.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function unregister_block_bindings_source( $source_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+function unregister_block_bindings_source( string $source_name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return WP_Block_Bindings_Registry::get_instance()->unregister( $source_name );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -66,3 +66,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> function get_all_registered_block_bindings_sources() {
</span><span class="cx" style="display: block; padding: 0 10px"> return WP_Block_Bindings_Registry::get_instance()->get_all_registered();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Retrieves a registered block bindings source.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name The name of the source.
+ * @return array|null The registered block bindings source, or `null` if it is not registered.
+ */
+function get_block_bindings_source( string $source_name ) {
+ return WP_Block_Bindings_Registry::get_instance()->get_registered( $source_name );
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesclasswpblockbindingsregistryphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-block-bindings-registry.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-block-bindings-registry.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/src/wp-includes/class-wp-block-bindings-registry.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -57,13 +57,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * used to look up the override value,
</span><span class="cx" style="display: block; padding: 0 10px"> * i.e. {"key": "foo"}.
</span><span class="cx" style="display: block; padding: 0 10px"> * - @param WP_Block $block_instance The block instance.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * - @param string $attribute_name The name of an attribute .
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * - @param string $attribute_name The name of the target attribute.
</ins><span class="cx" style="display: block; padding: 0 10px"> * The callback has a mixed return type; it may return a string to override
</span><span class="cx" style="display: block; padding: 0 10px"> * the block's original value, null, false to remove an attribute, etc.
</span><span class="cx" style="display: block; padding: 0 10px"> * }
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array|false Source when the registration was successful, or `false` on failure.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function register( $source_name, array $source_properties ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function register( string $source_name, array $source_properties ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! is_string( $source_name ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> _doing_it_wrong(
</span><span class="cx" style="display: block; padding: 0 10px"> __METHOD__,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -120,7 +120,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $source_name Block bindings source name including namespace.
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array|false The unregistered block bindings source on success and `false` otherwise.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function unregister( $source_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function unregister( string $source_name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! $this->is_registered( $source_name ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> _doing_it_wrong(
</span><span class="cx" style="display: block; padding: 0 10px"> __METHOD__,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -156,7 +156,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $source_name The name of the source.
</span><span class="cx" style="display: block; padding: 0 10px"> * @return array|null The registered block bindings source, or `null` if it is not registered.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function get_registered( $source_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function get_registered( string $source_name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! $this->is_registered( $source_name ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> return null;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunksrcwpincludesclasswpblockphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/class-wp-block.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-block.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/src/wp-includes/class-wp-block.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -211,11 +211,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * "metadata": {
</span><span class="cx" style="display: block; padding: 0 10px"> * "bindings": {
</span><span class="cx" style="display: block; padding: 0 10px"> * "title": {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * "source": "post_meta",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * "source": "core/post-meta",
</ins><span class="cx" style="display: block; padding: 0 10px"> * "args": { "key": "text_custom_field" }
</span><span class="cx" style="display: block; padding: 0 10px"> * },
</span><span class="cx" style="display: block; padding: 0 10px"> * "url": {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * "source": "post_meta",
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * "source": "core/post-meta",
</ins><span class="cx" style="display: block; padding: 0 10px"> * "args": { "key": "url_custom_field" }
</span><span class="cx" style="display: block; padding: 0 10px"> * }
</span><span class="cx" style="display: block; padding: 0 10px"> * }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -226,14 +226,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * The above example will replace the `title` and `url` attributes of the Image
</span><span class="cx" style="display: block; padding: 0 10px"> * block with the values of the `text_custom_field` and `url_custom_field` post meta.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @access private
</del><span class="cx" style="display: block; padding: 0 10px"> * @since 6.5.0
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @param string $block_content Block content.
- * @param array $block The full block, including name and attributes.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param string $block_content Block content.
+ * @param array $block The full block, including name and attributes.
+ * @return string The modified block content.
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> private function process_block_bindings( $block_content ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $block = $this->parsed_block;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $parsed_block = $this->parsed_block;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // Allowed blocks that support block bindings.
</span><span class="cx" style="display: block; padding: 0 10px"> // TODO: Look for a mechanism to opt-in for this. Maybe adding a property to block attributes?
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -246,62 +246,61 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // If the block doesn't have the bindings property, isn't one of the allowed
</span><span class="cx" style="display: block; padding: 0 10px"> // block types, or the bindings property is not an array, return the block content.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( ! isset( $block['attrs']['metadata']['bindings'] ) ||
- ! is_array( $block['attrs']['metadata']['bindings'] ) ||
- ! isset( $allowed_blocks[ $this->name ] )
- ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if (
+ ! isset( $allowed_blocks[ $this->name ] ) ||
+ empty( $parsed_block['attrs']['metadata']['bindings'] ) ||
+ ! is_array( $parsed_block['attrs']['metadata']['bindings'] )
+ ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return $block_content;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $block_bindings_sources = get_all_registered_block_bindings_sources();
</del><span class="cx" style="display: block; padding: 0 10px"> $modified_block_content = $block_content;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- foreach ( $block['attrs']['metadata']['bindings'] as $binding_attribute => $binding_source ) {
- // If the attribute is not in the list, process next attribute.
- if ( ! in_array( $binding_attribute, $allowed_blocks[ $this->name ], true ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) {
+ // If the attribute is not in the allowed list, process next attribute.
+ if ( ! in_array( $attribute_name, $allowed_blocks[ $this->name ], true ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> continue;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> // If no source is provided, or that source is not registered, process next attribute.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( ! isset( $binding_source['source'] ) || ! is_string( $binding_source['source'] ) || ! isset( $block_bindings_sources[ $binding_source['source'] ] ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> continue;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $source_callback = $block_bindings_sources[ $binding_source['source'] ]['get_value_callback'];
- // Get the value based on the source.
- if ( ! isset( $binding_source['args'] ) ) {
- $source_args = array();
- } else {
- $source_args = $binding_source['args'];
- }
- $source_value = call_user_func_array( $source_callback, array( $source_args, $this, $binding_attribute ) );
- // If the value is null, process next attribute.
- if ( is_null( $source_value ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $block_binding_source = get_block_bindings_source( $block_binding['source'] );
+ if ( null === $block_binding_source ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> continue;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- // Process the HTML based on the block and the attribute.
- $modified_block_content = $this->replace_html( $modified_block_content, $this->name, $binding_attribute, $source_value );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $source_callback = $block_binding_source['get_value_callback'];
+ $source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
+ $source_value = call_user_func_array( $source_callback, array( $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 ) ) {
+ $modified_block_content = $this->replace_html( $modified_block_content, $attribute_name, $source_value );
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> return $modified_block_content;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Depending on the block attributes, replace the HTML based on the value returned by the source.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Depending on the block attribute name, replace its value in the HTML based on the value provided.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.5.0
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @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.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @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.
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- private function replace_html( string $block_content, string $block_name, string $block_attr, string $source_value ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private function replace_html( string $block_content, string $attribute_name, $source_value ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $block_type = $this->block_type;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( null === $block_type || ! isset( $block_type->attributes[ $block_attr ] ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( ! isset( $block_type->attributes[ $attribute_name ] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return $block_content;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // Depending on the attribute source, the processing will be different.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- switch ( $block_type->attributes[ $block_attr ]['source'] ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ switch ( $block_type->attributes[ $attribute_name ]['source'] ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> case 'html':
</span><span class="cx" style="display: block; padding: 0 10px"> case 'rich-text':
</span><span class="cx" style="display: block; padding: 0 10px"> $block_reader = new WP_HTML_Tag_Processor( $block_content );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -308,7 +307,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // TODO: Support for CSS selectors whenever they are ready in the HTML API.
</span><span class="cx" style="display: block; padding: 0 10px"> // In the meantime, support comma-separated selectors by exploding them into an array.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $selectors = explode( ',', $block_type->attributes[ $block_attr ]['selector'] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> // Add a bookmark to the first tag to be able to iterate over the selectors.
</span><span class="cx" style="display: block; padding: 0 10px"> $block_reader->next_tag();
</span><span class="cx" style="display: block; padding: 0 10px"> $block_reader->set_bookmark( 'iterate-selectors' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -316,7 +315,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // TODO: This shouldn't be needed when the `set_inner_html` function is ready.
</span><span class="cx" style="display: block; padding: 0 10px"> // Store the parent tag and its attributes to be able to restore them later in the button.
</span><span class="cx" style="display: block; padding: 0 10px"> // The button block has a wrapper while the paragraph and heading blocks don't.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( 'core/button' === $block_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 'core/button' === $this->name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $button_wrapper = $block_reader->get_tag();
</span><span class="cx" style="display: block; padding: 0 10px"> $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
</span><span class="cx" style="display: block; padding: 0 10px"> $button_wrapper_attrs = array();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -348,10 +347,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( $selector_attrs as $attribute_key => $attribute_value ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $amended_content->set_attribute( $attribute_key, $attribute_value );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( 'core/paragraph' === $block_name || 'core/heading' === $block_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return $amended_content->get_updated_html();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( 'core/button' === $block_name ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 'core/button' === $this->name ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $button_markup = "<$button_wrapper>{$amended_content->get_updated_html()}</$button_wrapper>";
</span><span class="cx" style="display: block; padding: 0 10px"> $amended_button = new WP_HTML_Tag_Processor( $button_markup );
</span><span class="cx" style="display: block; padding: 0 10px"> $amended_button->next_tag();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -372,12 +371,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! $amended_content->next_tag(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><span class="cx" style="display: block; padding: 0 10px"> // TODO: build the query from CSS selector.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'tag_name' => $block_type->attributes[ $block_attr ]['selector'],
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
</ins><span class="cx" style="display: block; padding: 0 10px"> )
</span><span class="cx" style="display: block; padding: 0 10px"> ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> return $block_content;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $amended_content->set_attribute( $block_type->attributes[ $block_attr ]['attribute'], esc_attr( $source_value ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], esc_attr( $source_value ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> return $amended_content->get_updated_html();
</span><span class="cx" style="display: block; padding: 0 10px"> break;
</span><span class="cx" style="display: block; padding: 0 10px">
</span></span></pre></div>
<a id="trunksrcwpsettingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-settings.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/src/wp-settings.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -344,6 +344,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/class-wp-classic-to-block-menu-converter.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/class-wp-navigation-fallback.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/block-bindings.php';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require ABSPATH . WPINC . '/block-bindings/pattern-overrides.php';
+require ABSPATH . WPINC . '/block-bindings/post-meta.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/blocks.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/blocks/index.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/block-editor.php';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -376,8 +378,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/fonts.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/class-wp-script-modules.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/script-modules.php';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-require ABSPATH . WPINC . '/block-bindings/sources/post-meta.php';
-require ABSPATH . WPINC . '/block-bindings/sources/pattern.php';
</del><span class="cx" style="display: block; padding: 0 10px"> require ABSPATH . WPINC . '/interactivity-api.php';
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> wp_script_modules()->add_hooks();
</span></span></pre></div>
<a id="trunktestsphpunittestsblockbindingsblockbindingsphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tests/phpunit/tests/block-bindings/block-bindings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/block-bindings/block-bindings.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/tests/phpunit/tests/block-bindings/block-bindings.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,106 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-/**
- * Unit tests covering the Block Bindings public API.
- *
- * @package WordPress
- * @subpackage Blocks
- * @since 6.5.0
- *
- * @group blocks
- * @group block-bindings
- *
- * @covers register_block_bindings_source
- */
-class WP_Block_Bindings_Test extends WP_UnitTestCase {
-
- const SOURCE_NAME = 'test/source';
- const SOURCE_LABEL = array(
- 'label' => 'Test source',
- );
-
- /**
- * Set up before each test.
- *
- * @since 6.5.0
- */
- public function set_up() {
- foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) {
- if ( str_starts_with( $source_name, 'test/' ) ) {
- unregister_block_bindings_source( $source_name );
- }
- }
-
- parent::set_up();
- }
-
- /**
- * Test if the block content is updated with the value returned by the source.
- *
- * @ticket 60282
- *
- * @covers register_block_bindings_source
- */
- public function test_update_block_with_value_from_source() {
- $get_value_callback = function () {
- return 'test source value';
- };
-
- register_block_bindings_source(
- self::SOURCE_NAME,
- array(
- 'label' => self::SOURCE_LABEL,
- 'get_value_callback' => $get_value_callback,
- )
- );
-
- $block_content = <<<HTML
-<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source"}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
-HTML;
-
- $parsed_blocks = parse_blocks( $block_content );
- $block = new WP_Block( $parsed_blocks[0] );
-
- $expected = '<p>test source value</p>';
- $result = $block->render();
-
- // Check if the block content was updated correctly.
- $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
- }
-
- /**
- * Test passing arguments to the source.
- *
- * @ticket 60282
- *
- * @covers register_block_bindings_source
- */
- public function test_passing_arguments_to_source() {
- $get_value_callback = function ( $source_args, $block_instance, $attribute_name ) {
- $value = $source_args['key'];
- return "The attribute name is '$attribute_name' and its binding has argument 'key' with value '$value'.";
- };
-
- register_block_bindings_source(
- self::SOURCE_NAME,
- array(
- 'label' => self::SOURCE_LABEL,
- 'get_value_callback' => $get_value_callback,
- )
- );
-
- $key = 'test';
-
- $block_content = <<<HTML
-<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "$key"}}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
-HTML;
-
- $parsed_blocks = parse_blocks( $block_content );
- $block = new WP_Block( $parsed_blocks[0] );
-
- $expected = "<p>The attribute name is 'content' and its binding has argument 'key' with value 'test'.</p>";
- $result = $block->render();
-
- // Check if the block content was updated correctly.
- $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
- }
-}
</del></span></pre></div>
<a id="trunktestsphpunittestsblockbindingsregisterphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/block-bindings/register.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/block-bindings/register.php 2024-02-02 18:48:03 UTC (rev 57525)
+++ trunk/tests/phpunit/tests/block-bindings/register.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17,19 +17,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Set up before each test.
- *
- * @since 6.5.0
- */
- public function set_up() {
- foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) {
- unregister_block_bindings_source( $source_name );
- }
-
- parent::set_up();
- }
-
- /**
</del><span class="cx" style="display: block; padding: 0 10px"> * Tear down after each test.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @since 6.5.0
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,7 +23,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function tear_down() {
</span><span class="cx" style="display: block; padding: 0 10px"> foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- unregister_block_bindings_source( $source_name );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( str_starts_with( $source_name, 'test/' ) ) {
+ unregister_block_bindings_source( $source_name );
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> parent::tear_down();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -49,6 +38,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @covers ::register_block_bindings_source
</span><span class="cx" style="display: block; padding: 0 10px"> * @covers ::get_all_registered_block_bindings_sources
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @covers ::get_block_bindings_source
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function test_get_all_registered() {
</span><span class="cx" style="display: block; padding: 0 10px"> $source_one_name = 'test/source-one';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -64,13 +54,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> register_block_bindings_source( $source_three_name, $source_three_properties );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $expected = array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $source_one_name => array_merge( array( 'name' => $source_one_name ), $source_one_properties ),
- $source_two_name => array_merge( array( 'name' => $source_two_name ), $source_two_properties ),
- $source_three_name => array_merge( array( 'name' => $source_three_name ), $source_three_properties ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $source_one_name => array_merge( array( 'name' => $source_one_name ), $source_one_properties ),
+ $source_two_name => array_merge( array( 'name' => $source_two_name ), $source_two_properties ),
+ $source_three_name => array_merge( array( 'name' => $source_three_name ), $source_three_properties ),
+ 'core/post-meta' => get_block_bindings_source( 'core/post-meta' ),
+ 'core/pattern-overrides' => get_block_bindings_source( 'core/pattern-overrides' ),
</ins><span class="cx" style="display: block; padding: 0 10px"> );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $registered = get_all_registered_block_bindings_sources();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $this->assertSame( $expected, $registered );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $this->assertEquals( $expected, $registered );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span></span></pre></div>
<a id="trunktestsphpunittestsblockbindingsrenderphpfromrev57525trunktestsphpunittestsblockbindingsblockbindingsphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/tests/block-bindings/render.php (from rev 57525, trunk/tests/phpunit/tests/block-bindings/block-bindings.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/block-bindings/render.php (rev 0)
+++ trunk/tests/phpunit/tests/block-bindings/render.php 2024-02-02 20:22:11 UTC (rev 57526)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,101 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Tests for Block Bindings integration with block rendering.
+ *
+ * @package WordPress
+ * @subpackage Blocks
+ * @since 6.5.0
+ *
+ * @group blocks
+ * @group block-bindings
+ */
+class WP_Block_Bindings_Render extends WP_UnitTestCase {
+
+ const SOURCE_NAME = 'test/source';
+ const SOURCE_LABEL = array(
+ 'label' => 'Test source',
+ );
+
+ /**
+ * Tear down after each test.
+ *
+ * @since 6.5.0
+ */
+ public function tear_down() {
+ foreach ( get_all_registered_block_bindings_sources() as $source_name => $source_properties ) {
+ if ( str_starts_with( $source_name, 'test/' ) ) {
+ unregister_block_bindings_source( $source_name );
+ }
+ }
+
+ parent::tear_down();
+ }
+
+ /**
+ * Test if the block content is updated with the value returned by the source.
+ *
+ * @ticket 60282
+ *
+ * @covers ::register_block_bindings_source
+ */
+ public function test_update_block_with_value_from_source() {
+ $get_value_callback = function () {
+ return 'test source value';
+ };
+
+ register_block_bindings_source(
+ self::SOURCE_NAME,
+ array(
+ 'label' => self::SOURCE_LABEL,
+ 'get_value_callback' => $get_value_callback,
+ )
+ );
+
+ $block_content = <<<HTML
+<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source"}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
+HTML;
+
+ $parsed_blocks = parse_blocks( $block_content );
+ $block = new WP_Block( $parsed_blocks[0] );
+
+ $expected = '<p>test source value</p>';
+ $result = $block->render();
+
+ $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
+ }
+
+ /**
+ * Test passing arguments to the source.
+ *
+ * @ticket 60282
+ *
+ * @covers ::register_block_bindings_source
+ */
+ public function test_passing_arguments_to_source() {
+ $get_value_callback = function ( $source_args, $block_instance, $attribute_name ) {
+ $value = $source_args['key'];
+ return "The attribute name is '$attribute_name' and its binding has argument 'key' with value '$value'.";
+ };
+
+ register_block_bindings_source(
+ self::SOURCE_NAME,
+ array(
+ 'label' => self::SOURCE_LABEL,
+ 'get_value_callback' => $get_value_callback,
+ )
+ );
+
+ $value = 'test';
+ $block_content = <<<HTML
+<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"test/source", "args": {"key": "$value"}}}}} --><p>This should not appear</p><!-- /wp:paragraph -->
+HTML;
+
+ $parsed_blocks = parse_blocks( $block_content );
+ $block = new WP_Block( $parsed_blocks[0] );
+
+ $expected = "<p>The attribute name is 'content' and its binding has argument 'key' with value '$value'.</p>";
+ $result = $block->render();
+
+ $this->assertEquals( $expected, $result, 'The block content should be updated with the value returned by the source.' );
+ }
+}
</ins></span></pre>
</div>
</div>
</body>
</html>