WordPress/gutenberg

Epic: Interactivity API - public 1.0 version

luisherranz opened this issue ยท 45 comments

In More core blocks and new store() API, we first worked on preparing Core blocks for WP 6.4, including the new enhanced pagination of the Query block, and after the release of WP 6.4, we also worked on the migration of the new store() API.

For this iteration of the Interactivity API, we want to focus on the preparation of a 1.0 version that can be released publicly in WordPress Core and serve as the base for future enhancements.

We also want to consolidate here the work of the Tracking Issue: Server Directive Processing to keep all the implementation work under the same issue, but we will keep tracking the documentation-related tasks in the Documentation Tracking Issue.

Tasks

This is the list of initial tasks, although we will edit this post as we progress and discover other things that we need to do.

  • Directives
    • Implement the wp-run directive
    • Expose the useInit and useWatch hooks
    • Add data-wp-on-window and data-wp-on-document directives
    • Remove the navigation-link directive
    • Remove the wp-slot and wp-fill directives if we don't finally need them
    • Prevent using components in data-wp-text, only strings
    • Remove support for element state until naming and use cases are clearer
    • Add support for element attributes
    • Update Preact to the latest version and remove the custom role logic in our codebase
    • Expose withScope and add support for async functions (generators)
    • Add support for wp-each
    • Put all the private exports behind a locked proxy
    • Remove the non-default wp-context suffix
    • Use data-wp-interactive="namespace"
    • Review the @wordpress/interactivity exports
    • Remove the wp-body directive
    • Fix: Improve the way we merge contexts after navigation
    • Fix: Prevent proxifying non-plain objects
  • Store
    • Re-implement wp_store as wp_initial_state
    • Fix: Merge new SSR state on client-side navigation (discussion)
  • Router
    • Create the core/router store and move the navigate and prefecth actions there
    • Code-split the core/router store in @wordpress/interactivity/router
    • Rename data-wp-navigation-id to data-wp-router-region
    • Add a top loading bar on navigation
    • Add a screen reader announcement on navigation
    • Expose a way to trigger virtual pageviews, like state.url in the core/router store
    • Fix: Fix the initial page cache (code)
    • Populate state.url from the server
      • We finally decided to maintain the code that adds it from the core/router store in JS.
    • Switch to global config config['core/router'].regionNavigation = false
    • Fix: Add data-wp-key to the page numbers
  • Block metadata
    • Add clientNavigation and interactive to block supports metadata.
    • Move block script module registration to the render_callback and use wp_scripts_get_suffix
    • Use private stores for all the interactive core block stores
  • Server Directive Processing
    • Make sure we only process the directives once
    • Sort directives by priority
    • Add support for data-wp-interactive='{ "namespace": "..." }'
    • Improve block identification (check the block name before the md5)
    • Render the root interactive blocks
    • Encapsulate everything into a single function wp_interactivity_process_directives()
    • Make sure it bails out on unbalanced tags
    • Add tests for edge cases
    • Add processor for wp-each
    • Optional: Add a helper function to add data-wp-context on PHP
    • Optional: Add support for private stores
    • Fix: Skip SVG and MathML (instead of bail out)
  • Debug
  • Code Quality
    • Optional: Typscript the entire runtime. Add comments to functions. Etc.

Related to the server-side directive processing and the above PR #56302, are there any plans to provide an API function that is decoupled from blocks? I think there are many use-cases (primarily classic "hard-coded" HTML in core, plugins, and themes) that could use the Interactivity API. If such use-cases could then call a simple function to process the directives on the HTML string, that would be really helpful.

Potentially the function gutenberg_process_interactive_html() introduced in #56302 could be what I'm looking for? As far as I can tell, the only block specific part is $inner_blocks which could be omitted?

@felixarntz yeah, we're still trying different things here. To be honest, I'm not very happy with the current approach. And as you say, it's quite coupled with blocks.

I think we can simplify it to process only on the "root interactive blocks" and try to encapsulate everything in a single function. Maybe something like this that also classic themes could use:

$html = do_interactivity( $html );

To do so, we need to get rid of all the things that depend on knowing which part of the HTML belongs to which block during the processing (like private stores), but I think it's doable and it will simplify things.

What do you think?

Thanks @luisherranz, that sounds like a good plan to me. I have to admit, my understanding of private stores is quite limited still. But what you're saying sounds solid as far as I can assess.

Regarding a function name, I'd prefer to do away with the "do" prefix. While it's sort of common for some WP processing functions, I think it's also somewhat legacy. I would find something like process_interactivity or parse_interactivity or parse_interactivity_directives more suitable. But a function name is probably the last challenge in this ๐Ÿ˜†

Haha, sure. That's because I was thinking about do_blocks, but those names sound good to me. Let's see if we can condense everything into a single function ๐Ÿ™‚

Added a PR to render the root interactive blocks in Server Directives Processing. Ready to review!

I created a PR to implement the data-wp-run directive. I saw it convenient to include also the hooks useWatch and useInit in the same PR. Ready for review.

The PR with wp_initial_state was merged:

Created two PRs that remove directives that are not being used:

I labeled them as breaking changes, in case some external developers have been using them.

The wp-run directive implementation, the new useWatch and useInit hooks, and the scoped version of all callback-based hooks have been recently merged.

Prevent using components in data-wp-text is ready for review:

I'm currently working on the data-wp-each directive. Only the documentation needs to be included at this point.

I'll set the PR ready for review shortly.

I'm currently working on the upgrade of the dependencies. Is still draft, as needs some testing and I found the role in navigation is only appearing at the second click on the open button. Working and merged.

Added a bugfix that @luisherranz spotted while discussing wp-on-window and wp-on-document.

New directives wp-on-window and wp-on-document are ready for review:

๐Ÿ‘‹ Hello team. Whats the update on this feature for WP 6.5? Is it likely to land and if so which features (as originally outlined in the roadmap) will make it. Thanks in advance ๐Ÿ™

Added a PR to rename props to attributes and remove state from getElement():

Whats the update on this feature for WP 6.5? Is it likely to land and if so which features (as originally outlined in the roadmap) will make it.

Hey Dave ๐Ÿ‘‹

The main addition is the server directive processing. I'm currently working on the backport. I'll open a couple of PRs tomorrow, one here in Gutenberg in the /compat/wordpress-6.5 folder and another one in WordPress Core.

The rest of the features that require backports are optional, and it's not clear which ones we will finally include. We'll evaluate them next week and we'll let you know.

Made a PR for "Expose withScope and add support for async functions (generators)"

I did a refactor of the server directive processing logic that covers most of the remaining SDP tasks and is prepared to be backported into WordPress 6.5:

EDIT: @getdave, I'll open another PR in WordPress Core with these changes.

Thank you. If you're able to keep #57959 updated that would be much appreciated ๐Ÿ™‡

Small update here.

This is in really good shape now. We'll try to merge the new server directive processing refactor in time for GB 17.6. Apart from that:

  • wp-each:
    • The client runtime is ready. The PR is not merged yet due to failing tests in trunk, but it should be available for GB 17.6.
    • I'll start working on the wp-each server processor.
  • @wordpress/interactivity/router store
    • @DAreRodz is working on it, making good progress.
  • Query block
    • We'll work on adding the top-loading bar animation and screen announcement to the navigate action.
    • We'll also move the data-wp-navigation-disabled directive to a global core/router config using the new wp_interactivity_config API.
    • We'll add supports.clientNavigation to the block.json schema and we'll update the Query block to check for supports.clientNavigation.
  • We'll add supports.interactivity to the block.json schema.

The rest of the tasks are smaller details or optional items. We will keep working on them and reporting here.

  • We'll add supports.interactivity to the block.json schema.

Once tests passed it will be ready to review.

I created a PR to move all the router-related code to its own module and package. Awaiting tests to be merged.

I've also created another one to rename the data-wp-navigate-id directive to data-wp-router-region.

I've opened a new PR to move all the logic related to the ARIA live region and the loading bar from the Query block to the Interactivity Router. Ready for review.

Can someone please clarify what is the name of the function for a default store in PHP?

In previous release was wp_store, then changed to wp_initial_state. Now it seems it's renamed to wp_interactivity_state.

Can we please specify this in docs as well?

#58436

@Tropicalista: yes, we've renamed the function. I'll make a PR to update the docs once GB 17.6 is released with the final name.

Please follow the changelog and breaking changes discussion to get the latest updates on how the API evolves.

I have opened a draft PR to fix the initial page cache in the @wordpress/interactivity-router module.

I opened a PR that adds a server processor for data-wp-each:

Small update.

  • The last two server directive processors (data-wp-each and data-wp-router-region) have been merged.
  • The navigate function now triggers the loading bar and screen reader announcement by default.

Remaining tasks:

  • Query block: switch from data-wp-navigation-disabled to config['core/router'].clientNavigation = false
  • Image block: see if we can remove the data-wp-body directive.
  • Other small tweaks.

I added two more PRs:

Added a PR with some small changes in comments. And refactors to TS.

I've created a PR to make all core block stores private.

It includes a bugfix that solves a problem with the async initialization of private stores.

I've opened a PR to support data-wp-interactive="myPlugin".

Here, a draft PR that implements global configs in the JS runtime:

It also gets rid of the data-wp-navigation-disabled attribute we were adding to Query blocks when they contain unsupported blocks. Instead, a property clientNavigation inside the core/query config is used.

EDIT: the PR is ready for review now.

I have updated the task list to mark "Populate state.url from the server" as complete, explaining that we decided not to implement that and keep the logic that initializes it from JS in @wordpress/interactivity-router.

This PR limits the exposed API from @wordpress/interactivity:

I opened a PR to remove the data-wp-body directive and refactor the Image block to add the overlay using wp_footer instead:

Regarding one meta aspect of how we communicate this functionality more broadly, I think Interactivity API is ok as the technical aspect for developers, but when we talk broadly about what it does I think we should refer to it as Interactions. Interactions is the feature, and it's powered by this new developer API.

So similar to block API -> blocks we'll have interactivity API -> interactions. I find that clearer and easier than interactivity on its own, but curious what others think. I don't believe this has any material considerations on namespace issues at the code level, except perhaps the possibility of renaming the entry package to @wordpress/interactions.

Regarding one meta aspect of how we communicate this functionality more broadly, I think Interactivity API is ok as the technical aspect for developers, but when we talk broadly about what it does I think we should refer to it as Interactions. Interactions is the feature, and it's powered by this new developer API.

So similar to block API -> blocks we'll have interactivity API -> interactions. I find that clearer and easier than interactivity on its own, but curious what others think. I don't believe this has any material considerations on namespace issues at the code level, except perhaps the possibility of renaming the entry package to @wordpress/interactions.

This would need careful consideration, for sure. Having 2 names for the same functionality can also make things less clear in some cases. There is currently this issue with people referring to the "WordPress Block Editor" as "The Gutenberg Editor". Maybe `interactivity API -> interactivity"? Just a thought.

Added a PR to fix directives not being processed if the HTML contained a SVG or a MATH.

Now that we are past the Beta 1 cut off point I'm removing this tracking issue from the 6.5 Project board. From now on the board should only contain individual bugs that we want to still fix before 6.5 gets released.

Should we also close the issue an open separate issues for remaining tasks so those applicable can be put on the 6.5 board and tackled before 6.5 Beta 3 scheduled for Tuesday next week?

I will miss this tracking issue ๐Ÿ˜…, but yep, I will do that.