为啥WordPress块编辑器看不到API数据预览,咋整?

2,577字
11–16 分钟
in

搞过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数据库读取

最后贴个完整流程:新建块插件 → 注册块时指定editsave函数 → Edit里用useState加按钮拉API → 调用setAttributes存数据 → Save里直接读attributes.data渲染 → 样式写一份SCSS → 编译后测试。如果报错说块内容不一致,删了重插就行。这法子比上次那个只能前端看的爽多了,编辑页面就能实时刷新数据,妥妥的生产力提升。