这里有一些关于在 CSS-Tricks 上使用 WordPress 块的新教程。其中一个是 WordPress 块开发的介绍,它是学习什么是块并在 WordPress 中注册它们以在页面和帖子中使用的良好地方。
虽然该帖子很好地涵盖了块的基础知识,但我希望更进一步。 你会看到,在那篇文章中,我们了解了在后端 WordPress 块编辑器中渲染块与在前端主题中渲染块之间的区别。 例子是一个简单的引用块,它在每端渲染不同的内容和样式。
让我们更进一步,看看如何在 WordPress 块中使用动态内容。 更具体地说,让我们从外部 API 获取数据并在将特定块放入块编辑器时将其渲染到前端。
这是我想要涵盖所有在自定义 WordPress 块中使用外部 API 数据的要点的一个更大系列的一部分。
在 WordPress 块中使用外部 API
- 在前端渲染数据 (您就在这里!)
- 在后端渲染数据
- 创建自定义设置 UI
- 保存自定义块设置
- 使用实时 API 数据 (即将推出)
我们将构建一个块来输出显示从 Api-Football 中提取的足球(即足球)排名的数据。

将 API 与 WordPress 块集成有多种方法! 由于有关块基础知识的文章已经介绍了从头开始创建块的过程,因此我们将使用@wordpress/create-block
包来简化我们的工作并构建我们的项目。
初始化我们的块插件
首先:让我们从命令行启动一个新项目
npx @wordpress/create-block football-rankings
我通常会通过从头开始制作文件来启动这样的项目,但感谢 WordPress 核心团队为我们提供了这个方便的实用程序!
命令创建项目文件夹后,我们实际上已经注册了一个功能齐全的 WordPress 块作为插件。 因此,让我们将项目文件夹放到您安装了 WordPress 的wp-content/plugins
目录中(最好是在本地环境中工作),然后登录 WordPress 管理员并从插件屏幕中激活它。

现在我们的块已初始化、安装并激活,请打开/wp-content/plugins/football-rankings
中的项目文件夹。 您还需要从命令行cd
到那里,以确保我们可以继续开发。
目前我们只需要关注这些文件
edit.js
index.js
football-rankings.php
项目中的其他文件当然很重要,但在此时并非必需的。
查看 API 源代码
我们已经知道我们将使用由 RapidAPI 提供的 Api-Football。 幸运的是,RapidAPI 具有一个仪表板,可以自动生成我们用来获取 2021 年英超联赛积分榜的 API 数据所需的脚本。

如果您想查看 JSON 结构,可以使用 JSONCrack 生成可视化表示。
edit.js
文件中获取数据
从我将把 RapidAPI 代码包装在一个带空依赖项数组的 React useEffect()
钩子 中,这样它只会在页面加载时运行一次。 通过这种方式,我们阻止 WordPress 每次块编辑器重新渲染时调用 API。 如果您有兴趣,可以使用 wp.data.subscribe()
进行检查。
这是我在其中导入useEffect()
,然后将其包装在 RapidAPI 提供的fetch()
代码周围的代码
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/
import { useEffect } from "@wordpress/element";
export default function Edit(props) {
const { attributes, setAttributes } = props;
useEffect(() => {
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key": "Your Rapid API 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", attributes );
})
.catch((err) => console.error(err));
}, []);
return (
<p { ...useBlockProps() }>
{ __( "Standings loaded on the front end", "external-api-gutenberg" ) }
</p>
);
}
请注意,我已经将return
函数保持原样,但包含了一条确认足球积分榜在前端渲染的注释。 同样,我们只关注本文中的前端——我们也可以在块编辑器中渲染数据,但为了保持重点,我们将把它留到另一篇文章中。
将 API 数据存储在 WordPress 中
现在我们已经获取数据,我们需要将其存储在 WordPress 中的某个地方。 这就是 attributes.data
对象派上用场的地方。 我们将data.type
定义为object
,因为数据以 JSON 格式获取并格式化。 确保您没有其他类型,否则 WordPress 不会保存数据,也不会抛出任何错误供您调试。
我们在index.js
文件中定义了所有这些内容
registerBlockType( metadata.name, {
edit: Edit,
attributes: {
data: {
type: "object",
},
},
save,
} );
好的,所以 WordPress 现在知道我们正在获取的 RapidAPI 数据是一个对象。 如果我们在 WordPress 块编辑器中打开一个新的帖子草稿并保存该帖子,该数据现在将存储在数据库中。 事实上,如果我们可以看到它,我们可以看到它在wp_posts.post_content
字段中,如果我们在 phpMyAdmin、Sequel Pro、Adminer 或您使用的任何工具中打开网站的数据库。

在前端输出 JSON 数据
在前端输出数据有多种方法。 我将向您展示的方法将存储在数据库中的属性作为参数传递给football-rankings.php
文件中的render_callback
函数。
我喜欢保持关注点分离,所以我的做法是在块插件的build
文件夹中添加两个新文件:frontend.js
和frontend.css
(您可以在src
目录中创建一个frontend.scss
文件,该文件编译为build
目录中的 CSS)。 这样,后端和前端代码就分离了,football-rankings.php
文件也更容易阅读。
回顾一下 WordPress 块开发的介绍,有editor.css
和style.css
文件分别用于后端和前端和后端的共享样式。 通过添加frontend.scss
(它编译为frontend.css
,我可以隔离仅用于前端的样式。
在我们担心这些新文件之前,以下是如何在football-rankings.php
中调用它们
/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
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' ); // HIGHLIGHT 15,16,17,18
}
ob_start(); ?>
<div class="football-rankings-frontend" id="league-standings">
<div class="data">
<pre>
<?php echo wp_json_encode( $attributes ) ?>
</pre>
</div>
<div class="header">
<div class="position">Rank</div>
<div class="team-logo">Logo</div>
<div class="team-name">Team name</div>
<div class="stats">
<div class="games-played">GP</div>
<div class="games-won">GW</div>
<div class="games-drawn">GD</div>
<div class="games-lost">GL</div>
<div class="goals-for">GF</div>
<div class="goals-against">GA</div>
<div class="points">Pts</div>
</div>
<div class="form-history">Last 5 games</div>
</div>
<div class="league-table"></div>
</div>
<?php return ob_get_clean();
}
由于我正在使用render_callback()
方法来处理属性,因此我将像 块编辑器手册建议的那样手动处理排队。 这包含在!is_admin()
条件中,并且正在排队这两个文件,这样我们就可以避免在使用编辑器屏幕时排队它们。
现在我们有这两个新文件要调用,我们需要确保告诉npm
编译它们。 因此,请在package.json
中的scripts
部分中执行此操作
"scripts": {
"build": "wp-scripts build src/index.js src/frontend.js",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update",
"plugin-zip": "wp-scripts plugin-zip",
"start": "wp-scripts start src/index.js src/frontend.js"
},
另一种包含文件的方法是在我们block.json
文件中的块元数据中定义它们,如块开发简介中所述
"viewScript": [ "file:./frontend.js", "example-shared-view-script" ],
"style": [ "file:./frontend.css", "example-shared-style" ],
我之所以选择package.json
方法,是因为我正在使用render_callback()
方法。
渲染 JSON 数据
在渲染部分,我只关注一个区块。一般来说,你可能希望在前端针对多个区块。在这种情况下,你需要使用 `document.querySelectorAll()`,并带上区块的特定 ID。
我基本上是要等待窗口加载,然后从 JSON 中获取一些关键对象的數據,并将它们应用到一些标记,以便在前端渲染它们。我还会将 `attributes` 数据转换为 JSON 对象,以便更容易地在 JavaScript 中读取,并通过 JSON 设置 HTML 的详细信息,例如足球联赛徽标、球队徽标和统计数据。
“最近 5 场比赛”列显示了球队最近五场比赛的结果。由于 API 数据是字符串格式,我必须手动修改数据。将其转换为数组可以帮助在 HTML 中将其用作球队最近五场比赛中每一场比赛的独立元素。
import "./frontend.scss";
// Wait for the window to load
window.addEventListener( "load", () => {
// The code output
const dataEl = document.querySelector( ".data pre" ).innerHTML;
// The parent rankings element
const tableEl = document.querySelector( ".league-table" );
// The table headers
const tableHeaderEl = document.querySelector( "#league-standings .header" );
// Parse JSON for the code output
const dataJSON = JSON.parse( dataEl );
// Print a little note in the console
console.log( "Data from the front end", dataJSON );
// All the teams
let teams = dataJSON.data.response[ 0 ].league.standings[ 0 ];
// The league logo
let leagueLogoURL = dataJSON.data.response[ 0 ].league.logo;
// Apply the league logo as a background image inline style
tableHeaderEl.style.backgroundImage = `url( ${ leagueLogoURL } )`;
// Loop through the teams
teams.forEach( ( team, index ) => {
// Make a div for each team
const teamDiv = document.createElement( "div" );
// Set up the columns for match results
const { played, win, draw, lose, goals } = team.all;
// Add a class to the parent rankings element
teamDiv.classList.add( "team" );
// Insert the following markup and data in the parent element
teamDiv.innerHTML = `
<div class="position">
${ index + 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>
`;
// Stringify the last five match results for a team
const form = team.form.split( "" );
// Loop through the match results
form.forEach( ( result ) => {
// Make a div for each result
const resultEl = document.createElement( "div" );
// Add a class to the div
resultEl.classList.add( "result" );
// Evaluate the results
resultEl.innerText = result;
// If the result a win
if ( result === "W" ) {
resultEl.classList.add( "win" );
// If the result is a draw
} else if ( result === "D" ) {
resultEl.classList.add( "draw" );
// If the result is a loss
} else {
resultEl.classList.add( "lost" );
}
// Append the results to the column
teamDiv.querySelector( ".form-history" ).append( resultEl );
});
tableEl.append( teamDiv );
});
});
至于样式,你可以随意设置!如果你需要一些东西来使用,我有一套完整的样式,你可以用作起点。
我使用 SCSS 进行了样式设置,因为 `@wordpress/create-block` 包默认支持它。在命令行中运行 `npm run start` 以监控 SCSS 文件并在保存时将其编译为 CSS。或者,你可以在每次保存时使用 `npm run build` 来编译 SCSS 并构建插件包的其余部分。
查看 SCSS
body {
background: linear-gradient(to right, #8f94fb, #4e54c8);
}
.data pre {
display: none;
}
.header {
display: grid;
gap: 1em;
padding: 10px;
grid-template-columns: 1fr 1fr 3fr 4fr 3fr;
align-items: center;
color: white;
font-size: 16px;
font-weight: 600;
background-repeat: no-repeat;
background-size: contain;
background-position: right;
}
.frontend#league-standings {
width: 900px;
margin: 60px 0;
max-width: unset;
font-size: 16px;
.header {
.stats {
display: flex;
gap: 15px;
& > div {
width: 30px;
}
}
}
}
.league-table {
background: white;
box-shadow:
rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
padding: 1em;
.position {
width: 20px;
}
.team {
display: grid;
gap: 1em;
padding: 10px 0;
grid-template-columns: 1fr 1fr 3fr 4fr 3fr;
align-items: center;
}
.team:not(:last-child) {
border-bottom: 1px solid lightgray;
}
.team-logo img {
width: 30px;
}
.stats {
display: flex;
gap: 15px;
}
.stats > div {
width: 30px;
text-align: center;
}
.form-history {
display: flex;
gap: 5px;
}
.form-history > div {
width: 25px;
height: 25px;
text-align: center;
border-radius: 3px;
font-size: 15px;
}
.form-history .win {
background: #347d39;
color: white;
}
.form-history .draw {
background: gray;
color: white;
}
.form-history .lost {
background: lightcoral;
color: white;
}
}
这是演示!
看看吧 - 我们刚制作了一个区块插件,它可以从 API 获取数据并在 WordPress 网站的前端渲染它。
我们找到一个 API,使用 `fetch()` 从中获取数据,将其保存到 WordPress 数据库,解析它,并将其应用到一些 HTML 标记以在前端显示。一个教程就做到这些,还不错吧?
同样,我们可以做同样的事情,以便排名在区块编辑器中以及主题的前端进行渲染。但希望将重点放在前端可以让你了解在 WordPress 区块中如何获取数据,以及如何构建和渲染数据以供显示。
不幸的是,这个区块/教程有点用处不大... API 数据只在区块在后端渲染时才会被获取,所以你在前端看到的数据很快就会过时。你需要在区块的 `edit` 函数中获取数据以向管理员展示数据,但更重要的是,你需要在服务器端渲染 (render_callback) 中重新提交 API 请求,以便数据保持最新。
嗨 Brennan! 我同意你的观点。这是一系列文章:即将发布的文章正在草稿阶段。后续文章将重点关注实时数据,而不仅仅是历史数据。我们无法在一篇文章中容纳所有内容。再次感谢你注意到这一点并提醒用户! :)
你使用 DOM 和 createDocument 节点的那一刻,我就迷茫了。为什么你想要使用这么底层的 API,而你可以使用 React 呢?
这只是个人喜好 :) 没有人阻止你使用其中任何一个。
感谢 Manoj 的信息丰富且有用的文章。
<div class=”football-rankings-frontend” id=”league-standings”>
如果你看到错位,请在 football-rankings.php 中进行修正
<div class=”frontend” id=”league-standings”>
感谢这个有用的教程!我有一个问题:`render_frontend` 函数如何知道它的参数 `$attributes` 就是我们在 `edit.js` 中设置的属性?
谢谢!
这是 WordPress 核心完成的工作。现在不需要深入研究它 :)