Make WordPress Core

Opened 6 months ago

Closed 5 months ago

Last modified 4 months ago

#60356 closed enhancement (fixed)

Interactivity API: Server Directive Processing

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

Description

The Interactivity API enables WordPress developers to create dynamic and interactive web experiences with ease using a set of special HTML attributes called directives. Please refer to the Interactivity API proposal for further details.

This API processes the interactivity directives embedded within HTML content and transforms the markup in the server, seamlessly merging the server-rendered markup with the client-side interactivity to guarantee that:

  • Users view the correct HTML before the JavaScript loads.
  • There are no layout shifts when the JavaScript finally loads.

API

wp_interactivity_state( $store_namespace, $state )

Sets or gets the initial state of an interactivity store.

This state is used during the server directive processing and then is serialized and sent to the client as part of the interactivity data to be recovered during the hydration of the client interactivity stores.

Once the user starts interacting with the page, the actions contained in the stores will update this state, and the Interactivity API runtime will transform the markup accordingly.

<?php
// Sets the initial state for the 'myPlugin' namespace.
wp_interactivity_state( 'myPlugin', array( 'counter' => 0 ) );

// Gets the current state for the 'myPlugin' namespace.
$state = wp_interactivity_state( 'myPlugin' );

wp_interactivity_config( $store_namespace, $config )

Sets or gets configuration for an interactivity store.

This configuration is also serialized to the client, but it's static information about the page/site (it's not reactive).

<?php
// Sets configuration for the  'myPlugin' namespace.
wp_interactivity_config( 'myPlugin', array( 'setting' => true ) );

// Gets the current configuration for the 'myPlugin' namespace.
$config = wp_interactivity_config( 'myPlugin' );

wp_interactivity_process_directives( $html )

Processes directives within HTML content, updating the markup where necessary.

<?php
$html_content = '<div data-wp-bind--text="myPlugin::state.message"></div>';

// Process directives in HTML content.
wp_interactivity_state( 'myPlugin', array( 'message' => 'hello world!' ) );
$processed_html = wp_interactivity_process_directives( $html_content );

// output: <div data-wp-bind--text="myPlugin::state.message">hello world!</div>

Filter: wp_interactivity_process_directives_of_interactive_blocks

This function hooks into WordPress's block rendering pipeline, identifying the outermost interactive block in a hierarchy and marking it for directive processing after rendering. Subsequent nested blocks are ignored during this pass because their output is included in the root block's render. Once the root block's HTML is processed, the markup is transformed and ready to be sent to the client.

Feedback

Please share your thoughts, potential use cases, or any other input that could help us refine and enhance this feature. Use this Trac ticket or the main pull request for discussions.

Change History (16)

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


6 months ago
#1

  • Keywords has-patch has-unit-tests added

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

---

This PR backports the Server Directive Processing of the new Interactivity API for WordPress.

The Interactivity API enables WordPress developers to create dynamic and interactive web experiences with ease using a set of special HTML attributes called directives. Please refer to the Interactivity API proposal for further details.

This API processes the interactivity directives embedded within HTML content and transforms the markup in the server, seamlessly merging the server-rendered markup with the client-side interactivity to guarantee that:

  • Users view the correct HTML before the JavaScript loads.
  • There are no layout shifts when the JavaScript finally loads.

## API

### wp_interactivity_state( $store_namespace, $state )

Sets or gets the initial state of an interactivity store.

This state is used during the server directive processing and then is serialized and sent to the client as part of the interactivity data to be recovered during the hydration of the client interactivity stores.

Once the user starts interacting with the page, the actions contained in the stores will update this state, and the Interactivity API runtime will transform the markup accordingly.

// Sets the initial state for the 'myPlugin' namespace.
wp_interactivity_state( 'myPlugin', array( 'counter' => 0 ) );

// Gets the current state for the 'myPlugin' namespace.
$state = wp_interactivity_state( 'myPlugin' );

### wp_interactivity_config( $store_namespace, $config )

Sets or gets configuration for an interactivity store.

This configuration is also serialized to the client, but it's static information about the page/site (it's not reactive).

// Sets configuration for the  'myPlugin' namespace.
wp_interactivity_config( 'myPlugin', array( 'setting' => true ) );

// Gets the current configuration for the 'myPlugin' namespace.
$config = wp_interactivity_config( 'myPlugin' );

### wp_interactivity_process_directives( $html )

Processes directives within HTML content, updating the markup where necessary.

$html_content = '<div data-wp-bind--text="myPlugin::state.message"></div>';

// Process directives in HTML content.
wp_interactivity_state( 'myPlugin', array( 'message' => 'hello world!' ) );
$processed_html = wp_interactivity_process_directives( $html_content );

// output: <div data-wp-bind--text="myPlugin::state.message">hello world!</div>

### Filter: wp_interactivity_process_directives_of_interactive_blocks

This function hooks into WordPress's block rendering pipeline, identifying the outermost interactive block in a hierarchy and marking it for directive processing after rendering. Subsequent nested blocks are ignored during this pass because their output is included in the root block's render. Once the root block's HTML is processed, the markup is transformed and ready to be sent to the client.

## Feedback

Please share your thoughts, potential use cases, or any other input that could help us refine and enhance this feature. Use the Trac ticket or this pull request for discussions.

Thank you! 🙏

## Remaining tasks

The code here is ready for initial reviews, but I'd like to finish a few tasks before considering it complete:

  • [ ] Check support for SVG and MathML elements.
  • [ ] Add processor for data-wp-router-region.
  • [ ] Add processor for data-wp-each.
  • [ ] Add support for namespace strings, like data-wp-interactive="myPlugin".

I'll work on them and report my progress here.

#2 @gziolo
5 months ago

  • Component changed from General to Editor
  • Milestone changed from Awaiting Review to 6.5
  • Version set to trunk

@luisherranz commented on PR #5953:


5 months ago
#3

Thanks for the review @sirreal! I've addressed the feedback 🙂

@luisherranz commented on PR #5953:


5 months ago
#4

I've removed the temporary module registration that was included in `trunk` until this patch was committed.

I've also opened a PR that adds the data-wp-each processor on Gutenberg. I'll sync the changes here once it's merged:

@luisherranz commented on PR #5953:


5 months ago
#5

Thanks for the feedback, @swissspidy and @westonruter.

I've addressed all the actionable comments, and I'll wait until @dmsnell answers the remaining one to see if that should be fixed here or in the HTML API.

@luisherranz commented on PR #5953:


5 months ago
#6

Both data-wp-each and data-wp-router-region processors have been merged in Gutenberg.

I'll port them here.

@westonruter commented on PR #5953:


5 months ago
#7

I think with my latest feedback addressed this should be good to commit!

@luisherranz commented on PR #5953:


5 months ago
#8

Ok, everything but this suggestion has been addressed. I'll try making it work later. I've also added support for data-wp-interactive="myPlugin" and data_wp_context( $context ).

Except for that last suggestion, I now consider everything here complete and working. I don't expect any more changes from my side, so as soon as people are happy with it, we can commit.

Thanks, Weston, for helping me shape this code!

@luisherranz commented on PR #5953:


5 months ago
#9

Nit: Actually, I suggest consistently using hyphens instead of underscores for CSS class names and style handles.

Sorry, I read the other way around 🤦‍♂️

---

Ok, this should be ready now!

#10 @gziolo
5 months ago

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

In 57563:

Interactivity API: Integrate Server Directive Processing

The Interactivity API enables WordPress developers to create dynamic and interactive web experiences with ease using a set of special HTML attributes called directives. Please refer to the [Interactivity API proposal](https://make.wordpress.org/core/2023/03/30/proposal-the-interactivity-api-a-better-developer-experience-in-building-interactive-blocks/) for further details.

It syncs the changes from the Gutenberg plugin: https://github.com/WordPress/gutenberg/pull/58066.

Fixes #60356.
Props luisherranz, jonsurrell, swissspidy, westonruter, gziolo.

@gziolo commented on PR #5953:


5 months ago
#11

Committed with https://core.trac.wordpress.org/changeset/57563. Thank you everyone for all help to make that happen 🎉

#12 @gziolo
5 months ago

In 57564:

Interactivity API: Remove empty file

Missed that when applying patch from GitHub.

Follow-up [57563].
See #60356.
Props: swissspidy.

@luisherranz commented on PR #5953:


5 months ago
#13

Thanks, Greg! ❤️

A huge kudos to @darerodz, @santosguillamot and @c4rl0sbr4v0 for shaping the Interactivity API with me, to @ockham for the initial work on the server directive processing logic, to @dmsnell for his support with the HTML APIs, to @gziolo, @mtias and @youknowriad for their continued support and feedback on the APIs, to @westonruter, @felixarntz and @swissspidy for their support and their help shaping this for WP Core, and finally to @poliuk and @rmartinezduque for their _under the scenes_ work to make this API a reality.

I'm sure I forget people, but thanks to everyone for your support of this initiative. This is just the beginning, but I hope it adds value to all the WordPress users for many years to come 🙂

#14 @stevenlinx
5 months ago

  • Keywords needs-dev-note added

as part of the standalone dev note post

#15 @swissspidy
5 months ago

In 57646:

Interactivity API: Use string instead of object in data-wp-interactive attribute.

The server directive processing, integrated in [57563], supports a simplified format for passing the namespace to data-wp-interactive.

Props cbravobernal, gziolo.
Fixes #60542.
See #60356.

#16 @sabernhardt
4 months ago

  • Keywords has-dev-note added; needs-dev-note removed
Note: See TracTickets for help on using tickets.