分析 WordPress `get_terms()` 函数源码:与 `WP_Term_Query` 的关系及差异。

各位观众老爷们,大家好! 今天咱们来聊聊 WordPress 里一对有点暧昧,又有点说不清道不明的关系:get_terms() 函数和 WP_Term_Query 类。 它们都负责从数据库里捞分类法(Taxonomy)的词条(Terms)出来,但捞的方法,捞的东西,还有背后的逻辑,可差了十万八千里。 别担心,咱们今天就用最通俗易懂的方式,把它们扒个底朝天,让大家明明白白,以后用起来才能得心应手。

第一回合:初识两位主角

  • get_terms() 函数:WordPress 的老牌劲旅

    get_terms() 函数是 WordPress 的元老级函数,它在 WordPress 早期就存在了。 它的主要作用就是根据给定的参数,从数据库里获取指定的分类法(比如分类、标签)的词条列表。

    简单来说,你可以把它想象成一个经验丰富的老厨师,你告诉他你要什么菜(分类法),要什么口味(参数),他就能从厨房(数据库)里给你端出一盘你想要的菜(词条列表)。

    $terms = get_terms( array(
        'taxonomy' => 'category', // 获取分类
        'hide_empty' => true,   // 隐藏空分类
        'orderby' => 'name',      // 按名称排序
        'order'   => 'ASC'        // 升序
    ) );
    
    if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){
        echo '<ul>';
        foreach ( $terms as $term ) {
            echo '<li><a href="' . esc_url( get_term_link( $term ) ) . '">' . $term->name . '</a></li>';
        }
        echo '</ul>';
    }

    这段代码就是用 get_terms() 函数获取所有非空的分类,并按照名称升序排列,然后把它们以列表的形式展示出来。

  • WP_Term_Query 类:WordPress 的后起之秀

    WP_Term_Query 类是 WordPress 4.6 版本引入的,它是一个更加灵活和面向对象的方式来查询分类法词条。

    你可以把它想象成一个更加现代化的厨房,你不仅可以告诉厨师你要什么菜,要什么口味,还可以告诉他你要用什么锅,要用什么火候,甚至可以自己动手参与烹饪的过程。

    $args = array(
        'taxonomy' => 'post_tag', // 获取标签
        'hide_empty' => false,  // 显示空标签
        'orderby' => 'count',     // 按文章数量排序
        'order'   => 'DESC',      // 降序
        'number'  => 5           // 只获取前5个
    );
    
    $term_query = new WP_Term_Query( $args );
    
    if ( ! empty( $term_query->terms ) ) {
        echo '<ul>';
        foreach ( $term_query->terms as $term ) {
            echo '<li><a href="' . esc_url( get_term_link( $term ) ) . '">' . $term->name . '</a></li>';
        }
        echo '</ul>';
    }

    这段代码就是用 WP_Term_Query 类获取文章数量最多的前 5 个标签,并按照文章数量降序排列,然后把它们以列表的形式展示出来。

第二回合:深入对比,揭秘差异

特性 get_terms() WP_Term_Query
返回值 词条对象数组或 WP_Error 对象 一个 WP_Term_Query 对象,词条在 terms 属性中
参数传递方式 数组 数组
灵活性 相对较低,参数有限 较高,支持更复杂的查询参数和钩子
性能 在简单查询中可能更快 在复杂查询中可能更有效率,因为支持缓存
钩子 支持的钩子较少 支持更多的钩子,方便自定义查询行为
对象导向 非对象导向 对象导向
缓存 有缓存机制,但不如 WP_Term_Query 精细 有更精细的缓存机制,可以更好地利用 WordPress 的对象缓存
适用场景 简单查询,需要快速获取词条列表 复杂查询,需要更多的控制和自定义

接下来,咱们就针对表格里的几个关键点,进行更深入的探讨:

  1. 返回值:不仅是数据,更是姿势

    get_terms() 函数直接返回一个词条对象数组,或者在出错的时候返回一个 WP_Error 对象。 拿到数据之后,你就可以直接用了。

    $terms = get_terms( 'category' );
    
    if ( ! is_wp_error( $terms ) ) {
        foreach ( $terms as $term ) {
            // 直接访问 $term 的属性,比如 $term->name, $term->slug
        }
    }

    WP_Term_Query 类返回的是一个 WP_Term_Query 对象。 你需要访问这个对象的 terms 属性才能拿到词条数组。

    $term_query = new WP_Term_Query( array( 'taxonomy' => 'category' ) );
    
    if ( ! empty( $term_query->terms ) ) {
        foreach ( $term_query->terms as $term ) {
            // 直接访问 $term 的属性,比如 $term->name, $term->slug
        }
    }

    虽然都是拿到数据,但 WP_Term_Query 这种方式更加面向对象,也更方便进行一些高级操作,比如分页。

  2. 灵活性:参数的多少,决定了你的自由度

    get_terms() 函数支持的参数相对较少,虽然也能满足大部分的需求,但在一些复杂的查询场景下,就显得有些力不从心了。

    比如,你想根据某个自定义字段的值来筛选词条,get_terms() 就无能为力了。

    WP_Term_Query 类支持更多的参数,并且可以通过钩子来扩展查询条件,因此更加灵活。

    比如,你可以用 meta_query 参数来根据自定义字段的值来筛选词条。

    $args = array(
        'taxonomy' => 'category',
        'meta_query' => array(
            array(
                'key'     => 'my_custom_field',
                'value'   => 'my_custom_value',
                'compare' => '='
            )
        )
    );
    
    $term_query = new WP_Term_Query( $args );

    这段代码就是用 WP_Term_Query 类获取所有 my_custom_field 自定义字段的值等于 my_custom_value 的分类。

  3. 性能:速度与激情的抉择

    在简单的查询场景下,get_terms() 函数可能更快,因为它直接从数据库里获取数据,没有额外的对象创建和处理的开销。

    但在复杂的查询场景下,WP_Term_Query 类可能更有效率,因为它支持更精细的缓存机制,可以更好地利用 WordPress 的对象缓存。

    WP_Term_Query 允许你控制是否缓存结果,以及缓存的键值,这在处理大量数据或者频繁查询时非常有用。

    此外,WP_Term_Query 还可以通过 SQL 优化来提高查询效率,比如使用 JOIN 语句来关联多个表。

  4. 钩子:给你更多掌控权

    get_terms() 函数支持的钩子较少,主要是一些用于修改查询参数和结果的钩子。

    WP_Term_Query 类支持更多的钩子,比如 pre_get_terms, terms_clauses, get_terms 等,这些钩子可以让你在查询的不同阶段,对查询进行自定义修改。

    比如,你可以用 terms_clauses 钩子来修改 SQL 查询语句,实现一些非常规的查询需求。

    add_filter( 'terms_clauses', 'my_custom_terms_clauses', 10, 3 );
    
    function my_custom_terms_clauses( $clauses, $taxonomies, $args ) {
        // 在这里修改 SQL 查询语句
        $clauses['where'] .= " AND t.name LIKE '%my_keyword%'";
        return $clauses;
    }
    
    $term_query = new WP_Term_Query( array( 'taxonomy' => 'category' ) );

    这段代码就是用 terms_clauses 钩子来修改 SQL 查询语句,只获取名称包含 my_keyword 的分类。

  5. 缓存:记忆力决定效率

    get_terms()WP_Term_Query 都有缓存机制,但 WP_Term_Query 的缓存机制更加精细。

    get_terms() 的缓存主要依赖于 WordPress 的对象缓存,它会把查询结果缓存到对象缓存中,下次查询的时候直接从缓存中获取数据。

    WP_Term_Query 除了利用对象缓存之外,还可以通过 cache_domaincache_key 参数来控制缓存的行为。

    cache_domain 参数用于指定缓存的域名,cache_key 参数用于指定缓存的键值。

    通过这两个参数,你可以更精确地控制缓存的生命周期和刷新策略。

第三回合:源码剖析,深入骨髓

光说不练假把式,接下来咱们就来扒一扒 get_terms() 函数和 WP_Term_Query 类的源码,看看它们内部是怎么运作的。

  • get_terms() 函数源码分析

    get_terms() 函数位于 wp-includes/taxonomy.php 文件中。

    它的主要流程如下:

    1. 参数处理: 对传入的参数进行处理,包括参数的类型转换、默认值设置等。
    2. 缓存检查: 检查缓存中是否存在查询结果,如果存在则直接返回缓存结果。
    3. 构建查询参数: 根据传入的参数,构建查询参数数组。
    4. 调用 _get_terms() 函数: 调用 _get_terms() 函数执行实际的数据库查询。
    5. 结果处理: 对查询结果进行处理,包括对象转换、排序等。
    6. 缓存设置: 将查询结果缓存到对象缓存中。
    7. 返回结果: 返回查询结果。

    其中,_get_terms() 函数是 get_terms() 函数的核心,它负责执行实际的数据库查询。

    _get_terms() 函数的主要流程如下:

    1. 构建 SQL 查询语句: 根据查询参数,构建 SQL 查询语句。
    2. 执行 SQL 查询: 执行 SQL 查询,获取查询结果。
    3. 结果处理: 对查询结果进行处理,包括对象转换等。
    4. 返回结果: 返回查询结果。

    从源码可以看出,get_terms() 函数的实现比较简单,主要就是构建 SQL 查询语句,然后执行查询,最后返回结果。

  • WP_Term_Query 类源码分析

    WP_Term_Query 类位于 wp-includes/class-wp-term-query.php 文件中。

    它的主要流程如下:

    1. 参数处理: 对传入的参数进行处理,包括参数的类型转换、默认值设置等。
    2. 构建查询参数: 根据传入的参数,构建查询参数数组。
    3. 应用钩子: 应用 pre_get_terms 钩子,允许在查询之前修改查询参数。
    4. 构建 SQL 查询语句: 根据查询参数,构建 SQL 查询语句。
    5. 应用钩子: 应用 terms_clauses 钩子,允许修改 SQL 查询语句。
    6. 执行 SQL 查询: 执行 SQL 查询,获取查询结果。
    7. 结果处理: 对查询结果进行处理,包括对象转换等。
    8. 缓存设置: 将查询结果缓存到对象缓存中。
    9. 应用钩子: 应用 get_terms 钩子,允许在查询之后修改查询结果。
    10. 返回结果: 返回查询结果。

    从源码可以看出,WP_Term_Query 类的实现更加复杂,它使用了更多的钩子,允许在查询的不同阶段对查询进行自定义修改。

    此外,WP_Term_Query 类还提供了更多的参数,可以实现更复杂的查询需求。

第四回合:实战演练,案例分析

说了这么多理论,不如来点实际的。 咱们来看几个实际的案例,看看在不同的场景下,应该选择 get_terms() 函数还是 WP_Term_Query 类。

  • 案例 1:获取所有分类

    如果你只需要获取所有分类,并且不需要进行复杂的筛选和排序,那么 get_terms() 函数就足够了。

    $categories = get_terms( 'category' );
    
    if ( ! is_wp_error( $categories ) ) {
        // 处理分类数据
    }
  • 案例 2:获取指定分类下的所有子分类

    如果你需要获取指定分类下的所有子分类,并且需要按照名称排序,那么 get_terms() 函数也可以胜任。

    $args = array(
        'taxonomy' => 'category',
        'parent' => $parent_id,
        'orderby' => 'name',
        'order' => 'ASC'
    );
    
    $categories = get_terms( $args );
    
    if ( ! is_wp_error( $categories ) ) {
        // 处理分类数据
    }
  • 案例 3:获取文章数量最多的前 5 个标签

    如果你需要获取文章数量最多的前 5 个标签,并且需要按照文章数量降序排列,那么 WP_Term_Query 类就更适合。

    $args = array(
        'taxonomy' => 'post_tag',
        'orderby' => 'count',
        'order' => 'DESC',
        'number' => 5
    );
    
    $term_query = new WP_Term_Query( $args );
    
    if ( ! empty( $term_query->terms ) ) {
        // 处理标签数据
    }
  • 案例 4:根据自定义字段的值筛选分类

    如果你需要根据自定义字段的值来筛选分类,那么只能使用 WP_Term_Query 类。

    $args = array(
        'taxonomy' => 'category',
        'meta_query' => array(
            array(
                'key' => 'my_custom_field',
                'value' => 'my_custom_value',
                'compare' => '='
            )
        )
    );
    
    $term_query = new WP_Term_Query( $args );
    
    if ( ! empty( $term_query->terms ) ) {
        // 处理分类数据
    }

第五回合:总结陈词,一锤定音

总而言之,get_terms() 函数和 WP_Term_Query 类都是 WordPress 中用于查询分类法词条的重要工具。

get_terms() 函数简单易用,适合简单的查询场景。

WP_Term_Query 类功能强大,灵活可扩展,适合复杂的查询场景。

在实际开发中,应该根据具体的需求,选择合适的工具。

希望今天的讲解能够帮助大家更好地理解 get_terms() 函数和 WP_Term_Query 类的关系和差异,并在实际开发中灵活运用它们。 谢谢大家!

发表回复

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