分析 WordPress `rest_post_query` 过滤器源码:如何修改 REST API 的文章查询。

大家好!今天我们来聊聊 WordPress REST API 的 rest_post_query 过滤器,看看如何像个魔法师一样,修改 REST API 返回的文章查询结果。别怕,这玩意儿没那么神秘,咱们一步一步来,保证让你学会。

开场白:REST API 和文章查询的那些事儿

想象一下,WordPress 的 REST API 就像一个邮递员,专门负责传递信息。你问它:“嘿,邮递员,给我最近发布的 10 篇文章!” 它屁颠屁颠地跑到数据库里,把文章找出来,然后用 JSON 格式打包好,再给你送过来。

但是,有时候你可能对邮递员说:“等等!别急着送,我需要你先检查一下包裹,把标题里包含‘秘密’的文章过滤掉,或者把文章按照发布时间倒序排列。” 这时候,rest_post_query 过滤器就派上用场了。它就像一个中间人,允许你在邮递员(REST API)把文章送给你之前,先拦截一下,然后修改查询条件。

rest_post_query 过滤器:拯救世界的超级英雄

rest_post_query 过滤器本质上是一个钩子(Hook),它允许你在 REST API 处理文章查询之前,插入你自己的代码。它的作用是修改 $query 对象,这个 $query 对象包含了所有用于查询文章的参数,比如文章类型、状态、排序方式等等。

rest_post_query 过滤器的参数

rest_post_query 过滤器接收两个参数:

  1. $query: WP_Query 对象,包含了所有文章查询的参数。
  2. $request: WP_REST_Request 对象,包含了客户端发送的请求信息,比如 URL 参数、请求方法等等。

实战演练:用 rest_post_query 过滤器做点儿有趣的事情

接下来,咱们通过几个具体的例子,来看看如何使用 rest_post_query 过滤器。

例子 1:只显示“秘密”分类下的文章

假设你只想让 REST API 返回“秘密”分类下的文章,怎么办呢?很简单,只需要在你的主题的 functions.php 文件或者自定义插件中添加以下代码:

<?php
/**
 * 修改 REST API 文章查询,只显示“秘密”分类下的文章
 *
 * @param WP_Query $query WP_Query 对象.
 * @param WP_REST_Request $request 请求对象.
 * @return WP_Query
 */
function my_custom_rest_post_query( $query, $request ) {
    // 获取请求的路由
    $route = $request->get_route();

    // 仅当请求是 /wp/v2/posts 时才应用修改
    if ( '/wp/v2/posts' === $route ) {
        // 获取“秘密”分类的 ID
        $secret_category_id = get_cat_ID( '秘密' ); // 请确保你的分类名称是“秘密”

        if ( $secret_category_id ) {
            // 修改 WP_Query 对象,只查询“秘密”分类下的文章
            $query->set( 'cat', $secret_category_id );
        } else {
            // 如果“秘密”分类不存在,可以输出一个错误信息
            // error_log( '“秘密”分类不存在!' );
            // 或者直接返回原始的查询对象,不进行修改
            return $query;
        }
    }

    return $query;
}
add_filter( 'rest_post_query', 'my_custom_rest_post_query', 10, 2 );

这段代码做了什么呢?

  • 首先,我们定义了一个名为 my_custom_rest_post_query 的函数,这个函数接收 $query$request 两个参数。
  • 然后,我们检查请求的路由是否是 /wp/v2/posts,确保只修改文章列表的查询。
  • 接着,我们获取“秘密”分类的 ID。请注意,你需要将 '秘密' 替换成你实际的分类名称。
  • 如果“秘密”分类存在,我们就修改 $query 对象,设置 cat 参数为“秘密”分类的 ID。这样,REST API 就只会返回“秘密”分类下的文章了。
  • 最后,我们使用 add_filter 函数将 my_custom_rest_post_query 函数添加到 rest_post_query 过滤器中。10 是优先级,2 是参数个数。

例子 2:按照标题长度排序文章

有时候,你可能想按照文章标题的长度来排序文章。这个稍微复杂一点,需要用到 posts_orderby 过滤器。

<?php
/**
 * 修改 REST API 文章查询,按照标题长度排序文章
 *
 * @param WP_Query $query WP_Query 对象.
 * @param WP_REST_Request $request 请求对象.
 * @return WP_Query
 */
function my_custom_rest_post_query_title_length( $query, $request ) {
    // 获取请求的路由
    $route = $request->get_route();

    // 仅当请求是 /wp/v2/posts 时才应用修改
    if ( '/wp/v2/posts' === $route ) {
        // 添加一个自定义的 orderby 参数
        add_filter( 'posts_orderby', 'my_custom_posts_orderby', 10, 2 );
        $query->set( 'orderby', 'title_length' );
    }

    return $query;
}
add_filter( 'rest_post_query', 'my_custom_rest_post_query_title_length', 10, 2 );

/**
 * 自定义 posts_orderby 过滤器,实现按照标题长度排序
 *
 * @param string $orderby SQL ORDER BY 子句.
 * @param WP_Query $query WP_Query 对象.
 * @return string
 */
function my_custom_posts_orderby( $orderby, $query ) {
    global $wpdb;

    if ( 'title_length' === $query->get( 'orderby' ) ) {
        $orderby = "LENGTH({$wpdb->posts}.post_title)";
    }

    return $orderby;
}

这段代码做了什么呢?

  • 首先,我们定义了一个名为 my_custom_rest_post_query_title_length 的函数,这个函数接收 $query$request 两个参数。
  • 然后,我们检查请求的路由是否是 /wp/v2/posts,确保只修改文章列表的查询。
  • 接着,我们使用 add_filter 函数将 my_custom_posts_orderby 函数添加到 posts_orderby 过滤器中。
  • 然后,我们设置 $query 对象的 orderby 参数为 'title_length'
  • my_custom_posts_orderby 函数中,我们判断 $query 对象的 orderby 参数是否是 'title_length'。如果是,我们就修改 $orderby 变量,使用 LENGTH({$wpdb->posts}.post_title) 来按照标题长度排序。

例子 3:根据自定义字段进行过滤

假设你有一个名为 _my_custom_field 的自定义字段,你想只显示这个字段的值为 secret 的文章。你可以这样做:

<?php
/**
 * 修改 REST API 文章查询,根据自定义字段进行过滤
 *
 * @param WP_Query $query WP_Query 对象.
 * @param WP_REST_Request $request 请求对象.
 * @return WP_Query
 */
function my_custom_rest_post_query_meta( $query, $request ) {
    // 获取请求的路由
    $route = $request->get_route();

    // 仅当请求是 /wp/v2/posts 时才应用修改
    if ( '/wp/v2/posts' === $route ) {
        $query->set( 'meta_key', '_my_custom_field' );
        $query->set( 'meta_value', 'secret' );
        $query->set( 'meta_compare', '=' ); // 可选,默认为 '='
    }

    return $query;
}
add_filter( 'rest_post_query', 'my_custom_rest_post_query_meta', 10, 2 );

这段代码很简单,就是设置 $query 对象的 meta_keymeta_valuemeta_compare 参数,来根据自定义字段进行过滤。

高级技巧:结合 URL 参数动态修改查询

有时候,你可能想根据 URL 参数来动态修改查询。比如,你希望用户可以通过 ?category=secret 来只显示“秘密”分类下的文章。

<?php
/**
 * 修改 REST API 文章查询,根据 URL 参数动态修改查询
 *
 * @param WP_Query $query WP_Query 对象.
 * @param WP_REST_Request $request 请求对象.
 * @return WP_Query
 */
function my_custom_rest_post_query_url_params( $query, $request ) {
    // 获取请求的路由
    $route = $request->get_route();

    // 仅当请求是 /wp/v2/posts 时才应用修改
    if ( '/wp/v2/posts' === $route ) {
        // 获取 URL 参数
        $category = $request->get_param( 'category' );

        if ( $category ) {
            // 获取分类的 ID
            $category_id = get_cat_ID( $category );

            if ( $category_id ) {
                // 修改 WP_Query 对象,只查询指定分类下的文章
                $query->set( 'cat', $category_id );
            }
        }
    }

    return $query;
}
add_filter( 'rest_post_query', 'my_custom_rest_post_query_url_params', 10, 2 );

这段代码做了什么呢?

  • 首先,我们使用 $request->get_param( 'category' ) 获取 URL 中的 category 参数。
  • 如果 category 参数存在,我们就获取分类的 ID。
  • 如果分类存在,我们就修改 $query 对象,设置 cat 参数为分类的 ID。

表格总结:WP_Query 对象常用的参数

参数名 描述 例子
post_type 指定文章类型。默认值为 post $query->set( 'post_type', 'page' ); // 只查询页面
post_status 指定文章状态。默认值为 publish $query->set( 'post_status', 'draft' ); // 只查询草稿状态的文章
posts_per_page 每页显示的文章数量。默认值为 get_option( 'posts_per_page' ) $query->set( 'posts_per_page', 5 ); // 每页显示 5 篇文章
orderby 指定排序方式。常用的值有 date(发布时间)、title(标题)、ID(文章 ID)等等。 $query->set( 'orderby', 'title' ); // 按照标题排序
order 指定排序顺序。ASC(升序)或 DESC(降序)。 $query->set( 'order', 'DESC' ); // 降序排列
cat 指定分类 ID。 $query->set( 'cat', 1 ); // 只查询 ID 为 1 的分类下的文章
tag_id 指定标签 ID。 $query->set( 'tag_id', 2 ); // 只查询 ID 为 2 的标签下的文章
s 搜索关键词。 $query->set( 's', '秘密' ); // 搜索包含“秘密”关键词的文章
meta_key 自定义字段的键名。 $query->set( 'meta_key', '_my_custom_field' ); // 指定自定义字段的键名为 _my_custom_field
meta_value 自定义字段的值。需要和 meta_key 配合使用。 $query->set( 'meta_value', 'secret' ); // 指定自定义字段的值为 secret
meta_compare 自定义字段的比较方式。常用的值有 =(等于)、!=(不等于)、>(大于)、<(小于)等等。 $query->set( 'meta_compare', '!=' ); // 指定自定义字段的值不等于 secret
author 指定作者ID。 $query->set( 'author', 1 ); // 只查询ID为 1 的作者的文章

注意事项:安全第一!

在使用 rest_post_query 过滤器时,一定要注意安全问题。特别是当根据 URL 参数来修改查询时,要对用户输入进行严格的验证和过滤,防止 SQL 注入等安全漏洞。

总结:rest_post_query 过滤器,你的 REST API 好帮手

rest_post_query 过滤器是一个非常强大的工具,可以让你灵活地修改 REST API 的文章查询。通过它,你可以实现各种各样的自定义功能,比如只显示特定分类下的文章、按照标题长度排序文章、根据自定义字段进行过滤等等。只要你掌握了它的用法,就能像个魔法师一样,掌控 REST API 的文章查询!

希望今天的讲座对你有所帮助。记住,编程就像变魔术,多练习才能成为真正的魔法师!

发表回复

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