深入理解 `WP_Comment_Query` 类的源码,解释它是如何构建评论查询的。

各位观众老爷们,大家好!我是今天的主讲人,咱们今天就来聊聊WordPress里那个神秘又强大的 WP_Comment_Query 类,看看它到底是怎么构建评论查询的。准备好了吗?那咱们就开始吧!

一、 什么是 WP_Comment_Query

简单来说,WP_Comment_Query 就是 WordPress 提供的一个专门用来查询评论的类。你可能觉得直接用 get_comments() 函数就行了,但 WP_Comment_Query 更加灵活,可以让你更精细地控制评论查询的条件和结果。它封装了复杂的 SQL 查询逻辑,让你不用直接写 SQL 语句就能搞定各种评论查询需求。

二、WP_Comment_Query 的构造函数:一切的起点

我们先从 WP_Comment_Query 类的构造函数入手,看看它都做了些什么:

/**
 * Constructor.
 *
 * @param string|array $query Optional. Array or string of Query parameters. See {@see WP_Comment_Query::parse_query()}
 *                            for information on accepted arguments.
 */
public function __construct( $query = '' ) {
    $this->query = wp_parse_args( $query ); // 将传入的查询参数转换为数组
    $this->query_vars_hash = md5( serialize( $this->query ) ); // 生成查询参数的哈希值,用于缓存
    $this->parse_query( $this->query ); // 解析查询参数
    $this->get_comments(); // 执行查询
}

这段代码看起来是不是很简单?但它做了三件重要的事情:

  1. wp_parse_args():参数标准化

    wp_parse_args() 函数的作用是将传入的查询参数(可以是字符串或数组)转换为一个标准的数组。如果传入的是字符串,它会尝试将其解析为键值对。这样做的目的是为了方便后续的参数处理。

    $defaults = array(
        'number' => '20',
        'offset' => '0',
        'orderby' => 'comment_date',
        'order' => 'DESC',
        // ... 其他默认参数
    );
    
    $this->query = wp_parse_args( $query, $defaults );

    wp_parse_args() 会将用户传入的参数与默认参数合并,确保所有必要的参数都有值。

  2. md5(serialize()):生成查询哈希值

    为什么要生成查询参数的哈希值呢?答案是:为了缓存!WordPress 会根据这个哈希值来判断是否已经执行过相同的查询,如果已经执行过,就可以直接从缓存中获取结果,避免重复查询数据库,提高性能。

  3. parse_query():解析查询参数

    这是最关键的一步,parse_query() 函数负责解析查询参数,并将它们转换为 SQL 查询语句中使用的条件。

  4. get_comments():执行查询

    根据解析后的查询参数,执行SQL语句,获取评论数据。

三、parse_query():SQL 构建的核心

parse_query() 函数是 WP_Comment_Query 类的核心,它负责将查询参数转换为 SQL 查询语句。让我们深入了解一下它的工作原理。

/**
 * Parse arguments passed to the comment query with wp_parse_args() and fill
 * unavailable query parameters.
 *
 * @param string|array $query Array of query parameters.
 */
public function parse_query( $query = '' ) {
    // 1. 初始化查询变量
    $this->query_vars = wp_parse_args( $query, $this->query_vars );

    // 2. 处理各种查询参数
    $this->comment__in       = wp_parse_id_list( $this->query_vars['comment__in'] );
    $this->comment__not_in   = wp_parse_id_list( $this->query_vars['comment__not_in'] );
    $this->hierarchical      = $this->query_vars['hierarchical'];
    $this->number            = absint( $this->query_vars['number'] );
    $this->offset            = absint( $this->query_vars['offset'] );
    $this->paged             = absint( $this->query_vars['paged'] );
    $this->count             = (bool) $this->query_vars['count'];
    $this->no_found_rows     = (bool) $this->query_vars['no_found_rows'];
    $this->orderby           = $this->query_vars['orderby'];
    $this->order             = $this->query_vars['order'];
    $this->search            = $this->query_vars['search'];
    $this->status            = $this->query_vars['status'];
    $this->approve           = $this->query_vars['approve'];
    $this->author__in        = wp_parse_id_list( $this->query_vars['author__in'] );
    $this->author__not_in    = wp_parse_id_list( $this->query_vars['author__not_in'] );
    $this->post_id           = absint( $this->query_vars['post_id'] );
    $this->post__in          = wp_parse_id_list( $this->query_vars['post__in'] );
    $this->post__not_in      = wp_parse_id_list( $this->query_vars['post__not_in'] );
    $this->parent            = $this->query_vars['parent'];
    $this->parent__in        = wp_parse_id_list( $this->query_vars['parent__in'] );
    $this->parent__not_in    = wp_parse_id_list( $this->query_vars['parent__not_in'] );
    $this->fields            = $this->query_vars['fields'];
    $this->name              = $this->query_vars['name'];
    $this->email             = $this->query_vars['email'];
    $this->url               = $this->query_vars['url'];
    $this->comment_author    = $this->query_vars['comment_author'];
    $this->comment_author_email = $this->query_vars['comment_author_email'];
    $this->comment_author_url   = $this->query_vars['comment_author_url'];
    $this->comment_author_IP    = $this->query_vars['comment_author_IP'];
    $this->date_query        = $this->query_vars['date_query'];
    $this->meta_query        = $this->query_vars['meta_query'];
    $this->type              = $this->query_vars['type'];
    $this->type__in          = $this->query_vars['type__in'];
    $this->type__not_in      = $this->query_vars['type__not_in'];
    $this->include_unapproved = $this->query_vars['include_unapproved'];
    $this->user_id           = $this->query_vars['user_id'];
    $this->callback          = $this->query_vars['callback'];
    $this->walker            = $this->query_vars['walker'];

    // 3. 过滤查询参数
    $this->query_vars = apply_filters( 'comments_clauses', $this->query_vars, $this );
    $this->query_vars = apply_filters( 'comments_clauses_request', $this->query_vars, $this );
}

这个函数的主要工作是:

  1. 初始化查询变量: 将传入的参数与默认参数合并,确保所有必要的参数都有值。
  2. 处理各种查询参数: 对各种查询参数进行处理,例如将 comment__in 参数转换为整数数组,将 number 参数转换为整数等等。
  3. 过滤查询参数: 使用 apply_filters() 函数对查询参数进行过滤,允许其他插件或主题修改查询参数。

四、get_comments():构建 SQL 查询语句并执行

get_comments() 函数是 WP_Comment_Query 类中真正执行查询的地方。它会根据解析后的查询参数构建 SQL 查询语句,并执行该语句,然后返回查询结果。

/**
 * Retrieve comments matching the current query vars.
 *
 * @since 3.1.0
 *
 * @global wpdb $wpdb WordPress database abstraction object.
 *
 * @return array|int List of comments, or number of comments when 'count' is passed as a query var.
 */
public function get_comments() {
    global $wpdb;

    $comments = array();

    /**
     * Fires before comments query is run.
     *
     * @since 5.1.0
     *
     * @param WP_Comment_Query $this The WP_Comment_Query instance (passed by reference).
     */
    do_action_ref_array( 'pre_get_comments', array( &$this ) );

    /**
     * Filters the comments query clauses.
     *
     * @since 3.1.0
     *
     * @param array            $clauses   Empty array.
     * @param WP_Comment_Query $this The WP_Comment_Query instance (passed by reference).
     */
    $clauses = apply_filters_ref_array( 'comments_clauses', array( array(), &$this ) );

    $where = ! empty( $clauses['where'] ) ? 'WHERE 1=1 ' . $clauses['where'] : '';
    $join  = ! empty( $clauses['join'] ) ? $clauses['join'] : '';
    $orderby = ! empty( $clauses['orderby'] ) ? 'ORDER BY ' . $clauses['orderby'] : '';
    $limits  = ! empty( $clauses['limits'] ) ? 'LIMIT ' . $clauses['limits'] : '';

    $fields = isset( $clauses['fields'] ) ? $clauses['fields'] : '*';

    $this->sql_clauses = compact( 'fields', 'join', 'where', 'orderby', 'limits' );

    if ( $this->count ) {
        $found_comments = (int) $wpdb->get_var( "SELECT COUNT( DISTINCT {$wpdb->comments}.comment_ID ) FROM {$wpdb->comments} {$join} {$where}" );

        /**
         * Filters the found comments query.
         *
         * @since 3.1.0
         *
         * @param string           $found_comments_query The complete COUNT query.
         * @param WP_Comment_Query $this The WP_Comment_Query instance (passed by reference).
         */
        $found_comments_query = apply_filters( 'found_comments_query', "SELECT COUNT( DISTINCT {$wpdb->comments}.comment_ID ) FROM {$wpdb->comments} {$join} {$where}", $this );

        /**
         * Filters the total number of found comments for the query.
         *
         * @since 3.1.0
         *
         * @param int              $found_comments The total number of comments found.
         * @param WP_Comment_Query $this The WP_Comment_Query instance (passed by reference).
         */
        return apply_filters( 'found_comments', $found_comments, $this );
    }

    $this->request = "SELECT {$fields} FROM {$wpdb->comments} {$join} {$where} {$orderby} {$limits}";

    $comments = $wpdb->get_results( $this->request );

    return $comments;
}

这个函数的主要步骤如下:

  1. 构建 SQL 查询语句: 根据解析后的查询参数,构建 SQL 查询语句的各个部分,例如 WHERE 子句、JOIN 子句、ORDER BY 子句和 LIMIT 子句等等。
  2. 执行 SQL 查询语句: 使用 $wpdb->get_results() 函数执行 SQL 查询语句,并获取查询结果。
  3. 返回查询结果: 将查询结果封装成一个数组,并返回该数组。

五、WP_Comment_Query 的核心参数

WP_Comment_Query 支持很多查询参数,下面列出一些常用的参数:

参数 类型 描述
comment__in array 只获取指定 ID 的评论。
comment__not_in array 排除指定 ID 的评论。
number int 获取的评论数量。
offset int 偏移量,用于分页。
orderby string 排序字段,例如 comment_datecomment_ID 等。
order string 排序方式,ASC(升序)或 DESC(降序)。
status string 评论状态,approve(已审核)、hold(待审核)、spam(垃圾评论)等。
post_id int 只获取指定文章的评论。
post__in array 只获取指定文章 ID 列表的评论。
post__not_in array 排除指定文章 ID 列表的评论。
author__in array 只获取指定作者 ID 列表的评论。
author__not_in array 排除指定作者 ID 列表的评论。
date_query array 日期查询参数,可以根据日期范围过滤评论。
meta_query array 元数据查询参数,可以根据评论元数据过滤评论。
type string 评论类型,例如 commenttrackbackpingback 等。
type__in array 只获取指定评论类型列表的评论。
type__not_in array 排除指定评论类型列表的评论。
search string 搜索评论内容。

六、使用 WP_Comment_Query 的例子

说了这么多,不如来几个实际的例子,让你更直观地了解 WP_Comment_Query 的用法。

例子 1:获取指定文章的最新 10 条评论

$args = array(
    'post_id' => 123, // 文章 ID
    'number'  => 10,
    'orderby' => 'comment_date',
    'order'   => 'DESC',
);

$comments_query = new WP_Comment_Query( $args );
$comments = $comments_query->get_comments();

if ( $comments ) {
    foreach ( $comments as $comment ) {
        echo '<p>' . $comment->comment_content . '</p>';
    }
} else {
    echo 'No comments found.';
}

例子 2:获取所有待审核的评论

$args = array(
    'status' => 'hold', // 待审核
);

$comments_query = new WP_Comment_Query( $args );
$comments = $comments_query->get_comments();

if ( $comments ) {
    foreach ( $comments as $comment ) {
        echo '<p>' . $comment->comment_content . '</p>';
    }
} else {
    echo 'No comments found.';
}

例子 3:使用 date_query 获取指定日期范围的评论

$args = array(
    'date_query' => array(
        array(
            'after'     => '2023-01-01',
            'before'    => '2023-01-31',
            'inclusive' => true, // 包含开始和结束日期
        ),
    ),
);

$comments_query = new WP_Comment_Query( $args );
$comments = $comments_query->get_comments();

if ( $comments ) {
    foreach ( $comments as $comment ) {
        echo '<p>' . $comment->comment_content . '</p>';
    }
} else {
    echo 'No comments found.';
}

例子 4:使用 meta_query 获取指定元数据的评论

$args = array(
    'meta_query' => array(
        array(
            'key'   => 'rating',
            'value' => '5',
            'compare' => '=',
            'type' => 'NUMERIC',
        ),
    ),
);

$comments_query = new WP_Comment_Query( $args );
$comments = $comments_query->get_comments();

if ( $comments ) {
    foreach ( $comments as $comment ) {
        echo '<p>' . $comment->comment_content . '</p>';
    }
} else {
    echo 'No comments found.';
}

七、WP_Comment_Queryget_comments() 的区别

你可能会问,既然有了 WP_Comment_Query,那 get_comments() 还有什么用呢?

其实 get_comments() 函数内部也是使用 WP_Comment_Query 类来实现的。get_comments() 函数是一个更简单的封装,它接受一个参数数组,然后将其传递给 WP_Comment_Query 类的构造函数。

WP_Comment_Query 更加灵活,可以直接访问其属性和方法,可以更精细地控制查询过程。如果你需要更复杂的评论查询需求,建议使用 WP_Comment_Query 类。

八、总结

WP_Comment_Query 类是 WordPress 提供的一个强大而灵活的评论查询工具。通过深入理解它的源码和参数,你可以轻松地构建各种复杂的评论查询需求。

希望今天的讲座能帮助你更好地理解 WP_Comment_Query 类。如果你还有任何问题,欢迎提问!感谢大家的收听!下次再见!

发表回复

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