Interactivity API showcase #55642
Replies: 21 comments 45 replies
-
Hey John. Right now we have all the interactive Core blocks (Navigation, Search, File), the new Image "expand on click" feature and the first of the client-side navigation-based user experiences that prevents full reloads when users paginate on the Query block. Those have been in production in Gutenberg for a while, so they have been used in production by anyone using the Gutenberg plugin and all the sites hosted on WordPress.com. All these blocks and features are coming to WordPress 6.4, which will bundle a private version of the Interactivity API that only Core blocks can use, (so it can still be tweaked or even removed if people finally reject the proposal). Apart from that, WooCommerce is now shipping its own bundled version of the Interactivity API. If I recall correctly, they have the following blocks (either in production or about to be released): the Product Button block (Add to Cart, which now shows the number of items in the cart and is animated when the quantity changes), the Products Collection block (which has client-side navigation on pagination and filter changes, similar to the Query block), the Product Filters (which filter what's shown in the Product Collection block) and the Product Gallery block. Their intention is to keep shipping their own bundled version of the Interactivity API if/until WordPress includes a public version. The new |
Beta Was this translation helpful? Give feedback.
-
Looks like @sethrubenstein has been playing with it lately
|
Beta Was this translation helpful? Give feedback.
-
Why does interactivity API on the front-end need 31 kB? Why does every page need this big js file? https://2024.wordpress.net/wp-content/plugins/gutenberg/build/interactivity/index.min.js?ver=17.1.3 I would like to see a WP page with minimum JS or zero JS. Framework Astro shows this path with 0 JS on the front-end, see https://dev.to/ekqt/shipping-zero-javascript-with-astro-9ol |
Beta Was this translation helpful? Give feedback.
-
(reposting this to the main thread) Heres an example for everyone of the interactivity api in action. We just recently converted our Tabs blocks to the api, heres how that went: CleanShot.2023-11-29.at.18.12.56.mp4This is comprised of 5 blocks:
With really only 3 of them being "interactive". Tabs Controller is where the majority of the logic is for the tabs to work. Heres a quick sample of its view.js /**
* WordPress Dependencies
*/
import { store } from "@wordpress/interactivity";
import { addQueryArgs } from '@wordpress/url';
function updateHash(tab, uuid) {
tab.focus();
// add a tabItem query arg to the url with the id of the new tab
const { href } = window.location;
const newUrl = addQueryArgs(href, {
tabItem: uuid
});
window.history.pushState({ path: newUrl }, '', newUrl);
}
store( {
state: {
tabsController: {
// A simple log of all the tab controller blocks on the page
onPage: [],
}
},
actions: {
tabsController: {
setActiveTab: ({actions, selectors, context, ref}) => {
const { uuid } = context;
context.tabsController.activeUUID = uuid;
// When we select a new tab also update the browser history state and add the tab's uuid to the url. This allows users to copy the url and provide deep linking activation of a specific tab by url. Thats handled server side with a query var check on the block render.
updateHash(ref, uuid);
},
}
},
selectors: {
tabsController: {
isActive: ({context, ref}) => {
// Each panel|tab has its own context containing its own uuid, we can then compare that to the activeUUID in the tabsController context to see if it is active.
const { uuid, tabsController: { activeUUID } } = context;
if ( ! uuid ) {
return false;
}
return activeUUID === uuid;
}
}
},
effects: {
tabsController: {
onInit: ({actions, selectors, context, state, ref}) => {
const id = ref.getAttribute('id');
state.tabsController.onPage = [
...state.tabsController.onPage,
id,
];
const event = new CustomEvent('tabsReady', {detail: {id}});
// Fire a custom event when the tabs are ready
document.dispatchEvent(event);
}
}
}
} ); For the controller's block render heres what the looks like: /**
* Either return the uuid from the `tabItem` url var or get the uuid for the first menu item block.
* @param mixed $block
* @return mixed
*/
private function get_first_menu_item_uuid($block) {
$url_var_value = get_query_var('tabItem');
if ( $url_var_value ) {
return $url_var_value;
}
$parsed_block = $block->parsed_block;
$tabs_controller_innerblocks = $parsed_block['innerBlocks'];
$menu_block = wp_get_first_block($tabs_controller_innerblocks, 'prc-block/tabs-menu');
$first_menu_item_block = wp_get_first_block($menu_block['innerBlocks'], 'prc-block/tabs-menu-item');
return $first_menu_item_block['attrs']['uuid'];
}
/**
* Render the Tabs Controller
* @param mixed $attributes
* @param mixed $content
* @param mixed $block
* @return string
*/
public function render_block_callback( $attributes, $content, $block ) {
$initial_context = array(
'tabsController' => array(
'activeUUID' => $this->get_first_menu_item_uuid($block),
)
);
$block_wrapper_attrs = get_block_wrapper_attributes(
array(
'id' => 'tabs-'. md5( wp_json_encode( $attributes ) ),
'class' => \PRC\Platform\Block_Utils\classNames( array(
'is-vertical-tabs' => $attributes['vertical'],
'is-horizontal-tabs' => ! $attributes['vertical'],
) ),
'data-wp-interactive' => true,
'data-wp-context' => wp_json_encode($initial_context),
'data-wp-init' => 'effects.tabsController.onInit',
)
);
return wp_sprintf(
'<div %1$s><div>%2$s</div></div>',
$block_wrapper_attrs,
$content,
);
} The menu item block render: <?php
namespace PRC\Platform\Blocks;
$uuid = array_key_exists( 'uuid', $attributes ) ? $attributes['uuid'] : false;
if ( ! $uuid ) {
return;
}
$block_wrapper_attrs = get_block_wrapper_attributes(
array(
'data-wp-interactive' => true,
'data-wp-key' => 'tab-'.$uuid,
'data-wp-class--is-active' => 'selectors.tabsController.isActive',
'data-wp-context' => wp_json_encode(array('uuid' => $uuid)),
'data-wp-on--click' => 'actions.tabsController.setActiveTab',
)
);
$content = wp_kses( $attributes['title'], 'post' );
echo wp_sprintf(
'<button %1$s>%2$s</button>',
$block_wrapper_attrs,
$content,
); And then lastly this is the tabs pane render: <?php
namespace PRC\Platform\Blocks;
$uuid = array_key_exists( 'uuid', $attributes ) ? $attributes['uuid'] : false;
if ( ! $uuid ) {
return;
}
$block_wrapper_attrs = get_block_wrapper_attributes(
array(
'aria-role' => 'tabpanel',
'data-wp-interactive' => true,
'data-wp-key' => 'panel-' . $uuid,
'data-wp-class--is-active' => 'selectors.tabsController.isActive',
'data-wp-context' => wp_json_encode(array('uuid' => $uuid)),
)
);
echo wp_sprintf(
'<section %1$s>%2$s</section>',
$block_wrapper_attrs,
$content,
); Our experience with the API has been good so far. However, our dev team has expressed some consternation and confusion regarding the naming of "state" and "context". They suggest that calling them "Global State" and "Local State" or "Block State" might be more appropriate, given their functionality in a "reacty" way. Personally, I believe the current naming is fine, but additional documentation explaining the differences between the two and how they work together would be helpful. We're also interested in exploring another aspect: using the API with real React components. For instance, we're currently working on a searchable multiselect dropdown that can interact with global state, block context, and actions more smoothly. Although we have achieved some success in making it work, the approach still feels somewhat hacky. I'll share some examples of our progress soon. Looking forward to Gutenberg 17.2 releasing and really exploring (and I assume updating some of the blocks we've already converted) the updated store api. |
Beta Was this translation helpful? Give feedback.
-
I just opened this experimental proof of concept PR WordPress/wordpress-develop#5795 to use the Interactivity API to replace all dynamic frontend functionality in Twenty Twenty-One. This is mostly an exploration which explores how the API could be used even in classic theme contexts. While we speak a lot about blocks today, by no means is (or should be) the API limited to blocks. |
Beta Was this translation helpful? Give feedback.
-
👋🏾 So, this is my first block using the interactivity API. I opted to use the template from https://todomvc.com/, so that I could focus only on learning, and hooked the reactivity with the interactivity API. The documentation here has been helpful. Knowing a little bit of Alpine.js, I run into some issues with the "design" of the API. Like, "why can't the interactivity API do this Alpine.js does? Like x-show". The work on the vscode extension might help make the task easier/faster. Compared to Alpine, it takes more typing to bind and hook stuff (a lot of data-wp....). Maybe with snippets, it'll be faster. As an aside: I'd suggest adding an alias for But as soon as you understand the design of the API, all goes smoothly after that. :) CleanShot.2024-02-17.at.22.16.29-converted.mp4 |
Beta Was this translation helpful? Give feedback.
-
Ohhh, todomvc. Lovely 🙂 Do you have the code for that? It would be a great example to show! Oh, |
Beta Was this translation helpful? Give feedback.
-
I just used a bit of the Interactivity API in my tutorial on mega menus for the Developer Blog. It's not a very complex implementation, but it should be helpful for those looking to get started. |
Beta Was this translation helpful? Give feedback.
-
I'm attempting to recreate the feedback form interactivity featured on Nextjs.org/docs/ (at bottom of each docs - screenshot below). I've made some pretty good progress on hooking the toggling up. However, I'm hung up on processing and handling the submission of the form and passing along the post ID, sanitize, validate and nonce the form. Perhaps I'm stuck in the old ways of thinking on how to do things with WordPress, and I'm wondering if I'm missing something here. Here is some of the logic I'm working on for noncing and passing the info from a Post. Is reaching for WP's /**
* Adds a script to the footer that initializes the wpeFeedbackResponse object with necessary data.
*
* This function is hooked to the 'wp_footer' action.
*/
function devrel_feedback_response_script() {
if ( ! is_singular( 'post' ) ) {
return;
}
$data = array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'devrel_feedback_nonce' ),
);
$localise = wp_json_encode( $data );
printf( '<script type="text/javascript">let wpeFeedbackResponse = %s</script>', $localise ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
add_action( 'wp_footer', 'devrel_feedback_response_script' );
/**
* Handles the submission of feedback form via AJAX.
*
* This function is responsible for processing the feedback form submission and saving the feedback
* to the corresponding post meta. It checks the AJAX referer, retrieves the post ID and feedback
* from the request, sanitizes the input, and updates the post meta with the feedback value.
* If the feedback and post ID are valid, it returns a success message. Otherwise, it returns an error message.
*/
function devrel_feedback_submission_handler() {
// Check the AJAX referer.
check_ajax_referer( 'wpe_devrel_feedback_nonce', 'feedback_form_nonce' );
// Obtain the post ID and feedback from the request.
$comment = wp_filter_nohtml_kses( $_POST['feedback'] );
$comment_post_id = intval( $_POST['comment_post_id'] );
$commentdata = array(
'comment_post_id' => $comment_post_id,
'comment_content' => $comment,
'comment_author_ip' => $_SERVER['REMOTE_ADDR'],
'comment_agent' => $_SERVER['HTTP_USER_AGENT'],
'comment_approved' => 0, // Hold for moderation
);
wp_insert_comment( $commentdata );
echo 'Success';
wp_die();
}
add_action( 'wp_ajax_submit_feedback', 'devrel_feedback_submission_handler' );
add_action( 'wp_ajax_nopriv_submit_feedback', 'devrel_feedback_submission_handler' ); Is there a different method to do this in my block, and would this impact with Interactivity API integration planning (limitations, challenges)? |
Beta Was this translation helpful? Give feedback.
-
I just wanted to circle back and share that I put up my demo Feedback block plugin. I would love any insight on how to improve any of the code, and always still learning! ❤️ |
Beta Was this translation helpful? Give feedback.
-
Hey all 👋 Question: I've been going through the starter documentation again (https://developer.wordpress.org/block-editor/reference-guides/packages/packages-interactivity/#quick-start-guide) and in the basic toggle example I'm surprised to see that the data-bind to handle the show / hide actually doesn't get server rendered and I'm getting a layout shift on the client because of it. Do you have any insights on what I may be missing here? |
Beta Was this translation helpful? Give feedback.
-
Hi! I made this block plugin with the Interactivity API. https://github.com/garridinsi/carbonbadge-block/ I used this simple project to test the API and is awesome!! Also, I'm going to talk about the API on WordCamp Chiclana 2024! |
Beta Was this translation helpful? Give feedback.
-
Hello! I have created a to-do list block using the Interactivity API to learn more about it. You can find the demo of this plugin by clicking on this link. If you're interested, you can check out the code by clicking on this link. I would be highly appreciative of any suggestions to improve the code. Thank you! |
Beta Was this translation helpful? Give feedback.
-
Looks like we already have some MVC To-do apps here so I'll add mine to the mix as well! It should have all of the functionality expected and uses Demo: https://delicately-adorable.wp.build/ I've been live-streaming building this as well: Part 1: https://www.youtube.com/watch?v=VWUE2StCp_M |
Beta Was this translation helpful? Give feedback.
-
I have a gallery slider that uses the IAPI as well. It also uses the HTML API to add interactivity to core blocks Demo: slider-demo.mp4 |
Beta Was this translation helpful? Give feedback.
-
I've created instant search using Interactivity API: Instant-search-interactivity-api.movI created a thread some time ago Code: https://github.com/r-chrzan/instant-search-interactivity |
Beta Was this translation helpful? Give feedback.
-
Some really nice examples here. I put together a simple interactivity API tutorial, might be useful for someone: GitHub: https://github.com/bigbite/interactivity-api-tutorial/tree/main |
Beta Was this translation helpful? Give feedback.
-
Hey all! I wanted to share a booking form block I'm experimenting with. It's been really interesting working with Interactivity API for this one. I'm learning a lot about how Interactivity API works, I think I'm going to have a lot of fun experimenting with it in future! 3-step-booking-form.mov |
Beta Was this translation helpful? Give feedback.
-
Is there a way to add React packages? For example https://react-hot-toast.com/ |
Beta Was this translation helpful? Give feedback.
-
I experimented with region-based navigation within a custom Tabs Block 🤘 |
Beta Was this translation helpful? Give feedback.
-
Interactivity router is actually really fun to work with! I have put together this block Filterable Post List as another example of region based navigation. Feedback welcome 🙌 |
Beta Was this translation helpful? Give feedback.
-
Hey everyone,
Let's use this discussion as a showcase for what's been built with the Interactivity API so far and how successful those projects have been.
Show us your stuff!
Beta Was this translation helpful? Give feedback.
All reactions