<div style="text-align:center"></div><div>
<p>WordPress 6.8 comes with a few new best practices and requirements in the Interactivity API that are part of a longer-term continuous-improvement effort. Some of the relevant changes in 6.8 are an intermediary step: They do not include these enhancements themselves, but they prepare the project to add them in a future release by adding two new deprecation warnings.</p>
<p>If you have been using the Interactivity API in your project, especially if you have been writing your own stores, please read on to learn how you can prepare your changes for the latest and future behavior of the API.</p>
<h2 class="wp-block-heading">How to apply the latest best practices (and avoid deprecation warnings)</h2>
<p>To help the Interactivity API speed up WordPress, the project is working towards running most store actions asynchronously by default, as a better foundation for achieving good INP (“Interaction to Next Paint”) performance. Right now, browsers invoke all synchronous Interactivity API event handlers as part of the same task—this means they stack up. This can make the user wait for longer than 50 milliseconds (also called a <a href="https://web.dev/articles/optimize-long-tasks">“long task”</a>) for the site to react to some interaction, like clicking a button.</p>
<p>Starting with 6.8, and going forward, the Interactivity API’s push towards asynchronous handlers as the default will make those long tasks less likely. The 6.8 release only prepares for the transition. In the following WordPress release, the API will automatically yield to the main thread in between handlers, so ideally there’s nothing to stack up, and nothing to make the user wait. (Also refer to <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/api-reference/#:~:text=%7D%20)%3B-,Async%20actions,-Async%20actions%20should">async actions</a> and the <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/api-reference/#:~:text=API%20provides%20the-,splitTask(),-function%20for%20that"><code>splitTask()</code> function</a>.)</p>
<p>This performance enhancement also helps with cross-plugin compatibility, as handlers for the same event may come from different plugins. The new requirements outlined below are an important step to prepare the Interactivity API for that future.</p>
<h3 class="wp-block-heading">Wrap certain action callbacks in <code>withSyncEvent()</code></h3>
<p>Pay attention to any store action that is attached to an event listener (like <code>data-wp-on--click</code>) <em>and</em> accesses the <code>event</code> object: If the action callback uses any of the <code>event</code> properties or methods below, you need to wrap it in a newly added utility function called <code>withSyncEvent()</code>:</p>
<ul class="wp-block-list">
<li>Property: <code>event.currentTarget</code></li>
<li>Method: <code>event.preventDefault()</code></li>
<li>Method: <code>event.stopImmediatePropagation()</code></li>
<li>Method: <code>event.stopPropagation()</code></li>
</ul>
<p><strong>Starting in WordPress 6.8, if any action callback uses the above <code>event</code> properties or methods and is not wrapped in <code>withSyncEvent()</code>, that action callback will trigger a deprecation warning.</strong> For now, the logic will continue to work as before. But in a future WordPress release it will break if you do not migrate. For example, <code>event.preventDefault()</code> will not prevent the default action since the action will be asynchronous by default. As such, please make sure to resolve any deprecation warnings you see.</p>
<p>This <em>correct</em> (<imgsrc="" alt="â " class="wp-smiley" style="height: 1em; max-height: 1em;">) code example illustrates how to use <code>withSyncEvent()</code>:</p>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: jscript; title: ; notranslate">
import { store, withSyncEvent } from '@wordpress/interactivity';

store( 'myPlugin', {
	actions: {
		// `event.preventDefault()` requires synchronous event access.
		preventNavigation: withSyncEvent( ( event ) => {
			event.preventDefault();
		} ),

		// `event.target` does not require synchronous event access.
		logTarget: ( event ) => {
			console.log( 'event target => ', event.target );
		},

		// Not using `event` at all does not require synchronous event access.
		logSomething: () => {
			console.log( 'something' );
		},
	},
} );
</pre>
</div>
<p>This <em>bad</em> (<imgsrc="" alt="â" class="wp-smiley" style="height: 1em; max-height: 1em;">) example will, going forward, emit a deprecation warning:</p>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: jscript; title: ; notranslate">
import { store } from '@wordpress/interactivity';

store( 'myPlugin', {
	actions: {
		// Missing `withSyncEvent()` around synchronous event access.
		preventNavigation: ( event ) => {
			event.preventDefault();
		},
	},
} );
</pre>
</div>
<h3 class="wp-block-heading">Do not use actions to determine HTML attribute values</h3>
<p>If you have been relying on Interactivity API store functions (like <code>actions</code> or <code>callbacks</code>) to determine HTML attribute values (e.g. via <code>data-wp-bind--attr</code>), please revise these attributes now. Instead, use <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/core-concepts/undestanding-global-state-local-context-and-derived-state/">global state, local context, or derived state</a>. And please do not combine these function calls with directive logic like the <code>!</code> operator.</p>
<p><strong>Starting in WordPress 6.8, any directive using a store function in combination with the <code>!</code> operator will emit a deprecation warning.</strong> The logic will continue to work as before for now, but in a future WordPress release it will break if you do not migrate. More broadly, if you are using store functions in directives that determine HTML attribute values, please migrate to using <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/core-concepts/undestanding-global-state-local-context-and-derived-state/">global state, local context, or derived state</a> instead. More deprecation warnings around incorrect usage of store functions are expected soon, and eventually unmigrated code is going to break.</p>
<p>Please refer to the following <em>correct</em> (<imgsrc="" alt="â " class="wp-smiley" style="height: 1em; max-height: 1em;">) code example to illustrate how to use derived state:</p>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: jscript; title: ; notranslate">
import { store } from '@wordpress/interactivity';

store( 'myPlugin', {
	state: {
		get isOpen() {
			const ctx = getContext();
			return !! ctx.open;
		},
	},
} );
</pre>
</div>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: xml; title: ; notranslate">
<div
	data-wp-interactive="myPlugin"
	data-wp-bind--hidden="!state.isOpen"
>
	Content.
</div>
</pre>
</div>
<p>This <em>bad</em> (<imgsrc="" alt="â" class="wp-smiley" style="height: 1em; max-height: 1em;">) example will, going forward, emit a deprecation warning:</p>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: jscript; title: ; notranslate">
import { store } from '@wordpress/interactivity';

store( 'myPlugin', {
	actions: {
		isOpen() {
			const ctx = getContext();
			return !! ctx.open;
		},
	},
} );
</pre>
</div>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: xml; title: ; notranslate">
<div
	data-wp-interactive="myPlugin"
	data-wp-bind--hidden="!actions.isOpen"
>
	Content.
</div>
</pre>
</div>
<p>To provide context on why this new requirement is relevant: Using store functions for anything other than the “on”, “init”, or “watch” groups of directives has always been an anti-pattern. It is now being more formally discouraged, and will in the future be made impossible.</p>
<h2 class="wp-block-heading">Support for the <code>.length</code> property in directives</h2>
<p>An additional Interactivity API enhancement in WordPress 6.8 is support for the <code>.length</code> property on strings and numeric arrays in directives, ensuring consistency between server and client rendering.</p>
<p>Previously, the <code>.length</code> property was unavailable on the server, requiring workarounds. This update allows developers to use <code>.length</code> within all directives that reference <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/core-concepts/undestanding-global-state-local-context-and-derived-state/">global state, local context, or derived state</a>, aligning behavior across environments.</p>
<p>This code example illustrates using the <code>.length</code> property:</p>
<div class="wp-block-syntaxhighlighter-code ">
<pre class="brush: jscript; title: ; notranslate">
<div data-wp-interactive="example">
 <div data-wp-bind--hidden="!state.list.length">
 <input type="range" min="1" data-wp-bind--max="state.list.length">
 </div>
 <div data-wp-bind--hidden="!state.string.length">
 <h1 data-wp-text="state.string"></h1>
 </div>
</div>
</pre>
</div>
<p>This improvement streamlines logic and improves developer experience.</p>
<h2 class="wp-block-heading">Summary and further reading</h2>
<p>Please refer to the following links for further reading:</p>
<ul class="wp-block-list">
<li>Gutenberg pull request <a href="https://github.com/WordPress/gutenberg/pull/68097">#68097</a> for the <code>withSyncEvent</code> and new directive requirement enhancements</li>
<li>Gutenberg issues <a href="https://github.com/WordPress/gutenberg/issues/64944">#64944</a> and <a href="https://github.com/WordPress/gutenberg/issues/69552">#69552</a> with additional context on the long-term plans to run Interactivity API actions asynchronously by default.</li>
<li>Gutenberg issue <a href="https://github.com/WordPress/gutenberg/issues/69269">#69269</a> with additional context on the long-term plans to more clearly separate directives that <em>do</em> something vs that determine a <em>value</em>.</li>
<li>Trac ticket <a href="https://core.trac.wordpress.org/ticket/62582">#62582</a> for support of the <code>.length</code> property.</li>
<li>Documentation for understanding <a href="https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/core-concepts/undestanding-global-state-local-context-and-derived-state/">global state, local context, or derived state</a>.</li>
</ul>
<p class="has-text-align-right"><em>Co-authored by <a href="https://profiles.wordpress.org/gziolo/" class="mention"><span class="mentions-prefix">@</span>gziolo</a>.</em><br /><em>Props to <a href="https://profiles.wordpress.org/westonruter/" class="mention"><span class="mentions-prefix">@</span>westonruter</a>, <a href="https://profiles.wordpress.org/jonsurrell/" class="mention"><span class="mentions-prefix">@</span>jonsurrell</a>, <a href="https://profiles.wordpress.org/webcommsat/" class="mention"><span class="mentions-prefix">@</span>webcommsat</a>, <a href="https://profiles.wordpress.org/marybaum/" class="mention"><span class="mentions-prefix">@</span>marybaum</a> for review and proofreading.</em></p>
<p class="o2-appended-tags"><a href="https://make.wordpress.org/core/tag/6-8/" class="tag"><span class="tag-prefix">#</span>6-8</a>, <a href="https://make.wordpress.org/core/tag/dev-notes/" class="tag"><span class="tag-prefix">#</span>dev-notes</a>, <a href="https://make.wordpress.org/core/tag/dev-notes-6-8/" class="tag"><span class="tag-prefix">#</span>dev-notes-6-8</a>, <a href="https://make.wordpress.org/core/tag/interactivity-api/" class="tag"><span class="tag-prefix">#</span>interactivity-api</a>, <a href="https://make.wordpress.org/core/tag/performance/" class="tag"><span class="tag-prefix">#</span>performance</a></p>
</div>

Cloudways is bringing back its free Prepathon online event next week, from September 30 to…
Fueled has confirmed layoffs this week, cutting 4–5% of its workforce. But the news reached…
After calling for “more weirdness” in WordPress theme design earlier this year, Nick Hamze has…
FAIR has reached its first major milestone with the release of version 1.0 this week,…
The full chat log is available beginning here on Slack. WordPress Performance Trac tickets @westonruter…
Back in 2011, Jon Penland was selling centrifugal pumping units into the water and wastewater…