详解 WordPress `rest_prepare_post` 过滤器源码:如何修改文章返回的 REST API 数据。

大家好,欢迎来到今天的“WordPress REST API 魔改小课堂”。我是你们今天的导游,将带大家深入挖掘 rest_prepare_post 过滤器,看看它如何成为你定制 WordPress REST API 文章数据的秘密武器。

今天我们要聊的是: “如何用 rest_prepare_post 把 WordPress REST API 变成你的游乐场”

准备好了吗? 系好安全带,咱们发车!

一、 什么是 rest_prepare_post

想象一下,WordPress REST API 就像一家餐厅,它会根据你的要求(API 请求)给你提供菜品(数据)。而 rest_prepare_post 过滤器,就像是你在后厨安插的一个“间谍”,可以在菜品端上桌前,偷偷地给它加点盐,撒点辣椒,或者干脆换个摆盘,让它更符合你的口味。

更正式地说,rest_prepare_post 是 WordPress 提供的一个过滤器,允许你在文章数据通过 REST API 返回之前,对其进行修改。它会在 WP_REST_Posts_Controller::prepare_item_for_response() 方法中被调用。这个方法负责将数据库中的文章数据转换为 REST API 可以返回的格式。

二、 rest_prepare_post 的基本用法

要使用 rest_prepare_post,你需要创建一个函数,并将其挂载到这个过滤器上。这个函数会接收两个参数:

  • $response: WP_REST_Response 对象,包含了准备返回的 REST API 数据。
  • $post: WP_Post 对象,代表了正在处理的文章。
  • $request: WP_REST_Request 对象,代表了当前的 API 请求。

你的函数需要返回修改后的 $response 对象。

这是一个最简单的例子:

<?php
/**
 * 在文章 REST API 响应中添加一个自定义字段。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post( $response, $post, $request ) {
  $response->data['custom_field'] = 'Hello from rest_prepare_post!';
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post', 10, 3 );

这段代码做了什么? 它往每个文章的 REST API 响应里添加了一个名为 custom_field 的字段,其值为 "Hello from rest_prepare_post!"。 简单粗暴,一目了然。

三、 深入 WP_REST_Response 对象

要玩转 rest_prepare_post,你必须熟悉 WP_REST_Response 对象。它就像一个容器,里面装着要返回的 REST API 数据。

WP_REST_Response 对象有以下几个关键的属性和方法:

属性/方法 描述 示例
$data 一个数组,包含了主要的 REST API 数据。 这是你最常修改的部分。 $response->data['title'] = 'New Title';
$status HTTP 状态码。 默认为 200 (OK)。 $response->set_status(404);
$headers HTTP 头部信息。 $response->header('X-Custom-Header', 'Custom Value');
get_data() 获取 $data 属性的值。 $data = $response->get_data();
set_data() 设置 $data 属性的值。 $response->set_data(['title' => 'New Title']);
add_link() 添加一个链接到响应的 _links 属性中。 这对于构建 HATEOAS (Hypermedia as the Engine of Application State) 风格的 API 非常有用。 $response->add_link('related', 'https://example.com/api/related');

四、 实战演练:魔改文章数据

现在,让我们来做一些更有趣的事情。

1. 添加作者的头像 URL

WordPress 默认的 REST API 不包含作者的头像 URL。 我们可以用 rest_prepare_post 轻松地添加它。

<?php
/**
 * 在文章 REST API 响应中添加作者头像 URL。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post_add_author_avatar( $response, $post, $request ) {
  $author_id = $post->post_author;
  $avatar_url = get_avatar_url( $author_id );
  $response->data['author_avatar_url'] = $avatar_url;
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post_add_author_avatar', 10, 3 );

这段代码获取了文章的作者 ID,然后使用 get_avatar_url() 函数获取作者的头像 URL,最后将其添加到响应的 author_avatar_url 字段中。

2. 自定义文章摘要

WordPress 默认的摘要可能不符合你的需求。 你可以使用 rest_prepare_post 来修改它。

<?php
/**
 * 自定义文章摘要。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post_custom_excerpt( $response, $post, $request ) {
  $excerpt = wp_trim_words( strip_tags( $post->post_content ), 20, '...' );
  $response->data['excerpt']['rendered'] = $excerpt;
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post_custom_excerpt', 10, 3 );

这段代码从文章内容中提取文本,然后使用 wp_trim_words() 函数截取前 20 个词,并添加省略号。 最后,它将修改后的摘要设置为响应的 excerpt.rendered 字段。 注意,我们修改的是 excerpt.rendered,而不是直接修改 excerpt 字段,因为 excerpt 字段是一个数组,包含 rendered (渲染后的摘要) 和 protected (是否受保护) 两个属性。

3. 根据分类添加自定义字段

有时候,你可能想根据文章所属的分类添加不同的自定义字段。

<?php
/**
 * 根据分类添加自定义字段。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post_add_field_by_category( $response, $post, $request ) {
  $categories = wp_get_post_categories( $post->ID );
  if ( in_array( 1, $categories ) ) { // 如果文章属于分类 ID 为 1 的分类
    $response->data['category_specific_field'] = 'This is a field for category 1';
  } elseif ( in_array( 2, $categories ) ) { // 如果文章属于分类 ID 为 2 的分类
    $response->data['category_specific_field'] = 'This is a field for category 2';
  }
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post_add_field_by_category', 10, 3 );

这段代码首先获取文章所属的分类 ID,然后根据不同的分类 ID 添加不同的自定义字段。

4. 添加自定义字段(使用 ACF 插件)

如果你使用了 Advanced Custom Fields (ACF) 插件,你可以使用 rest_prepare_post 来轻松地添加 ACF 字段到 REST API 响应中。

<?php
/**
 * 添加 ACF 字段到文章 REST API 响应中。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post_add_acf_fields( $response, $post, $request ) {
  $response->data['my_acf_field'] = get_field( 'my_acf_field', $post->ID ); // 替换 'my_acf_field' 为你的 ACF 字段名称
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post_add_acf_fields', 10, 3 );

这段代码使用 get_field() 函数获取 ACF 字段的值,并将其添加到响应中。 请确保将 'my_acf_field' 替换为你实际的 ACF 字段名称。

五、 高级技巧:处理不同的 API 请求

有时候,你可能需要根据不同的 API 请求修改不同的数据。 例如,你可能想在获取单个文章时返回更多的数据,而在获取文章列表时返回较少的数据。

你可以使用 $request 对象来判断当前的 API 请求类型。

<?php
/**
 * 根据不同的 API 请求修改数据。
 *
 * @param WP_REST_Response $response REST API 响应对象。
 * @param WP_Post          $post     文章对象。
 * @param WP_REST_Request  $request  REST API 请求对象。
 *
 * @return WP_REST_Response 修改后的 REST API 响应对象。
 */
function my_custom_rest_prepare_post_conditional( $response, $post, $request ) {
  if ( isset( $request['id'] ) ) { // 如果请求包含了 'id' 参数,说明是获取单个文章
    $response->data['full_content'] = apply_filters( 'the_content', $post->post_content );
  } else { // 否则,说明是获取文章列表
    $response->data['short_excerpt'] = wp_trim_words( strip_tags( $post->post_content ), 10, '...' );
  }
  return $response;
}
add_filter( 'rest_prepare_post', 'my_custom_rest_prepare_post_conditional', 10, 3 );

这段代码检查请求中是否包含了 id 参数。 如果包含了,就说明是获取单个文章,然后将完整的文章内容添加到响应中。 否则,就说明是获取文章列表,然后将简短的摘要添加到响应中。

六、 调试技巧

当你的 rest_prepare_post 代码出现问题时,调试可能会比较困难。 以下是一些有用的调试技巧:

  1. 使用 error_log() 函数: 在你的代码中插入 error_log() 函数,将变量的值输出到 PHP 错误日志中。 例如:error_log( print_r( $response, true ) ); 可以打印整个 $response 对象。
  2. 使用 WP_DEBUG: 在 wp-config.php 文件中启用 WP_DEBUG 常量,可以显示 PHP 错误和警告。
  3. 使用 REST API 客户端: 使用 Postman 或 Insomnia 等 REST API 客户端来发送 API 请求,并查看响应数据。 这可以帮助你确定哪些数据被修改了,哪些数据没有被修改。
  4. 逐步调试: 逐步添加代码,并每次添加后都测试你的 API。 这可以帮助你快速定位问题所在。

七、 注意事项

  1. 性能: rest_prepare_post 会在每个文章的 REST API 响应之前被调用。 因此,请确保你的代码执行效率高,避免影响 API 的性能。
  2. 兼容性: 确保你的代码与 WordPress 的最新版本兼容。
  3. 安全性: 不要在 rest_prepare_post 中执行任何不安全的操作,例如直接执行 SQL 查询。
  4. 冲突: 如果你的主题或插件也使用了 rest_prepare_post 过滤器,可能会发生冲突。 请注意调整你的过滤器的优先级,以确保你的代码能够按预期执行。

八、 总结

rest_prepare_post 过滤器是一个强大的工具,可以让你定制 WordPress REST API 的文章数据。 通过理解 WP_REST_Response 对象,并结合实际的例子,你可以轻松地添加自定义字段,修改文章摘要,甚至根据不同的 API 请求修改不同的数据。

希望今天的课程对你有所帮助。 下次再见!

附录:一些常用函数

函数名 描述 示例
get_post_meta() 获取文章的自定义字段值。 $meta_value = get_post_meta( $post->ID, 'my_meta_key', true );
get_the_terms() 获取文章的分类术语或标签术语。 $terms = get_the_terms( $post->ID, 'category' );
wp_get_attachment_url() 获取附件的 URL。 $image_url = wp_get_attachment_url( get_post_thumbnail_id( $post->ID ) );
apply_filters( 'the_content', $post->post_content ) 应用 the_content 过滤器,对文章内容进行格式化 (例如,应用自动段落)。 通常用于在 REST API 中返回格式化后的文章内容。
get_permalink() 获取文章的永久链接 $permalink = get_permalink($post->ID);

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注