搞过WordPress动态块的老铁都懂,上次整了个从外部接口拉数据在前端渲染的玩法,结果块编辑器里一片空白,只能发布后才能看到效果。这波属实有点懵,编辑页面的时候心里没底,不知道数据长啥样。其实问题出在Edit函数和Save函数的配合上,这次手把手教怎么让后端编辑器也实时显示API拉来的数据,顺便带个刷新按钮,舒服得很。
核心概念
先唠唠两个关键函数。Edit函数负责块编辑器里看到的内容,可以塞进各种React交互组件,比如按钮、列表、加载动画。Save函数负责前端页面显示的内容,只能返回静态HTML,不能放React钩子,最终这块HTML会存进数据库。上次用的render_callback方法虽然能在PHP里动态渲染,但编辑器预览就别想了。这次纯靠JSX和@wordpress/element里的useState,让前后端数据打通。
打个比方,Edit函数就像厨房里的试菜员,炒菜过程中就能尝味道;Save函数是端上桌的成品,不能中途加调料。上次那个足球排名插件,前端能看到表格,编辑器里啥也没有,就是因为只在Save函数里干活,没把数据喂给Edit函数。
改造Edit函数
先把上次football-rankings.php里的HTML代码搬到JavaScript里。注意别再用render_callback那套,直接操作edit函数的props对象。props里有两个宝贝:attributes对象和setAttributes函数。attributes用来存数据,setAttributes负责把数据写进数据库。props本身只读,不能直接改,得通过setAttributes存进去。
从@wordpress/element引入useState,别从React原生库拿,否则每个块都得单独下载React,用@wordpress/element是走WordPress封装的单例,性能更香。代码这么写:
import { useState } from '@wordpress/element';
export default function Edit({ attributes, setAttributes }) {
const [apiData, setApiData] = useState(attributes.data || null);
const fetchData = async () => {
const response = await fetch('https://api-football-standings.xxx/rankings');
const result = await response.json();
setApiData(result.data);
setAttributes({ data: result.data });
};
return (
<div>
<button onClick={fetchData}>戳我拉数据</button>
{apiData && (
<table>
<tbody>
{apiData.map(team => (
<tr key={team.id}>
<td>{team.rank}</td>
<td>{team.name}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
}这里有个坑:如果attributes.data一开始是空,表格就不显示。点一下按钮触发fetchData,拿到数据后同时更新apiData(本地状态)和setAttributes(存进数据库)。页面保存后刷新,useState(attributes.data)会从数据库里把上次的数据捞出来当初始值,表格又回来了。但注意,如果没点按钮就保存,数据库里啥也没有,刷新后表格就没了。解决方案是把fetchData放到useEffect里自动执行一次,不过为了演示手动刷新效果,这里用按钮触发更直观。
改造Save函数
前端显示不需要按钮,直接判断attributes.data有没有值,有就渲染表格,没有就返回空。Save函数里不能用useState,只能返回静态JSX。代码长这样:
export default function Save({ attributes }) {
const { data } = attributes;
if (!data) return null;
return (
<table>
<tbody>
{data.map(team => (
<tr key={team.id}>
<td>{team.rank}</td>
<td>{team.name}</td>
</tr>
))}
</tbody>
</table>
);
}如果在已经插入块的情况下修改Save函数,编辑器会报错,因为之前保存的HTML结构和新的不一样。解决办法很简单:删掉当前页面里的旧块,重新从侧边栏拖一个新块进来。开发模式下这招最省事。要是用render_callback方法就不会有这种同步问题,但那玩意儿又没法在编辑器里实时预览,各有各的香。
样式双端同步
样式文件写一份,同时覆盖编辑器和前端。在src/style.scss里定义:
.wp-block-football-rankings {
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
}
button {
margin-bottom: 16px;
background: #007cba;
color: white;
border: none;
padding: 6px 12px;
cursor: pointer;
}
}构建后会自动编译成CSS。编辑器里点按钮拉数据,表格样式和前端完全一致。这波操作下来,再也不用盲写块了,数据长啥样一目了然。
| 函数 | 作用位置 | 可用技术 | 数据存储 |
|---|---|---|---|
| Edit | 块编辑器 | React组件 | setAttributes |
| Save | 前端页面 | 静态HTML | 数据库读取 |
最后贴个完整流程:新建块插件 → 注册块时指定edit和save函数 → Edit里用useState加按钮拉API → 调用setAttributes存数据 → Save里直接读attributes.data渲染 → 样式写一份SCSS → 编译后测试。如果报错说块内容不一致,删了重插就行。这法子比上次那个只能前端看的爽多了,编辑页面就能实时刷新数据,妥妥的生产力提升。
