使用 React 的无头 WordPress
使用 WordPress REST API 和 Create React App 构建解耦 WordPress 网站
最近几个月,我对 WordPress REST API(以下简称 WP-API)和 React 产生了浓厚的兴趣。我一直在写 WP-API 的入门系列文章,但决定暂时放下,写一篇更完整、更详细的文章。
本文将概述如何使用 Create React App 和 WP-API 构建解耦(或“无头”)的 WordPress Web 应用程序。虽然本文主要介绍 React 的前端开发,但如果您想使用 Angular、Rx、Ember 或 Vue 等其他框架构建前端,一些通用概念仍然适用。
而且您不必止步于 Web 应用程序。您不仅可以使用 WP-API 来支持 Web 应用程序,还可以同时支持移动应用程序、游戏机应用程序等。
在开始之前,请随意克隆此演示的存储库。
为什么?
为什么选择 WordPress?
您的第一个问题可能是“我为什么要关心 WordPress 是否有 API?”我已经在另一篇文章中对此进行了一些介绍,但如果您不想再打开另一个标签页,以下是一些重点内容:
-
截至 11 月,WordPress 已为超过 27% 的网络提供支持。自几个月前发布的 4.7 版本以来,WP-API 的所有内容端点均已包含在 WordPress 核心中,这意味着数百万个新 API 已上线。
-
WordPress 超级用户友好。这或许是 WordPress 如此广泛应用的最大原因。它允许任何人,即使是非技术人员,也能创建和编辑网站。目前没有其他工具能像 WordPress 一样,拥有如此丰富的功能和支持,并带来如此强大的功能。
-
WordPress 是一个功能强大的内容管理平台。一些从未使用过 WordPress(或很久没用过)的开发者普遍存在一个误解,认为 WordPress 仅仅用于博客。虽然 WordPress 非常适合博客,但实际上,它更擅长通过自定义文章类型来有效地管理自定义内容。
为什么要创建 React App?
除非你一直生活在 Web 开发的世界里,否则你肯定听说过React。React的背景介绍超出了本文的范畴,但我还是想向你介绍Create React App,这是入门 React 最简单的方法。
React 本身入门非常简单。现在就可以将 React 和 ReactDOM 集成到你的应用程序中:
<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
但是,如果你打算在应用程序中的多个小部分使用 React,那么这个“兔子洞”的深度很快就会让你感到不知所措。想要深入学习 React,通常需要学习的东西太多了:ES6、JSX、Babel、Webpack 等等——而这些都需要投入大量的时间才能真正理解。
即使对这些主题有了深入的了解,你仍然会在大多数大型项目中花费大量时间进行配置。
但是,如果你只是想尝试一下 React 本身,该怎么办?或者,如果你想从一组默认配置开始,然后在开发过程中不断修改这些默认配置,该怎么办?
好吧,还有希望:创建 React App。
去年夏天,Facebook 发布了 Create React App,这是一款样板工具,具有一套合理的配置标准,因此您可以快速开始使用 React 本身,然后按照自己的节奏深入研究。
Create React App 与 Webpack、ESLint、Babel、Autoprefixer、Jest 以及来自社区的其他优秀工具捆绑在一起。
为什么选择 Headless WordPress?
好吧,WordPress 很棒。React 也很棒。那么我们为什么要将两者结合起来呢?
-
JavaScript 是 WordPress 的未来。2015 年末,WordPress 背后的公司 Automattic 用 JavaScript 重写了整个管理应用程序(代号“Calypso”)。几周后,Automattic 首席执行官 Matt Mullenweg 给所有 WordPress 开发者布置了一项艰巨的家庭作业:“深入学习 JavaScript。”
-
因为前后端分离对用户和开发者都有好处。更好的用户体验是可能的。维护大型代码库更高效。性能也更好。
-
您的公司可以聘请更专业的人才。前端工程师不必了解 WordPress,反之亦然。与其聘请通才的 WordPress 主题/插件开发人员,不如分别聘请对前端工程和 WordPress 都有深入了解的独立职位。
向前!
好的,既然我们已经确定了为什么这很重要,那就让我们开始吧!
我们将要构建什么
在本教程中,我们将构建一个简单的应用程序,用于显示每部《星球大战》电影的数据。数据将由我们构建的 WordPress REST API 提供,并使用 Create React App 构建的 React 前端来使用这些数据。
第一步:创建新的 WordPress 安装
我不会深入讨论这一点,因为网络上有成千上万的资源可用于设置 WordPress 安装。
如果您是第一次接触 WordPress,那么我假设您尚未设置本地环境。有一些现成的解决方案,例如 MAMP 和 DesktopServer,非常适合快速上手。目前,我正在使用Vagrant,其中包含 Varying Vagrant Vagrants 和 Variable VVV。
设置好新的 WordPress 安装后,请继续访问您的管理仪表板:http://your-site.dev/wp-admin
第二步:安装 WordPress REST API 插件(可能不是必需的)
仅当您运行的 WordPress 版本低于 4.7 时才需要执行此步骤。您可以通过“控制面板”>“更新”查看您正在运行的 WordPress 版本:
从 WordPress 4.7 开始,WP-API 已集成到 WordPress 核心中。因此,如果您运行的是 4.7 或更高版本,就可以直接使用了。
否则,请导航至“插件”>“添加新插件”,然后搜索“WordPress REST API(版本 2)”。继续安装,然后激活它。
第三步:健全性检查
启动您最喜欢的 API 请求工具(我喜欢使用 Postman)或终端窗口(如果您愿意)。
向 发起 GET 请求http://your-site.dev/wp-json/
。您应该会返回一些 JSON,其中包含所有 WordPress 站点的资源及其各自的端点。
为了快速演示,请向 发送一个 GET 请求,http://your-site.dev/wp-json/wp/v2/posts/1
您应该会收到 JSON 格式的返回信息,其中包含“Hello World!”测试帖子的信息,该帖子默认随所有新安装的 WordPress 服务一起提供。如果您已经删除了该测试帖子,则不会收到任何信息。
第四步:为该项目安装插件
接下来要做的是安装此演示项目所需的插件。请先安装这些插件,然后返回查看每个插件的说明(除非另有说明,否则每个插件都可以通过“插件”>“添加新插件”进行搜索和安装)。
CPT用户界面
自定义帖子类型(CPT)是 WordPress 最强大的功能之一。它允许您创建自定义内容类型,超越 WordPress 自带的默认帖子和页面。
虽然通过 PHP 创建 CPT 确实可行(而且相当简单),但我真的很喜欢 CPT UI 的易用性。另外,如果您之前没有 WordPress 经验,我更希望您专注于 WP-API 本身,而不是 WordPress 和 PHP。
为了我们的演示,我们将创建一个名为“电影”的 CPT。
我将介绍如何手动添加电影 CPT,但如果您想跳过该步骤并直接导入数据,请转到 CPT UI>工具并粘贴以下内容:
{
"movies": {
"name": "movies",
"label": "Movies",
"singular_label": "Movie",
"description": "",
"public": "true",
"publicly_queryable": "true",
"show_ui": "true",
"show_in_nav_menus": "true",
"show_in_rest": "true",
"rest_base": "movies",
"has_archive": "false",
"has_archive_string": "",
"exclude_from_search": "false",
"capability_type": "post",
"hierarchical": "false",
"rewrite": "true",
"rewrite_slug": "",
"rewrite_withfront": "true",
"query_var": "true",
"query_var_slug": "",
"menu_position": "",
"show_in_menu": "true",
"show_in_menu_string": "",
"menu_icon": "",
"supports": [
"title",
"editor",
"thumbnail"
],
"taxonomies": [],
"labels": {
"menu_name": "",
"all_items": "",
"add_new": "",
"add_new_item": "",
"edit_item": "",
"new_item": "",
"view_item": "",
"search_items": "",
"not_found": "",
"not_found_in_trash": "",
"parent_item_colon": "",
"featured_image": "",
"set_featured_image": "",
"remove_featured_image": "",
"use_featured_image": "",
"archives": "",
"insert_into_item": "",
"uploaded_to_this_item": "",
"filter_items_list": "",
"items_list_navigation": "",
"items_list": ""
},
"custom_supports": ""
}
}
现在开始手动流程:
-
前往 CPT UI>添加/编辑帖子类型
-
对于帖子类型 Slug,输入
movies
“–”这是 WordPress 将使用的 URL slug。 -
对于复数标签,输入
Movies
-
对于单数标签,输入
Movie
-
重要提示:向下滚动到“设置”区域,找到“在 REST API 中显示”选项。默认情况下,该选项设置为 False。如果您不将其更改为 True,您将无法使用 WP-API 查询此 CPT。在该选项的正下方,您应该会看到“REST API 基本 slug”选项——您可以
movies
在此处输入。 -
一直向下滚动并单击“添加帖子类型”。
您应该会看到侧边栏中出现一个新的电影选项:
高级自定义字段
用数据库术语来说,如果 CPT 是表,那么自定义字段就是列。这实际上并不是 WordPress 在数据库中存储 CPT 和自定义字段的方式,但我发现这个例子对那些 WordPress 经验有限甚至毫无经验的人很有帮助。CPT 是资源(例如“电影”),而自定义字段是该资源的元数据(例如“发行年份、评级、描述”)。
高级自定义字段 (ACF) 是 WordPress 自定义字段的插件。当然,您可以使用 PHP 创建自定义字段(就像 CPT 一样),但 ACF 非常省时(而且使用起来非常愉快)。
您可以从插件>添加新插件中获取这个,但如果您想使用导入功能来导入我的示例数据,您将需要专业版,您可以在这里找到)。
如果您使用的是专业版,请在激活插件后前往“自定义字段”>“工具”。然后,您可以粘贴以下 JSON 数据来导入所需的字段:
[
{
"key": "group_582cf1d1ea6ee",
"title": "Movie Data",
"fields": [
{
"key": "field_582cf1d9956d7",
"label": "Release Year",
"name": "release_year",
"type": "number",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"placeholder": "",
"prepend": "",
"append": "",
"min": "",
"max": "",
"step": ""
},
{
"key": "field_582cf1fc956d8",
"label": "Rating",
"name": "rating",
"type": "number",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"placeholder": "",
"prepend": "",
"append": "",
"min": "",
"max": "",
"step": ""
},
{
"key": "field_5834d24ad82ad",
"label": "Description",
"name": "description",
"type": "textarea",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"placeholder": "",
"maxlength": "",
"rows": "",
"new_lines": "wpautop"
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "movies"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "top",
"instruction_placement": "label",
"hide_on_screen": "",
"active": 1,
"description": ""
}
]
如果您没有专业版,请按照以下步骤设置您的自定义字段:
创建字段组
ACF 将自定义字段集合组织到字段组中。这是 ACF 特有的领域功能。关于字段组,您目前真正需要了解的就这些。
1.转到自定义字段>字段组
-
点击“添加新”
-
对于字段组标题,输入“电影数据”
-
向下滚动,直到看到“位置”元框。将此字段组设置为仅当帖子类型等于电影时显示:
然后,您可以向下滚动到“设置”元框。您应该可以将所有这些选项保留为默认值,但您仍然可以将其与此屏幕截图进行比较:
之后,单击“更新”以保存您的“字段组”设置。
创建自定义字段
首先,创建一个“发布年份”字段:
Field Label: Release Year
Field Name: release_year
Field Type: Number
Required? No
接下来是评级字段:
Field Label: Rating
Field Name: rating
Field Type: Number
Required? No
最后是描述字段:
Field Label: Description
Field Name: description
Field Type: Text Area
Required? No
不要忘记单击“更新”来保存新的自定义字段。
现在,如果您转到“电影”>“添加新”,然后向下滚动一点,您应该会看到一个名为“电影数据”(字段组的名称)的元框以及您在其中创建的每个自定义字段:
ACF 到 REST API
现在我们有了自定义字段,接下来需要将它们暴露给 WP-API。ACF 目前不支持 WP-API,但社区提供了一个很棒的插件解决方案,叫做 ACF to REST API。您只需安装(您可以在“插件”>“添加新插件”中搜索找到)并激活它,它就会立即将您的 ACF 自定义字段暴露给 API。
如果我们直接通过 PHP 创建自定义字段(不使用插件),那么还有一些实用的函数可以将字段暴露给 API。更多信息请点击此处。
第五步:导入后数据
这是让我们的 WordPress 安装准备好为我们的星球大战数据提供服务的最后一步。
首先,我们需要导入所有电影。幸运的是,我已经完成了所有手动操作,你只需要导入一个文件即可。:-)
前往“工具”>“导入”。在页面底部,你会看到一个从 WordPress 导入的选项,下方有一个“立即安装”链接:
WordPress Import 安装完成后,您应该会看到一个运行导入器的链接。点击该链接,并在下一个屏幕上导入此文件。
下一个屏幕将要求您将导入的帖子分配给作者。您可以直接将它们分配给默认管理员帐户,然后单击“提交”:
最后,前往“电影”>“所有电影”。您应该会看到《星球大战》电影(第 1-7 集)的列表。由于我是在本地环境中开发的,导入文件无法导入电影的特色图片(无法从源服务器获取),因此您必须手动添加(大约只需 30 秒)。
我最喜欢(也是最快捷)的方式是,将鼠标悬停在“所有电影”页面上的每篇文章上,按住 Command(Windows 上是 Control),然后点击每篇文章的“编辑”。这样每部电影都会打开一个标签页。
在每个编辑页面的右侧边栏中,找到“精选图片”元框,然后点击“设置精选图片”。这是一个包含您需要的所有图片的 ZIP 文件。或者,您也可以使用任何其他您喜欢的图片。
对于第一个,最简单的方法是将所有图像上传到单击“设置特色图像”时看到的图像模式,然后仅选择第一部电影所需的图像(这将节省您在所有电影中单独上传每张图片的时间):
如果这看起来不清楚,这里有一个 GIF,希望它比我拙劣的解释更有意义。
对于每部电影,请务必在选择特色图片后单击“更新”。
现在一切就绪!保持 WordPress 服务器运行,我们继续。
第六步:安装 Create React App
假设您的机器上已经安装了 Node 和 npm,只需运行以下命令:
npm install -g create-react-app
就这样!您已准备好使用 Create React App。
第七步:创建应用程序
cd
进入您想要创建前端的目录(这不必(也不应该)与您的 WordPress 安装目录相同)。然后运行:
create-react-app headless-wp
该过程将需要几分钟,但一旦完成,您应该能够进入新创建的headless-wp
目录。从那里运行:
npm start
此命令会触发许多操作,但目前你只需要知道它将启动一个 Webpack 开发服务器。你的浏览器应该会自动打开http://localhost:3000
:
您可以让服务器在 shell 中运行。每次保存文件时,热加载都会自动刷新您的网页。
第八步:创建组件
由于这个演示应用非常简单,我们只会使用一个组件。我们可以轻松创建另一个组件(只需创建另一个ComponentName.js
文件并将其导入到其父组件中即可),但我们这次要编辑我们的App.js
组件。
打开App.js
。您可以继续删除此文件中除第一行和最后一行之外的所有现有代码。
此时,App.js
应该看起来像这样:
import React, { Component } from 'react';
export default App;
接下来,render()
为该组件创建函数。每次状态改变时都会调用此函数。如果您不确定这是什么意思,请耐心等待。很快就会明白的。
App.js
现在应该看起来像这样:
import React, { Component } from 'react';
class App extends Component {
render() {
return (
<div>
<h2>Star Wars Movies</h2>
</div>
)
}
}
export default App;
返回的内容render()
会被绘制到 DOM 上。如果你保存此文件并返回浏览器,它应该会自动重新加载,然后你就会看到h2
我们创建的内容:
这真是太棒了,但我们在 WordPress 中存储的《星球大战》电影数据怎么办呢?是时候获取这些数据了!
App.js
像这样更新:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://headless-wp.dev/wp-json/wp/v2/movies?_embed";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
return (
<div>
<h2>Star Wars Movies</h2>
</div>
)
}
}
export default App;
我们刚刚向我们的render()
函数添加了两个新函数:constructor()
和componentDidMount()
。
该constructor()
函数是我们初始化状态的地方。由于我们只处理一些关于电影的 JSON 数据,所以我们的状态会非常简单。movies
由于我们期望返回的是 JSON 数据,因此初始状态将只是一个空数组。
该componentDidMount()
函数在组件挂载后触发。这是进行外部 API 调用的最佳位置,因此我们在这里添加了代码,使用fetch API从 WordPress API 中抓取所有影片(请务必更新 URL 以反映您自己的 URL!)。然后,我们获取响应,将其解析为 JSON,然后将其推送到我们的状态对象中。
一旦响应被推送到我们的状态中,组件就会通过触发render()
函数重新渲染,因为状态已经改变。但这现在并不重要,因为目前我们的render()
函数仍然只返回一个带有h2
inside 的 div。
让我们修复它。
我们现在要向我们的函数添加一些额外的代码render()
,将我们状态中的 JSON(当前存储在this.state.movies
)和map
每部电影及其数据放入一个 中div
。
App.js
现在应该看起来像这样:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://headless-wp.dev/wp-json/wp/v2/movies?_embed";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<img src={movie._embedded['wp:featuredmedia'][0].media_details.sizes.large.source_url} />
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Release Year:</strong> {movie.acf.release_year}</p>
<p><strong>Rating:</strong> {movie.acf.rating}</p>
<div><strong>Description:</strong><div dangerouslySetInnerHTML={ {__html: movie.acf.description} } /></div>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
</div>
)
}
}
export default App;
如果您保存文件,页面将重新加载,但您仍然看不到《星球大战》电影数据加载。这是因为还有最后一件事要添加。我们将每部电影映射到各自的 div 中,然后将所有这些电影存储在函数movies
中的变量中render()
。现在我们只需要在下方添加 来告诉render()
函数返回我们的变量。movies
{movies}
h2
完成的App.js
:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://headless-wp.dev/wp-json/wp/v2/movies?_embed";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<img src={movie._embedded['wp:featuredmedia'][0].media_details.sizes.large.source_url} />
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Release Year:</strong> {movie.acf.release_year}</p>
<p><strong>Rating:</strong> {movie.acf.rating}</p>
<div><strong>Description:</strong><div dangerouslySetInnerHTML={ {__html: movie.acf.description} } /></div>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
{movies}
</div>
)
}
}
export default App;
切换回浏览器窗口,页面重新加载后您应该会看到星球大战数据:
更进一步
这只是 WP-API 和 React 功能的开始。两者都有许多其他功能,并且都拥有庞大的社区。
您可以通过了解身份验证和 POST 请求、自定义端点和更复杂的查询来进一步了解 WP-API。
正如我之前所说,Create React App 是为你准备的入门工具。当你准备好学习更多内容时,你可以学习 Redux、ES6、Webpack、React Native 等等。
我会在以后的帖子中讨论这些主题以及更多内容,所以请务必回来查看。或者,如果您希望将这些帖子直接发送到您的收件箱,请给我发送电子邮件,我会将您添加到我的邮件列表中。
问题?
我很乐意帮忙!在下方留言是获得回复的最快方式(而且,它还能帮助其他遇到同样问题的人!)。或者,您也可以在 Twitter 上留言或发送电子邮件给我,我会尽力提供帮助!
鏂囩珷鏉ユ簮锛�https://dev.to/jchiatt/headless-wordpress-with-react