摘要
咱今儿聊点实在的,WordPress自带那个块编辑器(Gutenberg)里头,光弄个静态内容太没劲了。要是能从外面那些数据接口(API)直接拉点实时信息,比如足球排名、股票价格啥的,那才叫带劲。这篇手把手教大家怎么鼓捣一个自定义块,利用API拿数据,存进数据库,最后在前端页面给整得明明白白。整个过程不用慌,跟着敲代码就完事了。
啥是动态块和外部API
WordPress里头的“块”就是编辑页面时拖来拖去那些小零件,比如段落、图片。普通块存进数据库的是固定内容,换个说法叫静态渲染。动态块就牛了,每次有人打开页面,它都能重新从别处抓最新数据来显示,比如从足球数据网站拉个实时积分榜。
外部API就好比饭店的窗口,这边喊一嗓子“来份英超排名”,那边就把做好的数据(通常是JSON格式)递出来。配合fetch这个工具,WordPress块就能跟外面世界唠上嗑。
用脚手架搭块儿地基
开整之前得先有个干活的环境。推荐用官方那个@wordpress/create-block包,跟装修队似的,唰一下就把项目架子搭好了。
在命令行敲这串:
npx @wordpress/create-block football-rankings这命令会生出一个叫football-rankings的文件夹,里边已经是一个能直接用的WordPress插件。完事把这个文件夹整个挪到本地网站的wp-content/plugins目录下头,然后去后台“插件”页面点一下“启用”。
这时候新建一篇文章,编辑器里已经能看到“Football Rankings”这个块了。不过现在它还是个空壳子,接下来给它加点真功夫。
从API抓数据的正确姿势
想拿到外部数据,得在edit.js文件里动刀。这个文件管的是编辑器里块长啥样。用useEffect钩子包住请求代码,保证页面加载时只请求一次,免得编辑器每刷新一下就狂轰滥炸API。
打开src/edit.js,先引入useEffect:
import { useEffect } from "@wordpress/element";然后在Edit函数里塞进去这段:
useEffect(() => {
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key": "你的密钥",
"X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
},
};
fetch("https://api-football-v1.p.rapidapi.com/v3/standings?season=2021&league=39", options)
.then( ( response ) => response.json() )
.then( ( response ) => {
let newData = { ...response };
setAttributes( { data: newData } );
console.log( "属性里存的数据", attributes );
})
.catch((err) => console.error(err));
}, []);这里有个坑:API密钥得自己去RapidAPI申请,免费的够折腾了。还有那个setAttributes是拿来把拿到的数据存进块的“属性”里,就像给块安了个小书包。
让WordPress记住抓来的数据
数据拿下来了,不存好等于白干。块得有地方放这些宝贝,那就是attributes。在index.js里头注册块的时候得声明一下:
registerBlockType( metadata.name, {
edit: Edit,
attributes: {
data: {
type: "object",
},
},
save,
} );指定type为object特别要紧,因为API返回的是JSON对象。要是写错了类型,WordPress一声不吭就把数据扔了,连个错都不报,那才叫欲哭无泪。存好之后去数据库的wp_posts表里post_content字段翻翻,能看到一串JSON字符串,证明数据已经落袋为安了。
前端页面把数据摆上桌
后端存储搞掂了,该让网站访客也瞅瞅这些排名了。这需要在前端把数据从数据库拽出来,再画成好看的表格。
先在src目录下新建两个文件:frontend.js和frontend.scss(SCSS编译后变CSS)。然后在package.json的scripts里改一下构建命令:
"scripts": {
"build": "wp-scripts build src/index.js src/frontend.js",
"start": "wp-scripts start src/index.js src/frontend.js"
}接着在football-rankings.php里注册一个渲染回调:
function create_block_football_rankings_block_init() {
register_block_type( __DIR__ . '/build', array(
'render_callback' => 'render_frontend'
));
}
add_action( 'init', 'create_block_football_rankings_block_init' );
function render_frontend($attributes) {
if( !is_admin() ) {
wp_enqueue_script( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.js');
wp_enqueue_style( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.css' );
}
ob_start(); ?>
<div class="football-rankings-frontend" id="league-standings">
<div class="data" style="display:none;">
<pre><?php echo wp_json_encode( $attributes ); ?></pre>
</div>
<div class="header">
<div class="position">排名</div>
<div class="team-logo">队徽</div>
<div class="team-name">队名</div>
<div class="stats">
<div class="games-played">场次</div>
<div class="games-won">胜</div>
<div class="games-drawn">平</div>
<div class="games-lost">负</div>
<div class="goals-for">进球</div>
<div class="goals-against">失球</div>
<div class="points">积分</div>
</div>
<div class="form-history">近5场</div>
</div>
<div class="league-table"></div>
</div>
<?php return ob_get_clean();
}注意那个隐藏的<div class="data">,它把属性里的JSON数据塞进HTML,方便前端JS去读。这种土法子虽然不优雅,但胜在简单粗暴,新手一看就懂。
用JavaScript把JSON变表格
最后一步,在frontend.js里写逻辑,把隐藏的JSON数据解析出来,动态生成每一行的排名信息。
import "./frontend.scss";
window.addEventListener( "load", () => {
const dataPre = document.querySelector( ".data pre" );
if ( !dataPre ) return;
const dataEl = dataPre.innerHTML;
const tableEl = document.querySelector( ".league-table" );
const headerEl = document.querySelector( "#league-standings .header" );
const dataJSON = JSON.parse( dataEl );
console.log( "前端拿到数据", dataJSON );
let teams = dataJSON.data.response[0].league.standings[0];
let leagueLogo = dataJSON.data.response[0].league.logo;
headerEl.style.backgroundImage = `url(${leagueLogo})`;
teams.forEach( ( team, idx ) => {
const teamDiv = document.createElement("div");
const { played, win, draw, lose, goals } = team.all;
teamDiv.classList.add("team");
teamDiv.innerHTML = `
<div class="position">${ idx + 1 }</div>
<div class="team-logo"><img src="${ team.team.logo }" /></div>
<div class="team-name">${ team.team.name }</div>
<div class="stats">
<div class="games-played">${ played }</div>
<div class="games-won">${ win }</div>
<div class="games-drawn">${ draw }</div>
<div class="games-lost">${ lose }</div>
<div class="goals-for">${ goals.for }</div>
<div class="goals-against">${ goals.against }</div>
<div class="points">${ team.points }</div>
</div>
<div class="form-history"></div>
`;
// 处理近五场战绩,把字符串"WWLDW"拆成一个个字母
const formArray = team.form.split("");
formArray.forEach( result => {
const resultSpan = document.createElement("div");
resultSpan.classList.add("result");
resultSpan.innerText = result;
if ( result === "W" ) resultSpan.classList.add("win");
else if ( result === "D" ) resultSpan.classList.add("draw");
else resultSpan.classList.add("lost");
teamDiv.querySelector(".form-history").appendChild(resultSpan);
});
tableEl.appendChild(teamDiv);
});
});这里把“W”代表赢、“D”代表平、“L”代表输分别配上不同样式,整得红红绿绿的,一眼就能看出球队最近状态咋样。运行npm run build打包一下,刷新页面,一个活生生的足球排名块就出来了。
| 步骤 | 关键动作 | 常见翻车点 |
|---|---|---|
| 搭架 | 跑create-block命令 | Node版本太低会报错 |
| 抓数 | useEffect里写fetch | 忘记传空数组导致死循环 |
| 存数 | 定义attributes类型为对象 | 类型写错数据就没了 |
| 显示 | 写render_callback | 忘记清空输出缓冲 |
| 渲染 | 前端解析JSON生成DOM | 数据路径不对取不到response[0] |
搞定收工,这个套路不光能搞足球排名,换成天气、股票、段子啥的都一样玩得转。
