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_meta 将 show_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',
);
第三个参数是一个参数数组,用于决定字段的功能。你至少需要向该数组传递以下三个参数。
- get_callback – 返回字段值的函数
- update_callback – 更新字段值的函数
- schema – 包含字段模式的数组
register_rest_field(
'book',
'isbn',
array(
'get_callback' => null,
'update_callback' => null,
'schema' => null,
)
);
现在,你可以将 REST 字段的模式参数保留为 null,但你需要指定 get_callback 和 update_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 手册中的“修改响应”部分。