解析 WordPress `rest_prepare_post` 过滤器源码:如何在 REST API 响应中添加自定义字段或修改现有数据。

各位观众老爷们,大家好!我是今天的主讲人,咱们今天来聊聊WordPress REST API 中一个非常重要的过滤器:rest_prepare_post。 相信大家在使用WordPress REST API 的时候,肯定遇到过这样的需求:想在API返回的数据中,添加一些WordPress默认没有提供的字段,或者想修改一下现有的字段内容。 那么,rest_prepare_post 就是解决这类问题的利器。

一、什么是 rest_prepare_post 过滤器?

首先,rest_prepare_post 是一个过滤器,它是WordPress在准备好文章(Post)类型的 REST API 响应数据之后,但在最终返回数据之前触发的。 简单来说,你可以把它理解为“数据加工厂”的最后一道工序,你可以在这里对数据进行“精装修”,添加你想要的“家具”,或者修改一些“装修风格”。

二、rest_prepare_post 过滤器的工作原理

当 WordPress REST API 需要返回一个文章类型的资源时(比如通过 /wp/v2/posts 获取文章列表,或者通过 /wp/v2/posts/{id} 获取单个文章),它会经过一系列的处理流程。 在这个流程的最后阶段,WordPress 会使用 apply_filters() 函数来应用 rest_prepare_post 过滤器。

apply_filters( 'rest_prepare_post', $response, $post, $request );

可以看到,这个过滤器接收三个参数:

  • $response:一个 WP_REST_Response 对象,包含了即将返回给客户端的全部数据。 你可以在这里添加、修改或删除数据。
  • $post:一个 WP_Post 对象,代表当前正在处理的文章。 你可以从这个对象中获取文章的各种属性,比如标题、内容、作者等等。
  • $request:一个 WP_REST_Request 对象,包含了客户端发送的请求信息,比如请求的参数、请求的头部等等。 你可以根据请求的信息来决定如何修改数据。

过滤器函数必须返回修改后的 $response 对象。

三、实战演练:添加自定义字段

废话不多说,直接上代码,演示如何在 REST API 响应中添加自定义字段。

场景1:添加文章阅读量

假设我们使用了一个插件或者自定义代码来记录文章的阅读量,并将阅读量存储在文章的自定义字段(meta field)中,字段名为 post_views。现在我们想把这个阅读量添加到 REST API 的响应中。

<?php
/**
 * 添加文章阅读量到 REST API 响应
 *
 * @param WP_REST_Response $response REST 响应对象.
 * @param WP_Post          $post     文章对象.
 * @param WP_REST_Request  $request  请求对象.
 *
 * @return WP_REST_Response 修改后的 REST 响应对象.
 */
function add_post_views_to_rest_response( $response, $post, $request ) {
    // 获取文章阅读量
    $post_views = get_post_meta( $post->ID, 'post_views', true );

    // 确保阅读量是一个数字
    $post_views = intval( $post_views );

    // 将阅读量添加到响应数据中
    $response->data['post_views'] = $post_views;

    return $response;
}
add_filter( 'rest_prepare_post', 'add_post_views_to_rest_response', 10, 3 );

这段代码做了以下几件事:

  1. 定义了一个名为 add_post_views_to_rest_response 的函数,这个函数就是我们的过滤器函数。
  2. 使用 get_post_meta() 函数获取文章的阅读量。
  3. 使用 intval() 函数确保阅读量是一个整数。
  4. 将阅读量添加到 $response->data 数组中,键名为 post_views
  5. 使用 add_filter() 函数将我们的过滤器函数添加到 rest_prepare_post 过滤器中。 10 是优先级,3 是参数个数。

现在,当你通过 REST API 获取文章数据时,你会发现响应中多了一个 post_views 字段,它的值就是文章的阅读量。

场景2:添加作者头像 URL

有时候,我们希望在文章的 REST API 响应中包含作者的头像 URL。 这也很简单,可以这样做:

<?php
/**
 * 添加作者头像 URL 到 REST API 响应
 *
 * @param WP_REST_Response $response REST 响应对象.
 * @param WP_Post          $post     文章对象.
 * @param WP_REST_Request  $request  请求对象.
 *
 * @return WP_REST_Response 修改后的 REST 响应对象.
 */
function add_author_avatar_url_to_rest_response( $response, $post, $request ) {
    // 获取作者 ID
    $author_id = $post->post_author;

    // 获取作者头像 URL
    $author_avatar_url = get_avatar_url( $author_id, array( 'size' => 96 ) ); // 96 是头像大小

    // 将作者头像 URL 添加到响应数据中
    $response->data['author_avatar_url'] = $author_avatar_url;

    return $response;
}
add_filter( 'rest_prepare_post', 'add_author_avatar_url_to_rest_response', 10, 3 );

这段代码与上面的例子类似,只是获取的数据不同,使用了 get_avatar_url() 函数来获取作者的头像 URL。

四、实战演练:修改现有字段

除了添加自定义字段,我们还可以使用 rest_prepare_post 过滤器来修改现有的字段。

场景:修改文章标题

假设我们想在 REST API 响应中,将文章标题加上一个前缀 "[Modified]"。

<?php
/**
 * 修改文章标题
 *
 * @param WP_REST_Response $response REST 响应对象.
 * @param WP_Post          $post     文章对象.
 * @param WP_REST_Request  $request  请求对象.
 *
 * @return WP_REST_Response 修改后的 REST 响应对象.
 */
function modify_post_title( $response, $post, $request ) {
    // 获取原始标题
    $original_title = $response->data['title']['rendered'];

    // 添加前缀
    $modified_title = '[Modified] ' . $original_title;

    // 修改标题
    $response->data['title']['rendered'] = $modified_title;

    return $response;
}
add_filter( 'rest_prepare_post', 'modify_post_title', 10, 3 );

注意,文章标题是一个嵌套的数组,我们需要修改 title['rendered'] 字段。

五、根据请求参数进行条件修改

$request 对象包含了客户端发送的请求信息,我们可以根据这些信息来决定如何修改数据。

场景:只在请求包含 show_views=true 参数时才显示阅读量

<?php
/**
 * 根据请求参数显示阅读量
 *
 * @param WP_REST_Response $response REST 响应对象.
 * @param WP_Post          $post     文章对象.
 * @param WP_REST_Request  $request  请求对象.
 *
 * @return WP_REST_Response 修改后的 REST 响应对象.
 */
function conditionally_add_post_views( $response, $post, $request ) {
    // 获取请求参数
    $params = $request->get_params();

    // 检查是否包含 show_views 参数且值为 true
    if ( isset( $params['show_views'] ) && $params['show_views'] === 'true' ) {
        // 获取文章阅读量
        $post_views = get_post_meta( $post->ID, 'post_views', true );
        $post_views = intval( $post_views );

        // 添加阅读量到响应数据中
        $response->data['post_views'] = $post_views;
    }

    return $response;
}
add_filter( 'rest_prepare_post', 'conditionally_add_post_views', 10, 3 );

现在,只有当客户端发送 GET /wp/v2/posts?show_views=true 请求时,才会显示 post_views 字段。

六、处理不同类型的请求

$request 对象还可以区分不同的请求类型,比如 GETPOSTPUTDELETE 等等。 你可以使用 $request->get_method() 方法来获取请求类型。

七、代码组织和最佳实践

  • 插件化: 将你的过滤器函数放在一个插件中,方便管理和维护。
  • 代码注释: 编写清晰的代码注释,方便自己和他人理解代码。
  • 错误处理: 考虑各种可能的错误情况,并进行适当的处理。
  • 性能优化: 避免在过滤器函数中执行耗时的操作,以免影响 API 的性能。
  • 使用命名空间: 为了避免与其他插件或主题的代码冲突,可以使用命名空间。

八、常见问题

  • 过滤器不生效: 检查你的过滤器函数是否正确地添加到了 rest_prepare_post 过滤器中,以及优先级是否设置正确。
  • 数据格式错误: 确保你添加的数据格式符合 REST API 的规范。
  • 性能问题: 如果你的过滤器函数执行了耗时的操作,可能会导致 API 的性能下降。 尽量避免在过滤器函数中执行复杂的逻辑。

九、总结

rest_prepare_post 过滤器是一个非常强大的工具,它可以让你轻松地定制 WordPress REST API 的响应数据。 通过它可以添加自定义字段、修改现有字段,甚至可以根据请求参数进行条件修改。 掌握了 rest_prepare_post 过滤器,你就可以更加灵活地使用 WordPress REST API,满足各种各样的需求。

希望今天的分享对大家有所帮助,如果有什么问题,欢迎在评论区留言。 感谢大家的观看!

附:常用函数和对象

函数/对象 描述 示例
get_post_meta() 获取文章的自定义字段值。 $post_views = get_post_meta( $post->ID, 'post_views', true );
get_avatar_url() 获取用户的头像 URL。 $author_avatar_url = get_avatar_url( $author_id, array( 'size' => 96 ) );
$response->data 包含 REST API 响应数据的数组。 可以通过修改这个数组来添加、修改或删除数据。 $response->data['post_views'] = $post_views;
$post WP_Post 对象,代表当前正在处理的文章。 可以从中获取文章的各种属性。 $author_id = $post->post_author;
$request WP_REST_Request 对象,包含了客户端发送的请求信息。 可以从中获取请求的参数、头部等等。 $params = $request->get_params();
$request->get_method() 获取 HTTP 请求方法 (GET, POST, PUT, DELETE 等). if ( 'POST' === $request->get_method() ) { // Only do something on POST requests }

示例代码整合

<?php
/**
 * 增强 REST API 文章响应.
 */
add_filter( 'rest_prepare_post', 'enhance_rest_api_post_response', 10, 3 );

function enhance_rest_api_post_response( $response, $post, $request ) {
    // 1. 添加文章阅读量 (仅当请求包含 show_views=true 时)
    $params = $request->get_params();
    if ( isset( $params['show_views'] ) && $params['show_views'] === 'true' ) {
        $post_views = get_post_meta( $post->ID, 'post_views', true );
        $post_views = intval( $post_views );
        $response->data['post_views'] = $post_views;
    }

    // 2. 添加作者头像 URL
    $author_id = $post->post_author;
    $author_avatar_url = get_avatar_url( $author_id, array( 'size' => 96 ) );
    $response->data['author_avatar_url'] = $author_avatar_url;

    // 3. 修改文章标题
    $original_title = $response->data['title']['rendered'];
    $modified_title = '[Enhanced] ' . $original_title;
    $response->data['title']['rendered'] = $modified_title;

    // 4. 添加自定义字段 "is_featured" (假设这个字段存在)
    $is_featured = get_post_meta( $post->ID, 'is_featured', true );
    $response->data['is_featured'] = (bool) $is_featured; // 转换为布尔值

    // 5. 根据请求方法进行不同的操作 (例如,只在 GET 请求时添加某些字段)
    if ( 'GET' === $request->get_method() ) {
        $response->data['request_type'] = 'GET Request';
    } else {
        $response->data['request_type'] = 'Not a GET Request';
    }

    return $response;
}

这个整合的示例演示了如何在一个过滤器函数中完成多个任务,包括添加自定义字段、修改现有字段以及根据请求参数和请求方法进行条件修改。 记得把示例代码放到你的主题的 functions.php 文件或者一个自定义插件中。

最后,祝大家编程愉快,bug 永不相见!

发表回复

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