Interactivity API 是 WordPress 6.5 起内置的官方前端交互方案:在区块渲染出的 HTML 上写 data-wp-* 指令,再用一份 store(状态 + 动作 + 回调)驱动 DOM 更新,不需要引入 jQuery 或整套前端框架。它的真正价值不在「能做个展开收起」,而在服务端渲染的 HTML 与客户端状态共用一套标记,SEO 和无障碍天然在线,多个区块之间还能共享状态。
它解决的是什么问题
过去给区块加前端交互,常规做法是自己引 jQuery 或 React,结果是每个插件各带一套运行时,页面体积和冲突风险都上升。 Interactivity API 把这层统一掉:核心的图片灯箱、搜索、查询、导航、文件区块都已经用它实现,开发者写的自定义区块可以直接复用同一套机制,甚至跨区块通信——点「加入购物车」区块,另一个「购物车」区块自动更新。
两个核心概念:指令和 store
指令(Directives)
指令就是写在 HTML 标签上的自定义属性,统一以 data-wp- 开头。常用这几个:
| 指令 | 作用 |
|---|---|
| data-wp-interactive | 激活该元素及子元素的交互能力,并指定 store 命名空间(必需) |
| data-wp-context | 定义局部状态,值是一段 JSON,只对当前节点及子节点可见 |
| data-wp-bind | 按布尔或字符串值设置 HTML 属性,写法为 data-wp-bind--属性名 |
| data-wp-class / wp-style | 按状态增删 class 或行内样式 |
| data-wp-text | 把状态值写入元素文本内容 |
| data-wp-on | 绑定事件,写法为 data-wp-on--click |
| data-wp-watch / wp-init | 状态变化时运行回调 / 元素挂载时运行一次 |
| data-wp-each | 遍历数组渲染列表 |
一段最小可用示例(写在区块的 render.php 里):
<div data-wp-interactive="myPlugin"
data-wp-context='{ "isOpen": false }'>
<button data-wp-on--click="actions.toggle"
data-wp-bind--aria-expanded="context.isOpen">切换</button>
<p data-wp-bind--hidden="!context.isOpen">现在可见了</p>
</div>
Store(状态容器)
store 写在区块的 view.js 里,用 @wordpress/interactivity 提供的 store() 注册:
import { store, getContext } from '@wordpress/interactivity';
store( 'myPlugin', {
actions: {
toggle() {
const context = getContext();
context.isOpen = ! context.isOpen;
},
},
} );
data-wp-bind--aria-expanded 这类布尔属性要特别注意:值为 true 时属性被加上,false 时被移除;如果属性名以 aria- 或 data- 开头,布尔值会以字符串形式写入,正好符合无障碍属性的预期。
data-wp-text="state.title" 是引用 state.title,写 data-wp-text="`固定文案`" 是无效用法——需要动态计算请放到 store 的 getter 里。state 、 context 、 config 怎么分工
这三个最容易混,记住一句话:context 是局部的、 state 是全局的、 config 是不可变的。
- context(局部):跟着具体 DOM 节点走,同一区块在页面上出现三次就有三个互不相干的 context 。适合「这个折叠面板开没开」。
- state(全局):整个页面共享,适合购物车总数、筛选条件这类跨区块数据。可以用 getter 做派生状态(derived state)。
- config(静态配置):PHP 通过
wp_interactivity_config()下发,不参与响应式更新,适合放 REST 地址、 nonce 、翻译文案。
服务端对应的四个 PHP 函数也记一下:wp_interactivity_config() 下发静态配置,wp_interactivity_state() 初始化全局状态,wp_interactivity_process_directives() 手动处理指令,wp_interactivity_data_wp_context() 安全地输出 context JSON(不要自己 json_encode 拼属性,用这个函数能省掉转义坑)。
接入一个区块要改动哪些文件
- 用官方模板脚手架初始化:
npx @wordpress/create-block@latest my-block --template @wordpress/create-block-interactive-template,它会把该配的都配好。 - 在
block.json里声明"supports": { "interactivity": true },并配置"viewScriptModule": "file:./view.js"。 - 确认构建脚本带
--experimental-modules标志(wp-scripts build/start),否则 Script Module 打不出来。用官方模板生成的 package.json 已自带。 - 在
render.php的 HTML 上加data-wp-*指令,context 用wp_interactivity_data_wp_context()输出。 - 在
view.js里import { store } from '@wordpress/interactivity'并注册同名命名空间的 store 。
老项目手改 package.json 的写法
{
"scripts": {
"build": "wp-scripts build --experimental-modules",
"start": "wp-scripts start --experimental-modules"
}
}
如果不想改构建流程,也可以直接在 PHP 里 wp_enqueue_script_module() 并声明对 @wordpress/interactivity 的依赖,但维护成本更高,不建议。
进阶:无刷新导航与服务端状态
配合 @wordpress/interactivity-router,可以用 actions.navigate() 做客户端导航,页面不整体刷新而局部更新。这时服务端会在每次导航时下发新的 state 和 context,客户端用 getServerState() / getServerContext() 拿到快照。
有两个坑必须知道:
- 这两个函数返回的是深拷贝快照,改它不会影响真实状态,只能读了之后写回 state/context 。
- 监听它们的回调在每次客户端导航都会触发,不管值有没有变,回调里要自己判断是否需要更新,别写无条件的重渲染。
需要同步事件(比如 event.preventDefault())的动作,要用 withSyncEvent() 包一层生成器函数,否则异步调度下事件对象已经失效。
什么时候不该用它
- 复杂表单与大量业务状态:它就是为区块级交互设计的,没有路由、状态管理中间件,复杂应用还是该上专门的框架。
- 纯静态展示型区块:没有任何交互就没必要引入,白增一个模块请求。
- 需要兼容 WP 6.5 以下:虽然装 Gutenberg 17.5+ 也能用,但线上环境复杂时不如降级用普通 JS 。








评论 (0)