扩展WordPress REST API

WordPress REST API 提供了一种统一的接口,用于从 WordPress 站点获取、添加、更新和删除数据。

虽然 REST API 中可用的数据类型模式相当广泛,但有时你可能需要存储不属于核心模式的其他数据。

在本课中,你将学习两种在 REST API 请求中添加字段的方法:一种是在 REST API 路由中启用自定义字段,另一种是将自定义字段作为顶级字段提供。

你还将了解这两种方法的优缺点。

如果你跳过了本模块中的前几课,请从仓库自述文件中的链接下载 Bookstore 插件 1.0.2 版本,并在本地 WordPress 安装中安装并激活该插件。

此外,如果你还没有这样做,请下载并安装适用于你操作系统的 Postman 应用。

关于修改响应的重要说明

在开始之前,务必注意修改 WP REST API 响应可能会产生意外后果。从核心 REST API 端点响应中更改或删除数据可能会破坏插件或 WordPress 核心行为,应尽可能避免。

如果你需要从 REST API 请求中检索数据子集,推荐的方法是使用 _fields 全局参数来限制响应中返回的字段。

例如,如果你只需要应用程序中的 id 和 title 字段,可以使用 fields 参数将返回的字段限制为仅这两个。

向 REST API 响应添加字段风险较小,因此本课仅涵盖添加字段。

使用自定义字段

如果你观看了“WordPress 插件简介”模块中的课程,你应该已经了解了自定义字段(也称为元数据)。

这些字段通常用于自定义文章类型,以存储特定于该文章类型的额外数据。在底层,这些自定义字段存储在 postmeta 表中,作为一组键/值对,通过文章 ID 附加到文章上。

除了文章,WordPress 还支持其他数据类型(如评论和用户)的元数据。你可以在元数据 API 文档中了解更多信息。

WP REST API 允许你在创建或更新数据时创建或更新自定义字段。

这可以通过将键/值对对象传递给所操作文章类型的 meta 属性来实现。

但是,要使用自定义字段,你必须先注册它。这可以使用 register_meta 函数完成。

注册自定义字段

如果你想在文章上注册一个名为 location 的自定义字段,你可以像这样使用 register_meta 函数:

register_meta( 'post', 'location', array(
    'type'         => 'string',
    'description'  => 'A location for the post',
    'single'       => true,
    'show_in_rest' => true,
) );

虽然可以将其添加到插件的任何位置,但建议将其添加到类似 init 动作钩子的地方。

add_action( 'init', function() {
    register_meta( 'post', 'location', array(
        'type'         => 'string',
        'description'  => 'A location for the post',
        'single'       => true,
        'show_in_rest' => true,
    ) );
} );

务必确保 show_in_rest 属性设置为 true,否则自定义字段将无法在 REST API 中使用。

这将使自定义字段能够添加到文章的 REST API 模式中,并且还允许你使用 REST API 将数据发布到自定义字段。这通过在请求体的 meta 对象 中传递自定义字段作为键值对来处理。

{
    "title": "My Post",
    "content": "This is my post content.",
    "meta": {
        "location": "New York"
    }
}

你可以通过在 Postman 中创建一个新的 POST 请求并将其发送到文章路由来测试这一点。

为特定 WP REST API 路由启用自定义字段

WordPress 4.9.8 之前,使用 register_metashow_in_rest 设置为 true 的自定义字段会注册到给定类型的所有对象上。例如,如果你向文章类型添加了一个自定义字段,然后创建了一个自定义文章类型,该自定义字段将自动在自定义文章类型中可用。

WordPress 4.9.8 开始,可以使用带有 object_subtype 参数的 register_meta,该参数允许将元键的使用范围限制到特定的文章类型。

例如,假设你想仅在 book 自定义文章类型上注册一个 ISBN 自定义字段。你可以将其添加到注册自定义文章类型的代码中,如下所示:

register_post_type( 'book', array(
    'labels'      => array(
        'name'          => __( 'Books', 'bookstore' ),
        'singular_name' => __( 'Book', 'bookstore' ),
    ),
    'public'      => true,
    'has_archive' => true,
    'show_in_rest' => true,
    'supports'    => array( 'title', 'editor', 'custom-fields' ),
) );

register_meta( 'post', 'isbn', array(
    'type'         => 'string',
    'description'  => 'The ISBN of the book',
    'single'       => true,
    'show_in_rest' => true,
    'object_subtype' => 'book',
) );

现在,isbn 自定义字段将仅对 book 自定义文章类型可用。

你可以通过 REST API 添加一本书来测试这一点。

在 Postman 中,创建或更新对书籍路由的 POST 请求,并在 meta 对象中包含 ISBN 字段:

POST /wp-json/wp/v2/books

然后在请求体中发布以下内容:

{
    "title": "My Book",
    "content": "This is my book content.",
    "meta": {
        "isbn": "978-3-16-148410-0"
    }
}

如果你随后在 WordPress 管理后台编辑这本书,并且启用了自定义字段面板,你将看到 isbn 字段的值。它也是 book 文章类型唯一可用的自定义字段。

将自定义字段添加为 API 响应的顶级字段

另一种将自定义字段添加到 WP REST API 的方法是将它们添加为 API 响应的顶级字段。

在之前的示例中,isbn 被注册为元字段,因此它出现在 REST API 响应的元对象中。但如果你希望它作为顶级字段,与标题、内容和摘要并列,该怎么办呢?

这可以通过使用 register_rest_field 函数来实现。让我们看看如何实现这一点。

将自定义字段添加为顶级字段

首先,你需要在 rest_api_init 动作钩子中注册你的 REST 字段。这是为了确保该字段仅在 REST API 上注册。

add_action( 'rest_api_init', 'bookstore_add_rest_fields' );
function bookstore_add_rest_fields() { 
    // register some REST API functionality
}

然后,你使用 register_rest_field 函数来注册该字段。第一个参数是字段应注册的对象类型。对于单个对象,可以是字符串;对于多个对象,可以是数组。在本例中,只需在 book 自定义文章类型上注册该字段。第二个参数是字段的名称。在本例中,只需将其设置为与自定义字段相同的名称,即 isbn

    register_rest_field(
        'book',
        'isbn',
    );

第三个参数是一个参数数组,用于决定字段的功能。你至少需要向该数组传递以下三个参数。

  1. get_callback – 返回字段值的函数
  2. update_callback – 更新字段值的函数
  3. schema – 包含字段模式的数组
    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => null,
            'update_callback' => null,
            'schema'          => null,
        )
    );

现在,你可以将 REST 字段的模式参数保留为 null,但你需要指定 get_callbackupdate_callback 函数。这些函数将在 API 请求发出时触发,无论是用于获取数据,还是用于创建或更新数据。

    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => 'bookstore_rest_get_isbn',
            'update_callback' => 'bookstore_rest_update_isbn',
            'schema'          => null,
        )
    );

默认情况下,文章类型的准备数据数组会作为第一个参数传递给 get_callback 函数。这个函数的实现可以简单到直接返回自定义字段的值。

function bookstore_rest_get_isbn( $book ){
    return  get_post_meta( $book['id'], 'isbn', true );
}

从 REST API 创建或更新请求中为字段发送的值会作为第一个参数传递给 update_callback 函数,而模型对象(即文章)则作为第二个参数。这个函数的实现可以简单到直接更新自定义字段的值。

function bookstore_rest_update_isbn( $value, $book ){
    return update_post_meta( $book->ID, 'isbn', $value );
}

如果你通过创建一本新书并为 isbn 字段传递一个值来测试这一点,你会看到数据被保存到数据库的 post_meta 表中,同时也会作为顶级字段显示在 REST API 响应中。

包含模式

模式参数是一个描述字段模式的数组。虽然这不是必须的,但建议包含模式。至少,它有助于未来的开发者理解字段的用途。它还可以用于在创建自动化 API 测试时验证发送的数据。

    register_rest_field(
        'book',
        'isbn',
        array(
            'get_callback'    => 'wp_learn_rest_get_isbn',
            'update_callback' => 'wp_learn_rest_update_isbn',
            'schema'          => array(
                'description' => __( 'The ISBN of the book' ),
                'type'        => 'string',
            ),
        )
    );

你可以在 WP REST API 手册中阅读更多关于如何定义 REST API 资源和字段模式的内容。

是否使用 register_rest_field

在决定是仅使用 register_meta,还是添加 register_rest_field 的使用时,你应该考虑每种方法的优缺点。

仅使用 register_meta 方法的主要优点是,只要你记得在应用程序代码中使用元对象来获取和保存数据,就不需要添加任何额外的代码来启用自定义字段的存储或检索。你只需启用该字段在 REST API 中显示,就可以直接使用它。这也是性能更优的选择,因为它不会增加任何需要执行的额外代码。

另一方面,使用 register_rest_field 方法的优点是,你可以在数据返回或保存之前对其进行额外的处理。例如,你可以在数据保存到数据库之前对其进行一些验证。你还可以向 get_callback 和 update_callback 函数添加钩子,以便对数据进行额外处理,或允许其他开发者扩展你的自定义字段。缺点是它会为 API 请求增加一些开销,因为需要执行更多的代码。

最终,你选择哪种方法应根据具体情况来决定。

进一步阅读

有关修改 REST API 响应的更多信息,请查看 WP REST API 手册中的“修改响应”部分。

与WordPress REST API交互

虽然 WP REST API 通常用于从 WordPress 获取数据,但它也可以用来执行其他操作。

REST API 还允许你创建、更新和删除各种 WordPress 数据类型。

在本课中,你将了解 WP REST API 模式、验证 WP REST API 请求的方法、测试 WP REST API 请求的工具,以及通过 WP REST API 添加、编辑或删除数据的几种方式。

如果你跳过了本模块前面的课程,请从仓库自述文件中的链接下载 Bookstore 插件 1.0.1 版本,并在本地 WordPress 安装中安装并激活该插件。

WP REST API 模式

在使用 REST API 时,最好将 WP REST API 文档中的端点参考部分放在手边。端点参考列出了 WordPress 核心附带的所有端点。

点击某个端点,例如文章,将显示该端点的模式。模式定义了在获取或创建特定类型数据时,该资源存在的所有字段。

如果你创建了自定义文章类型,比如 bookstore 插件中的书籍自定义文章类型,那么自定义文章类型端点的模式将与文章端点类似。

你会注意到,许多端点字段与 WordPress 数据库中与该数据类型相关的表中的字段相匹配。然而,有些字段略有不同。例如,文章端点的标题字段将与文章表中的 post_title 字段对应。记住这些差异很重要,并且在通过 API 交互时使用正确的字段名称。

身份验证

默认情况下,WordPress REST API 使用与登录 WordPress 仪表盘时相同的基于 Cookie 的身份验证方法。

对于任何非公开的 REST API 端点,或者需要验证用户才能查看或修改的端点,必须存在身份验证 Cookie。

例如,块编辑器就是这样工作的。

有多种验证请求的方法,包括 JSON Web 令牌和 OAuth。

WordPress 内置的另一种方法是应用程序密码。

应用程序密码可以按用户设置,用于验证对 WP REST API 的请求。这允许你让用户访问 API,而无需共享他们用于登录 WordPress 仪表盘的密码。

要为你的用户创建应用程序密码,请导航到用户列表中的该用户,点击该用户进行编辑。滚动到屏幕底部,在应用程序密码部分下。

为新的应用程序密码命名,然后点击添加新应用程序密码。

密码将为你生成。请务必复制并安全地存储它,因为你将无法再次看到它。

在此屏幕上,如果密码泄露,你也可以撤销它。

使用应用程序密码为你的用户测试 REST API 请求,是使用 REST API 测试工具的好方法。

如果你打算构建更复杂的东西,比如连接到 WordPress REST API 的移动应用,你应该考虑使用 JSON Web 令牌或 OAuth 1.0a。

Postman

有许多工具可用于测试 REST API 请求。

例如,如果你使用 PhpStorm,它内置了 HTTP 客户端;如果你使用 VS Code,则有像 Postcode 这样的扩展。还有像 Hoppscotch 和 Postman 这样的独立工具。你甚至可以在终端中使用 curl 命令测试 REST API 端点。

为了本课的目的,你将学习如何使用 Postman 测试一些 REST API 请求。

你可以从 Postman 网站下载 Postman。默认情况下,Postman 会创建一个初始工作区,用于存储你的请求集合。

安装后,打开 Postman,点击创建集合按钮。这将创建一个新集合,你可以在其中添加多个请求进行测试。

你可以为集合命名,以区别于其他集合。在集合内部,点击添加请求按钮。

这将打开一个新请求,你可以为请求指定一个唯一名称。然后,输入本地 books 端点的 URL,并点击发送按钮。

http://yourlocal.wordpress.site/wp-json/wp/v2/books

请求将被发送,JSON 响应将被解析并显示在响应区域中。

现在,创建一个新请求,输入相同的 books 端点 URL,但这次将请求方法更改为 POST,然后点击发送。通过将请求方法更改为 POST,你告诉服务器你想要创建或可能更新一本书。

这次你将看到一个错误消息,因为你没有经过身份验证。

要验证请求,请点击“授权”选项卡,然后从下拉菜单中选择“基本认证”。

接着,输入你的用户名以及之前创建的应用程序密码,然后点击保存按钮。

这次你不会遇到同样的错误,因为你已经通过了身份验证。现在你可以创建书籍了。

继续操作,点击请求中的“正文”选项卡,并选择“原始”单选按钮。然后,从下拉菜单中选择 JSON,并输入以下 JSON 内容:

{
    "title": "My Postman Book",
    "content": "This is my Postman book",
    "status": "publish"
}

再次点击发送,书籍将被创建,并返回新书籍的 JSON 响应。

为了确认,请前往 WordPress 后台检查书籍列表,你应该能看到这本书。

要更新一本书,你可以使用与添加书籍相同的请求配置,但需要修改端点 URL,使其包含书籍 ID。

要删除一本书,你可以使用与更新书籍相同的端点 URL,但需要将请求方法改为 DELETE,并且不在请求正文中发送任何数据。

你还会注意到,删除一篇文章实际上会将其移至回收站,而不是永久删除。这与 WordPress 后台的行为一致。

使用 Postman 这样的工具来测试 REST API 端点,是学习如何使用 WP REST API 的好方法。它对于测试 WP REST API 请求也非常有用,可以确保你打算发送的数据格式正确,并且请求被发送到了正确的端点。

创建一本书

让我们使用 WP REST API 和 api-fetch 来创建一本新书。

为此,我们需要将标题和内容字段作为 POST 请求发送到 books 端点。

你已经有一个可以列出书籍的插件,所以可以以此为基础开始。

首先,你需要更新页面,添加一个表单,用于输入要创建的书籍的标题和内容。你可以使用以下 HTML 来创建表单,并将其添加到 bookstore_render_booklist() 管理页面回调函数中,放在现有 HTML 代码下方:

<div style="width:50%;">
    <h2>Add Book</h2>
    <form>
        <div>
            <label for="bookstore-book-title">Book Title</label>
            <input type="text" id="bookstore-book-title" placeholder="Title">
        </div>
        <div>
            <label for="bookstore-book-content">Book Content</label>
            <textarea id="bookstore-book-content" cols="100" rows="10"></textarea>
        </div>
        <div>
            <input type="button" id="bookstore-submit-book" value="Add">
        </div>
    </form>
</div>

这段 HTML 代码在自定义管理页面中添加了一个新表单,允许你输入新书的标题和内容。表单还包含一个提交按钮。

添加表单后,下一步是添加 JavaScript 代码,用于处理按钮点击事件:

const submitBookButton = document.getElementById( 'bookstore-submit-book' );
if ( submitBookButton ) {
    submitBookButton.addEventListener( 'click', function () {
        // create post code
    } );
}

现在你已经添加了按钮点击事件监听器,可以添加处理书籍创建的代码了。

为此,建议创建一个单独的函数来创建书籍,并在点击事件中调用该函数。

首先,你需要创建一个 submitBook 函数:

function submitBook() {
    // create book code
}

然后更新点击事件监听器,使其调用该函数:

submitBookButton.addEventListener( 'click', submitBook );

submitBook 函数内部,你需要从表单字段中获取标题和内容的值:

    const title = document.getElementById( 'bookstore-book-title' ).value;
    const content = document.getElementById( 'bookstore-book-content' ).value;

现在,你可以使用 api-fetch 向 books 端点发送请求,将路径设置为 books 端点,请求方法设置为 POST,并将 titlecontent 作为数据对象传递:

    wp.apiFetch( {
        path: '/wp/v2/books/',
        method: 'POST',
        data: {
            title: title,
            content: content
        },
    } ).then( ( result ) => {
        alert( 'Book saved!' );
    } );

打开自定义管理页面,输入标题和内容,然后点击“添加”按钮。你应该会看到一个提示,显示“书籍已保存!”。

然后,如果你浏览到书籍列表,就会看到新书被列出来了。

更新和删除书籍

你也可以使用 WP REST API 来更新和删除书籍。

你可以使用与添加项目相同的 api-fetch 实现来更新项目。你需要更新路径,使其包含要更新的数据实体(本例中为书籍)的 ID,以便更新该项目,同时更新数据对象,为要更新的字段提供新值。

    wp.apiFetch( {
        path: '/wp/v2/books/' + id,
        method: 'POST',
        data: {
            title: newTitle,
            content: newContent
        },
    } ).then( ( result ) => {
        alert( 'Book Updated!' );
    } );

删除一篇文章只需要将路径设置为该项目的 URL,并将方法设置为 DELETE

    wp.apiFetch( {
        path: '/wp/v2/books/' + id,
        method: 'DELETE',
    } ).then( ( result ) => {
        alert( 'Book deleted!' );
    } );

进一步阅读

有关使用 WP REST API 创建、更新和删除数据的更多信息,请查看 WP REST API 手册中的“使用 REST API”部分,以及区块编辑器手册中的 api-fetch 包参考。

使用WordPress REST API

WordPress REST API 提供了一个统一的接口,用于与 WordPress 站点中的数据进行交互。

在本课中,你将学习如何使用 WP REST API 从你的 WordPress 站点获取数据。

你将发现三种进行 REST API 请求的内部选项,然后使用它们执行 GET 请求来获取一些公开的自定义文章类型数据。

Bookstore 插件

如果你完成了“WordPress 插件入门”模块,你应该已经构建了一个注册名为 book 的自定义文章类型的插件。

如果你跳过了那个模块,你可以通过点击 Bookstore 插件链接,从 GitHub 仓库下载主插件代码。

安装并激活插件后,在你的代码编辑器中打开主插件文件。

你会注意到传递给 register_post_type 函数的参数之一是 show_in_rest

register_post_type( 'book',
    array(
        'labels'      => array(
            'name'          => __( 'Books', 'textdomain' ),
            'singular_name' => __( 'Book', 'textdomain' ),
        ),
        'public'      => true,
        'has_archive' => true,
        'show_in_rest' => true,
    )
);

此参数设置为 true,这意味着该自定义文章类型在 REST API 中可用。

这意味着如果你浏览到 wp-json/wp/v2/book 路由,你将在响应中看到自定义文章类型的数据。

如果你查看 register_post_type 函数参考,你会发现一些额外的参数可用于控制 REST API 响应。

例如,你可以更改 rest_base 参数来改变自定义文章类型数据可用的路由。

考虑到你期望能够从 book 路由获取多本书,将 rest_base 改为 books 是个好主意。

register_post_type( 'book',
    array(
        'labels'      => array(
            'name'          => __( 'Books', 'textdomain' ),
            'singular_name' => __( 'Book', 'textdomain' ),
        ),
        'public'      => true,
        'has_archive' => true,
        'show_in_rest' => true,
        'rest_base'   => 'books',
    )
);

这样做将允许你向 wp-json/wp/v2/books 路由发出请求,通过 REST API 访问书籍。

发起 REST API 请求

假设你想在 WordPress 仪表盘中添加一个页面,该页面获取书籍并以逗号分隔的列表形式显示书名和永久链接。

首先,你可以使用 admin_menu 钩子和 add_submenu_page 函数,在“书籍”菜单下添加一个管理子菜单页面。

add_action( 'admin_menu', 'bookstore_add_admin_menu' );
function bookstore_add_admin_menu() {
    add_submenu_page(
        'edit.php?post_type=book',
        __( 'Book List', 'textdomain' ),
        __( 'Book List', 'textdomain' ),
        'manage_options',
        'book-list',
        'bookstore_render_booklist'
    );
}

然后,你需要创建 bookstore_render_booklist 回调函数,该函数将输出管理页面的 HTML。

function bookstore_render_booklist() {
    ?>
    <div class="wrap">
        <h1>Book List</h1>
        <button id="load-books" class="button button-primary">Load Books</button>
        <textarea id="book-list" rows="10" cols="50"></textarea>
    </div>
    <?php
}

如果你浏览到仪表盘并点击“书籍”菜单,你会看到一个名为“Book List”的新子菜单页面。

点击该链接将带你进入一个包含“Load Books”按钮和一个文本区域的页面。

现在,你可以向 bookstore_render_booklist 函数添加功能,通过 PHP 获取书籍列表,并使按钮触发页面刷新。

然而,为了获得更流畅的用户体验,你希望使用 JavaScript 和 REST API 异步获取书籍数据并填充书籍列表,而无需等待整个页面刷新。

加载管理 JavaScript

在“WordPress 插件入门”模块中,你学习了如何在插件中加载 JavaScript 文件。

由于此功能被添加到管理仪表盘中,你需要设置一个单独的 wp_enqueue_script 函数调用,并将其挂载到 admin_enqueue_scripts 钩子上,这样 JavaScript 文件就只在管理仪表盘中加载。

首先,在插件目录中创建一个新的 JavaScript 文件,命名为 admin_bookstore.js

然后,将以下代码添加到主插件文件中,以在仪表盘中加载该 JavaScript 文件:

add_action( 'admin_enqueue_scripts', 'bookstore_enqueue_admin_scripts' );
function bookstore_enqueue_admin_scripts() {
    wp_enqueue_script(
        'bookstore-admin',
        plugin_dir_url( __FILE__ ) . 'admin_bookstore.js',
        array(),
        '1.0.0',
        true
    );
}

请注意,这段代码不仅加载了 JavaScript 文件,还指定了一个空的依赖项数组、一个版本号,并通过将最后一个参数设置为 true,指定它应在 HTML 页面的页脚中加载。

你可以在 wp_enqueue_script 函数参考的“参数”部分阅读有关这些参数的更多信息。

你可以通过在 admin_bookstore.js 文件中添加一个简单的 alert,然后刷新管理页面来测试它是否正确加载。

alert( 'Hello, World!' );

一旦你确认它正常工作,就可以从文件中删除该行。

选项 1:使用 Backbone.js 客户端

自从 REST API 被添加到 WordPress 以来,它就包含了一个 Backbone.js REST API JavaScript 客户端,用于直接向 WP REST API 发出请求。

它通过为所有通过 API 暴露的端点提供模型和集合,提供了一个使用 WP REST API 的接口。

为了确保你的 JavaScript 代码能够使用 REST API 客户端,你需要将其添加为已加载 JavaScript 的依赖项。

wp_enqueue_script 的第三个参数是一个包含所有依赖项的数组,你可以将 wp-api 作为依赖项添加到你的 wp_enqueue_script 函数调用中。

add_action( 'admin_enqueue_scripts', 'bookstore_enqueue_admin_scripts' );
function bookstore_enqueue_admin_scripts() {
    wp_enqueue_script(
        'bookstore-admin',
        plugin_dir_url( __FILE__ ) . 'admin_bookstore.js',
        array( 'wp-api' ),
        '1.0.0',
        true
    );
}

这将确保你的插件 JavaScript 代码仅在 REST API JavaScript 客户端加载完成后才加载,从而你可以在插件中使用它。

你需要先为新按钮注册一个点击事件处理器。

const loadBooksByRestButton = document.getElementById( 'bookstore-load-books' );
if ( loadBooksByRestButton ) {
    loadBooksByRestButton.addEventListener( 'click', function () {
        //do somthing
    } );
}

然后,在事件处理函数中,你可以通过全局对象 wp 访问 WP API 客户端,来创建一个新的书籍集合。

    const allBooks = new wp.api.collections.Books();

此时,allBooks 只是一个空集合,因此你需要通过调用集合的 fetch 方法来获取文章。

   allBooks.fetch();

fetch 方法返回一个 Promise,因此你可以链式调用 done 方法来处理响应,并实现一个回调函数来接收 API 请求的响应。

你可以在该回调函数中指定一个 books 参数,用于接收 API 请求的响应。

    allBooks.fetch().done(
        function ( books ) {
            // do something with books
        }
    );

现在,你可以使用类似 forEach 的方法遍历 books 对象,并逐一访问每本书。

    allBooks.fetch().done(
        function ( books ) {
            books.forEach( function ( book ) {
              // do something with book
            } );
        }
    );

最后,你可以将书名和永久链接添加到文本区域中。

首先,你需要在 forEach 循环之前创建一个文本区域的实例,然后在 forEach 循环内部将值追加到文本区域的 value 属性中。

        allBooks.fetch().done(
            function ( books ) {
                const textarea = document.getElementById( 'bookstore-booklist' );
                books.forEach( function ( book ) {
                    textarea.value += book.title.rendered + ',' + book.link + ',\n'
                });
            }
        );

你的最终代码将类似这样。

const loadBooksByRestButton = document.getElementById( 'bookstore-load-books' );
if ( loadBooksByRestButton ) {
    loadBooksByRestButton.addEventListener( 'click', function () {
        const allBooks = new wp.api.collections.Books();
        allBooks.fetch().done(
            function ( books ) {
                const textarea = document.getElementById( 'bookstore-booklist' );
                books.forEach( function ( book ) {
                    textarea.value += book.title.rendered + ',' + book.link + ',\n'
                });
            }
        );
    });
}

切换回自定义的“书籍列表”管理页面,点击“加载书籍”按钮,即可看到书籍列表出现在文本区域中。

选项 2:使用 @wordpress/fetch-api

自 WordPress 5.0 引入区块编辑器以来,@wordpress/fetch-api 包也已可用,用于发起 REST API 请求。

该包是浏览器 fetch API 的封装,提供了一种更现代、更灵活的方式来向 REST API 发起请求。

要使用 fetch API,你可以更新插件的 JavaScript 依赖项,加入 wp-api-fetch

    wp_enqueue_script(
        'bookstyle-script',
        plugins_url() . '/bookstore/admin_bookstore.js',
        array( 'wp-api', 'wp-api-fetch' ),
        '1.0.0',
        true
    );

你可以移除 wp-api 依赖,或者将 wp-api-fetch 作为额外依赖添加。

接下来,在表单的“操作”区域添加一个按钮,用于触发 fetch 请求。

<button id="bookstore-fetch-books">Fetch Books</button>

和之前一样,在你的 bookstore.js 文件中,为新按钮的点击事件设置一个事件监听器,但这次使用 apiFetch 方法来向 REST API 发起请求。

const fetchBooksByRestButton = document.getElementById( 'bookstore-fetch-books' );
if ( fetchBooksByRestButton ) {
    fetchBooksByRestButton.addEventListener( 'click', function () {
        wp.apiFetch( { path: '/wp/v2/books' } ).then( ( books ) => {
            const textarea = document.getElementById( 'bookstore-booklist' );
            books.map( ( book ) => {
                textarea.value += book.title.rendered + ',' + book.link + ',\n'
            });
        } );
    });
}

注意,你将指向书籍端点的路径作为一个对象传递给 wp.apiFetch 函数。这比使用 Backbone.js 客户端更灵活,因为后者需要使用特定的集合来访问书籍。

你可以链式调用 then 方法来处理响应。这与 Backbone 示例中使用 done 方法类似,因为它返回一个 Promise,等待 REST API 请求完成,然后将结果返回给回调函数。

在回调函数内部,你可以访问 books 对象,并使用 map 方法遍历它,将书名和永久链接追加到文本区域。

你还会注意到,这段代码使用了箭头函数语法作为接收响应的回调,这是一种更现代的 JavaScript 函数编写方式。

刷新管理页面,点击“获取书籍”按钮,即可看到书籍列表出现在文本区域中。

选项 3:使用 @wordpress/core-data

如果你正在开发区块,还有一个 core-data 包可用,用于从 REST API 访问数据。

core-data 旨在简化对核心 WordPress 实体的访问和操作。它注册了自己的存储,并提供了许多选择器,可自动从 WordPress REST API 解析数据,同时提供派发动作创建器来操作数据。

core-data 使用了大量 React 功能,因此最适合在区块上下文中使用。

让我们看看如何在区块中使用 core-data 模块从 REST API 获取书籍。

首先,使用你在“区块开发入门”模块中学到的 create-block 工具,创建一个名为 bookstore-block 的新区块。

cd path/to/local/site/wp-content/plugins
npx @wordpress/create-block bookstore-block

这将搭建新区块的脚手架,并生成一些代码供你编辑。

在区块的 edit.js 文件中,从 @wordpress/data 包导入 useSelect 钩子,以及从 @wordpress/core-data 包导入 store

import { useSelect } from '@wordpress/data';
import { store as bookStore } from '@wordpress/core-data';

然后,你可以使用这些来从 REST API 获取书籍。

    const books = useSelect(
        select =>
            select( bookStore ).getEntityRecords( 'postType', 'book' ),
        []
    );

useSelect 是一个钩子,允许你从已注册的选择器中检索数据。

useSelect 接受一个回调函数作为第一个参数,在该函数中你可以使用 bookStore 存储的 getEntityRecords 选择器从 REST API 中检索书籍。这些书籍随后会被存储在 books 变量中。

最后,你可以更新代码,使其在没有返回书籍时返回一个空组件,或者遍历书籍对象并输出书名和链接。

    if ( ! books ) {
        return (
            <div { ...useBlockProps() }></div>
        )
    }

    return (
        <div { ...useBlockProps() }>
            { books.map( ( book ) => (
                <p>
                    <a href={ book.link }>{book.title.rendered}</a>
                </p>
            ) ) }
        </div>
    );

现在,运行区块构建步骤,激活插件,并将书店区块添加到文章或页面中。

你将看到区块输出从 REST API 获取的书名和链接。

不同选项之间的区别

Backbone 客户端是三个选项中最古老的,但它也是与 REST API 集成最紧密的。如果你需要使用 WP REST API 构建管理仪表板页面,它是一个不错的选择,并且远优于使用传统的 admin-ajax.php 端点。

apiFetch 是一个出色的全能解决方案,因为它既可用于管理仪表板页面,也可用于编辑器中的区块。它也是一种更现代的向 REST API 发起请求的方式,并且比 Backbone 客户端更灵活。

core-data 最适合在区块上下文中使用,因为它使用了在区块编辑器上下文之外不可用的 React 功能。

进一步阅读

有关在 WordPress 中使用 REST API 的各种方式的更多信息,请查看 REST API 手册中的 Backbone JavaScript 客户端部分、区块编辑器手册中的 api-fetch 包,以及区块编辑器手册中的 core-data 包。

WordPress REST API

当您为 WordPress 进行开发时,有许多 API 可用于与您的站点数据进行交互。其中最重要的 API 之一就是 REST API。

本课程作为 WordPress REST API 的入门介绍。

您将了解什么是 REST API,以及一些关键的 REST API 概念,例如路由、端点和全局参数,这些将通过您可以在浏览器中执行的一系列示例请求来学习。

您还将了解在哪里可以找到关于 WP REST API 的更多信息。

什么是 WordPress REST API?

WordPress REST API 提供了一个接口,供应用程序与 WordPress 站点进行交互。这些应用程序可以是 WordPress 插件、主题,或需要访问 WordPress 站点数据的自定义应用程序。

WordPress REST API 最著名的实现之一是块编辑器,它是一个通过 REST API 与 WordPress 数据进行交互的 JavaScript 应用程序。

如果您打开浏览器的开发者工具并查看“网络”选项卡,您可以看到当您与块编辑器交互时,向 WordPress REST API 发出的请求。

REST API 是什么意思?

API 代表应用程序编程接口。它是一组允许应用程序相互交互的功能。WordPress 有许多 API,REST API 只是其中之一。

REST 代表表述性状态转移,这是一种软件架构风格,描述了物理上独立的组件之间的统一接口。

其核心是,WordPress REST API 提供了代表文章、页面、分类法以及任何其他自定义数据类型的 REST 端点(URI)。您的代码可以以 JavaScript 对象表示法(即 JSON)的形式向这些端点发送和接收数据,以获取、修改和创建您站点上的内容。

让我们深入了解 REST API 的一些概念,以便更好地理解它们。

路由与端点

WordPress REST API 的上下文中,路由是一个可以映射到不同 HTTP 方法的 URI。

HTTP 方法是您与网络上任何内容交互时发出的请求类型。例如,当您浏览到网络上的一个 URL 时,会向服务器发出一个 GET 请求以请求数据。

当您提交表单时,会发出一个 POST 请求,该请求将提交的表单数据传递给 Web 服务器。

将单个 HTTP 方法映射到路由的过程称为端点。

因此,例如,您会有一个用于获取数据的 GET 端点、一个用于创建数据的 POST 端点以及一个用于删除数据的 DELETE 端点,所有这些都使用相同的路由。

本地开发测试

关于在本地 WordPress 安装上测试 REST API 路由,需要注意的一点是,您可能需要启用除“朴素”之外的固定链接设置。

这是因为 REST API 使用与固定链接相同的 URL 重写功能,将人类可读的路由和端点映射到相关的内部请求。

因此,如果您的本地 WordPress 安装使用的是默认的“朴素”固定链接设置,请将其更改为类似“文章名”的设置。

示例路由与端点

让我们看一些路由和端点的示例。

如果您打开浏览器,并访问 WordPress 站点的 /wp-json/ URI,您将向该 URI 发出一个 GET 请求,该请求会返回一个 JSON 响应。

// 示例代码块,保持原样

某些浏览器内置支持“美化打印”JSON 响应,这将以更易读的格式显示它。

如果您使用 Firefox 查看 JSON 响应,它允许您在不同视图之间切换,以及检查请求头。

根据您的需求,也有浏览器扩展程序,例如 Chrome 的 JSON Formatter 或 Safari 的 JSON Peep。

返回的数据是一个 JSON 响应,显示了哪些路由可用,以及每个路由内有哪些端点可用。

在此示例中,/wp-json/ 是一个路由,当该路由收到 GET 请求时,由显示数据的端点处理。此数据就是所谓的 WordPress REST API 的索引。

相比之下,/wp-json/wp/v2/posts 路由提供了一个返回文章列表的 GET 端点,但也提供了一个 POST 端点。如果您是经过身份验证的用户,并且通过 POST 请求向 /wp-json/wp/v2/posts 路由提交了正确的数据,则该请求由创建新文章的端点处理。

通常,同一个路由(在本例中为 /wp-json/wp/v2/posts)将针对不同的 HTTP 方法有不同的端点,包括用于获取数据的 GET、用于创建数据的 POST 和用于删除数据的 DELETE。

全局参数

WP REST API 包含许多全局参数,这些参数控制 API 如何处理请求/响应处理。这些参数在实际资源之上的层运行,并且对所有资源都可用。

全局参数作为查询字符串参数在 REST API 路由上实现。查询字符串以 ? 开头,后跟一系列由 & 分隔的 key=value 键值对。

看看你之前查看过的 /wp-json/wp/v2/posts 路由,通过在浏览器中请求该路由,从而激活 GET 端点。如你所见,默认情况下会返回文章的所有可用字段。

不过,你可以通过添加 _fields 全局参数来更新路由,然后以逗号分隔的列表形式指定你希望在响应中返回的字段。

wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link

如果你通过刷新浏览器发起第二个 GET 请求,那么只有你请求在响应中返回的字段才会可用。

分页与排序

WP REST API 还支持结果的分页和排序。

分页由 per_pagepageoffset 参数处理。

例如,你可以通过向路由添加 per_page 参数,将 wp-json/wp/v2/posts 路由更新为每页仅返回 5 篇文章。

wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link&per_page=5

如果你通过刷新页面发起新的 GET 请求,则只会返回前 5 篇文章。

还可以使用 orderorder_by 参数对结果进行排序。

例如,你可以将 wp-json/wp/v2/posts 路由更新为按文章标题降序排列。

wp-json/wp/v2/posts?_fields=author,id,excerpt,title,link&per_page=5&orderby=title&order=asc

延伸阅读

WordPress 开发者资源网站有一个专门介绍 REST API 的完整章节,其中包含关于 REST API 关键概念、常见问题、使用和扩展 REST API 等内容的部分。