在WordPress里搞自定义区块,想从外部API拉数据展示,比如足球排名,还得让内容编辑能自由切换国家、联赛和赛季,这需求听着就头大。别慌,WordPress自带的区块编辑器控制面板(就是右侧那个能调样式、改颜色的侧边栏)完全能安排得明明白白。这次就来盘一盘,怎么给自定义区块加上一套筛选控件,让API数据听话地按需刷新。
加载国家数据
动手之前得先弄到可选的国家名单。外部API(比如RapidAPI的足球数据接口)有专门返回国家列表的端点。思路很简单:当区块被插入到文章或页面里时,自动去抓一遍国家数据,存到组件的状态里。这活儿可以用React的useState配合useEffect来干。
// edit.js 核心片段
import { useState, useEffect } from '@wordpress/element';
const [countriesData, setCountriesData] = useState(null);
useEffect(() => {
const fetchCountries = {
method: "GET",
headers: {
"X-RapidAPI-Key": "你自己的密钥",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
},
};
fetch("https://api-football-v1.p.rapidapi.com/v3/countries", fetchCountries)
.then(res => res.json())
.then(data => {
let rawList = { ...data };
console.log("国家清单", rawList.response);
setCountriesData(rawList.response);
})
.catch(err => console.error(err));
}, []);这里有个小坑:API密钥千万别写死在代码里提交到仓库,得用WordPress的wp_add_inline_script或者环境变量注入。另外,useEffect的依赖数组是空的,意味着只在区块首次加载时执行一次。如果觉得每次编辑页面都请求太频繁,可以考虑把结果缓存到浏览器的localStorage里,设置个过期时间。
搭建设置面板
国家数据到位后,就要把控件塞到右侧的设置面板里。WordPress的@wordpress/block-editor包提供了InspectorControls组件,它就像一块画布,专门承接各种设置控件。在edit函数中这样用:
import { InspectorControls } from "@wordpress/block-editor";
// 在Edit组件内部
<InspectorControls>
{ countriesData && (
<CustomLeagueControls
props={props}
countryList={countriesData}
setExternalData={setExternalData}
/>
)}
</InspectorControls>InspectorControls本质上是一个插槽(slot),它的子组件会被渲染到右侧设置栏。用条件渲染{countriesData && ...}确保只有数据加载完成后才显示控件,避免界面闪白。这里把复杂的控件逻辑抽成了一个独立组件CustomLeagueControls,这样edit.js就不会变成几百行的庞然大物。
组合框选择
国家列表少说也有上百项,普通的下拉框翻起来费劲。ComboboxControl组件是更优解——它带搜索输入框,可以一边打字一边筛选项。先得把API返回的国家数组转成它认的格式:
let formattedCountryOptions = countriesList.map(country => ({
label: country.name,
value: country.name,
}));然后在组件里渲染:
import { ComboboxControl, PanelBody } from "@wordpress/block-editor";
<PanelBody title="数据筛选" initialOpen={false}>
<ComboboxControl
label="选择国家"
value={selectedCountry}
options={filteredCountryOps}
onChange={val => handleCountryChange(val)}
onInputChange={inputVal => {
setFilteredCountryOps(
formattedCountryOptions.filter(opt =>
opt.label.toLowerCase().startsWith(inputVal.toLowerCase())
)
);
}}
/>
</PanelBody>PanelBody相当于一个可折叠的面板区域,initialOpen={false}让它默认收起,保持界面整洁。onInputChange每敲一个键就重新过滤一次选项列表,实现实时搜索的效果。注意startsWith是前缀匹配,如果想做模糊匹配可以换成includes,但性能稍差。
联动筛选
选了国家之后,联赛列表得跟着变——这叫做联动。handleCountryChange函数里要干三件事:更新国家状态、请求该国家下的联赛、把返回的联赛数据转成下拉选项。
function handleCountryChange(countryName) {
setSelectedCountry(countryName);
const leagueRequest = {
method: "GET",
headers: { "X-RapidAPI-Key": "你的key", "X-RapidAPI-Host": "api-football-v1.p.rapidapi.com" }
};
fetch(`https://api-football-v1.p.rapidapi.com/v3/leagues?country=${countryName}`, leagueRequest)
.then(res => res.json())
.then(data => {
const leaguesRaw = data.response;
setLeaguesList(leaguesRaw);
let leagueOpts = leaguesRaw.map(item => ({
label: item.league.name,
value: item.league.name,
}));
setFilteredLeagueOpts(leagueOpts);
})
.catch(err => console.error(err));
}这里有个细节:联赛数据里还嵌套了赛季数组(seasons),所以在handleLeagueChange里需要额外提取出当前选中联赛的ID和可用赛季列表。代码逻辑类似,就不再重复贴了。需要留意的是,有些联赛(比如某些杯赛)可能没有标准的积分榜数据,或者积分榜是分组的(像世界杯小组赛)。真实项目里要针对这些边缘情况做兜底处理——比如弹个提示“该联赛暂无排名数据”。
提交数据按钮
当国家、联赛、赛季三个选项都选好之后,才显示“拉取数据”按钮。这个按钮的展示条件可以写成:
{ selectedSeason && (
<button className="fetch-rankings" onClick={fetchRankingsData}>
获取排名
</button>
)}点击按钮时调用fetchRankingsData,它把当前选中的联赛ID和赛季参数拼接到API请求里,拿到排名数据后通过setExternalData传回父组件,最终渲染成表格。整个过程就像搭积木:右侧面板负责收集筛选条件,点击按钮后触发请求,表格区域重新渲染。
下面是最终在编辑器里呈现的效果——右侧面板的三个组合框丝滑联动,选完赛季点按钮,左边区块的排名表瞬间刷新。
| 组件 | 作用 | 常见坑点 |
|---|---|---|
| ComboboxControl | 带搜索的下拉框 | 选项数据格式必须是{label,value} |
| PanelBody | 可折叠面板容器 | 记得设置initialOpen避免一直展开 |
| InspectorControls | 挂载到右侧设置栏 | 只能用在Edit函数内 |
这波操作下来,一个能动态筛选外部API数据的WordPress区块就基本成型了。不过还有个遗留问题:刷新页面或者保存文章后,刚才选的那些国家、联赛、赛季全都归零了。这是因为筛选设置还没有存到数据库里。下回就专门来搞定数据持久化,让选好的配置怎么刷新都不丢。
