扩展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 手册中的“修改响应”部分。