Make WordPress Core

Opened 5 months ago

Closed 4 months ago

Last modified 4 months ago

#60282 closed enhancement (fixed)

Add the Block Bindings API, including the "post_meta" and "pattern" sources

Reported by: czapla's profile czapla Owned by: youknowriad's profile youknowriad
Milestone: 6.5 Priority: normal
Severity: normal Version:
Component: Editor Keywords: has-patch has-unit-tests needs-dev-note
Focuses: Cc:

Description

Introduce the Block Bindings API for WordPress.

This includes 2 sources for block bindings:

  • post meta
  • patterns

Change History (41)

This ticket was mentioned in PR #5888 on WordPress/wordpress-develop by @czapla.


5 months ago
#1

  • Keywords has-unit-tests added

More information about the Block Bindings API: https://github.com/WordPress/gutenberg/issues/54536


Trac ticket: https://core.trac.wordpress.org/ticket/60282

This PR introduces the Block Bindings API for WordPress.

The API allows developers to connects block attributes to different sources. In this PR, two such sources are included: "post meta" and "pattern". Attributes connected to sources can have their HTML replaced by values coming from the source in a way defined by the binding.

On a technical level, the way the API works is a 3-step process:

  1. Create a binding between block attributes and a source - _in the editor_.
  2. Get the value from the source defined in the binding - _at runtime._
  3. Update the HTML using the value obtained from the source - _at runtime_.

### 1. Create a binding

The bindings have the following structure:

_An example binding for the content attribute of Paragraph block and the url attribute of the Image block.
Both using the post_meta source._

// These are block attributes
{
    "metadata": {
        "bindings": {
            "content": {
                "source": {
                    "name": "post_meta",
                    "attributes": {
                        "value": "text_custom_field"
                    }
                }
            },
            "url": {
                "source": {
                    "name": "post_meta",
                    "attributes": {
                        "value": "url_custom_field"
                    }
                }
            }
        }
    }
}

This PR does not include any UI for adding those metatada attributes to blocks at the moment. This is intentional as the API is meant as a building block and such UI will be developed later.

### 2. Get the value

This PR includes a mechanism for registering "sources" for the block bindings. A "source" defines where to get a value for the binding from. Two sources are included in this PR:

  • "post meta"
  • "pattern" - which is used by Partially Synced Patterns

Each source is responsible any logic required to obtain the value from a source.

### 3. Update the HTML

At runtime, the HTML API is used to update the HTML of the block with values from the block binding sources. At the moment, a limited and hardcoded number of blocks and attributes is supported in this PR:

$allowed_blocks = array(
    'core/paragraph' => array( 'content' ),
    'core/heading'   => array( 'content' ),
    'core/image'     => array( 'url', 'title', 'alt' ),
    'core/button'    => array( 'url', 'text' ),
);

@talldanwp commented on PR #5888:


5 months ago
#2

The API allows developers to connects block attributes to different sources. In this PR, two such sources are included: "post meta" and "pattern".

An option could be to consider a separate backport PR for the 'pattern' source, as I think there's also a little bit of extra code needed to set up the block context for pattern overrides. Let me know what you think.

@artemiosans commented on PR #5888:


5 months ago
#3

Summarizing my comments, we could further simplify what gets exposed as a public API for v1. We should consider moving two functions to WP_Block class as private methods:

  • wp_block_bindings_replace_html
  • _process_block_bindings

@gziolo Ok I addressed this in https://github.com/WordPress/wordpress-develop/pull/5888/commits/9303e02f1c755256fd5011250cd754ed6bf9ccd4. But we still need to expose the processing somehow, right? I added a wrapper function process_bindings to the class so we can still access the logic.

Which leads me to the next observation, that we should follow the established pattern and rename the method to align:

function register_block_binding( $name, $properties )
If we follow other registration helpers, the class name would better fit as:
WP_Block_Bindings_Registry

Ok I've updated the class name and renamed the methods in https://github.com/WordPress/wordpress-develop/pull/5888/commits/30f4ed76f41be76c0cb929e883176ad98ec11312. However, I don't think we can go with just register_block_binding because technically, a _binding_ is the act of connecting a block's attribute to a source in the editor, and what we're doing here is registering the source to facilitate that connection. I think it would be good to continue making that distinction to keep things simple to understand.

@artemiosans commented on PR #5888:


5 months ago
#4

Also, the latest changes will break the tests, so we need to update those.

@artemiosans commented on PR #5888:


5 months ago
#5

Hi all! I believe I've addressed all of the outstanding issues up to now except for the following:

  • Refactoring the processing of block bindings into two steps as discussed here. I think this one can be handled in a separate PR.
  • Refactoring to use post ID from the block context, which seems it may require more discussion and could be handled separately as well (discussion 1) (discussion 2)
  • Potentially remove manual check for supported blocks and properties in the future, as per usage of the HTML API sometime in the future (discussion)

It seems there's still some discussion to be had on the structure of the bindings object and naming of certain methods as well, namely register() which I can follow up on next week.

Am I missing anything? Let me know what you all think, thanks! 🙏

#7 @gziolo
5 months ago

In 57373:

Editor: Add registry for block binding sources

It is part of the sync from the Gutenberg plugin that introduces the registry for block binding sources required for the new Block Bindings API: https://github.com/WordPress/gutenberg/issues/54536.

See #60282.
Props czapla, artemiosans, santosguillamot, sc0ttkclark, lgladdy, talldanwp, swissspidy, youknowriad, fabiankaegy.

@gziolo commented on PR #5888:


5 months ago
#9

I landed the WP_Block_Bindings_Registry class with https://core.trac.wordpress.org/changeset/57373. Let's update the branch to reflect it.

#11 @gziolo
5 months ago

In 57375:

Editor: Add Block Bindings API helpers

It is part of the sync from the Gutenberg plugin that introduces the registry for block binding sources required for the new Block Bindings API: WordPress/gutenberg#54536.

See #60282.
Follow-up [57373].
Props czapla, artemiosans, santosguillamot, sc0ttkclark, lgladdy, talldanwp, swissspidy, youknowriad, fabiankaegy, mukesh27.

@gziolo commented on PR #5888:


5 months ago
#13

I also landed register_block_bindings_source, unregister_block_bindings_source and get_all_registered_block_bindings_sources with functions with https://core.trac.wordpress.org/changeset/57375.

@czapla commented on PR #5888:


5 months ago
#14

There are currently some unit test failures. I'm working on fixing them.

#15 @gziolo
5 months ago

In 57385:

Tests: Remove redundant unregister call in block bindings tear down

Only block bindings sources registered in the tests should get unregistered.

Follow-up for [57375].
See #60282.
Props czapla.

@czapla commented on PR #5888:


5 months ago
#16

~An option could be to consider a separate backport PR for the 'pattern' source, as I think there's also a little bit of extra code needed to set up the block context for pattern overrides. Let me know what you think.~

Actually, this changed recently, there are now no backports for pattern overrides other than the registration of the binding source.

Thanks for the update @talldan 🙏

@czapla commented on PR #5888:


5 months ago
#17

The tests are passing now and I believe all of the feedback has been addressed.

Summary of the updates:


As previosly mentioned by @artemiomorales, the following can be handled in follow-up PRs:

cc @artemiomorales @SantosGuillamot @gziolo

@artemiosans commented on PR #5888:


5 months ago
#18

During my testing, I realized that pattern overrides are no longer working on this branch or on trunk. I haven't been able to look into identifying the cause yet, though it may be getting addressed by this PR on the Gutenberg side:

#19 @swissspidy
5 months ago

  • Component changed from General to Editor

#20 @andraganescu
5 months ago

I opened an issue on Github about Standardizing data access for blocks on the server in place of my previous comment.

Last edited 5 months ago by andraganescu (previous) (diff)

@talldanwp commented on PR #5888:


5 months ago
#21

During my testing, I realized that pattern overrides are no longer working on this branch or on trunk. I haven't been able to look into identifying the cause yet, though it may be getting addressed by this PR on the Gutenberg side:

It could be that. A lot of the pattern overrides code also resides in the block library package in gutenberg, so a package update for wordpress core might also be required (and then this branch rebased).

There were quite a few last minute PRs added to the last Gutenberg release.

@czapla commented on PR #5888:


5 months ago
#22

The unit tests are failing because Tests_WP_Customize_Widgets::test_get_selective_refreshable_widgets_when_no_theme_supports test calls $this->do_customize_boot_actions(); which calls do_action( 'init' );.

Because of this, the init action is fired twice and this check fails.

If understand correctly, init could be fired multiple times per request on a site under some circumstances (which is what happens here). Block registration has a similar check.

I'm not sure what the right behavior here should be. I see these options:

  1. For the bindings that ship in core (post-meta & pattern), always unregister any bindings with the same name.
  2. Remove the _doing_it_wrong() altoghether.

What do you think @youknowriad @gziolo ?

@gziolo commented on PR #5888:


5 months ago
#23

The following diff should resolve the issue that exists only in the test env:

  • tests/phpunit/includes/functions.php

    diff --git a/tests/phpunit/includes/functions.php b/tests/phpunit/includes/functions.php
    index 81d4339db1..0fdff9c71a 100644
    a b tests_add_filter( 'send_auth_cookies', '__return_false' ); 
    339339 * @since 5.0.0
    340340 */
    341341function _unhook_block_registration() {
     342        // Block types.
    342343        require __DIR__ . '/unregister-blocks-hooks.php';
    343344        remove_action( 'init', 'register_core_block_types_from_metadata' );
    344345        remove_action( 'init', 'register_block_core_legacy_widget' );
    345346        remove_action( 'init', 'register_block_core_widget_group' );
    346347        remove_action( 'init', 'register_core_block_types_from_metadata' );
     348
     349        // Block binding sources.
     350        remove_action( 'init', '_register_block_bindings_pattern_overrides_source' );
     351        remove_action( 'init', '_register_block_bindings_post_meta_source' );
    347352}
    348353tests_add_filter( 'init', '_unhook_block_registration', 1000 );

It will never be the case in the production code.

#24 @youknowriad
5 months ago

  • Owner set to youknowriad
  • Resolution set to fixed
  • Status changed from new to closed

In 57514:

Editor: Add the Block Bindings API.

This introduces the Block Bindings API for WordPress.

The API allows developers to connects block attributes to different sources. In this PR, two such sources are included: "post meta" and "pattern". Attributes connected to sources can have their HTML replaced by values coming from the source in a way defined by the binding.

Props czapla, lgladdy, gziolo, sc0ttkclark, swissspidy, artemiosans, kevin940726, fabiankaegy, santosguillamot, talldanwp, wildworks.
Fixes #60282.

#27 @gziolo
5 months ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening as there are still issues to fix like the bug discussed in this thread: https://github.com/WordPress/wordpress-develop/pull/5888#discussion_r1475692597.

@youknowriad commented on PR #6016:


5 months ago
#28

Thanks for handing the follow-up @gziolo I appreciate it. On a quick glance, everything looks good to me.

#29 @gziolo
5 months ago

In 57526:

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 [57514].
Props: gziolo, mukesh27, youknowriad, santosguillamot.
See #60282.

This ticket was mentioned in PR #6029 on WordPress/wordpress-develop by @czapla.


5 months ago
#31

This PR improves the inline documentation for the Block Bindings API.

It also implements a minor improvement from https://github.com/WordPress/wordpress-develop/pull/5888#discussion_r1476793062. The values passed to $processor->set_attribute() should not be escaped.

@czapla commented on PR #6029:


5 months ago
#32

Maybe it's enough to put there @see register_block_bindings_source annotation. I left two suggestions to discuss further before I commit changes.

That makes sense. I also added a note in 94385a524085363cdd07b9870109123e2601a63c saying it's a low-level method and register_block_bindings_source() should be used in most cases instead.

#33 @gziolo
5 months ago

In 57560:

Editor: Improve code documentation for block bindings

Follow-up [57514].
See #60282.
Props czapla, gziolo, retrofox.

#35 @gziolo
5 months ago

In 57562:

Editor: Introduce WP_Block_Bindings_Source class

Abstracts the block bindings source array into a well-defined object.

Fixes #60447.
See #60282.
Follow-up [57373].
Props czapla, santosguillamot, gziolo.

This ticket was mentioned in PR #6059 on WordPress/wordpress-develop by @czapla.


4 months ago
#36

This PR refactors the processing of block bindings into 2 steps.

#### Before

process_block_bindings() takes the $block_content as input and:

  1. Gets the value for each "bound" attribute from the respective source.
  2. For each updated attribute calls replace_html() to get the updated $block_content filled in with the values from the updated attributes.

#### Now

process_block_bindings() doesn't take any input

  1. Gets the value for each "bound" attribute from the respective source.
  2. Returns the updated attributes with values from the sources.
  3. The updated attributes are used in the render() function of the block where replace_html() is called with the updated attributes.

Trac ticket: https://core.trac.wordpress.org/ticket/60282

#37 @gziolo
4 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 57574:

Editor: Refactor block binding processing and attribute computation

Refactors the processing of block bindings into steps:

  • Gets the value for each "bound" attribute from the respective source.
  • Returns the computer attributes with values from the sources.
  • The computed attributes get injected into block's content.
  • The render_callback gets the updated list of attributes and processeded block content.

Fixes #60282.
Props czapla, gziolo, andraganescu, santosguillamot.

#39 @gziolo
4 months ago

In 57575:

Editor: Add wakeup magic method to the block bindings registry

See #60282.
Follow-up [57373].
Props dmsnell, mukesh27, gziolo.

@gziolo commented on PR #6059:


4 months ago
#40

Currently the binding process is completely on, nether $block_content = $this->process_block_bindings( $block_content ); or $modified_block_content = $this->replace_html are filtered. Is it too soon to consider filters? Maybe it is.

@draganescu, we could always discuss introducing new settings for the block binding source:

  • filter_callback to post-process the raw value returned by the source, example: date formatting.
  • should_replace_callback to run before $this->replace_html() that would let folks decide whether to replace the value for an attribute in HTML.

We should be iterating on the public API as we learn about the most common needs reported by developers.

#41 @stevenlinx
4 months ago

  • Keywords needs-dev-note added

as part of the standalone dev note post.

Note: See TracTickets for help on using tickets.