深入理解 WordPress `get_term_by()` 函数的源码:如何通过 `slug` 或 `name` 高效地查询分类术语。

WordPress get_term_by() 函数源码深度剖析:像侦探一样追踪你的分类术语

大家好!我是今天的主讲人,希望大家今天听完我的分享,都能像福尔摩斯一样,快速准确地在 WordPress 的分类术语世界里找到你想要的信息。

今天我们要深入探讨的是 WordPress 中一个非常实用的函数:get_term_by()。这个函数允许我们通过不同的属性(例如 slug、name、ID 等)来检索分类术语对象。我们将重点关注如何通过 slugname 这两个属性高效地进行查询,并深入源码,看看 WordPress 内部是如何运作的。

1. get_term_by() 函数的基本用法

首先,让我们回顾一下 get_term_by() 函数的基本用法。它的函数签名如下:

get_term_by( string $field, mixed $value, string|array $taxonomy = 'category', string $output = OBJECT, string $filter = 'raw' )
  • $field: 我们要查询的字段。常见的选项有 'id', 'slug', 'name', 'term_id' 等。
  • $value: 我们要查询的字段对应的值。
  • $taxonomy: 分类术语的分类法(taxonomy)。默认为 'category'。可以是一个字符串,也可以是一个字符串数组,代表多个分类法。
  • $output: 返回值的类型。默认为 OBJECT (WP_Term 对象)。也可以是 ARRAY_A (关联数组) 或 ARRAY_N (索引数组)。
  • $filter: 对结果进行过滤。默认为 'raw',不进行任何过滤。

例子:通过 slug 查找分类术语

$term = get_term_by( 'slug', 'my-awesome-category', 'category' );

if ( $term ) {
  echo '分类术语名称: ' . $term->name . '<br>';
  echo '分类术语 ID: ' . $term->term_id . '<br>';
  echo '分类术语 slug: ' . $term->slug . '<br>';
} else {
  echo '未找到分类术语。';
}

例子:通过 name 查找分类术语

$term = get_term_by( 'name', '我的超棒分类', 'category' );

if ( $term ) {
  echo '分类术语名称: ' . $term->name . '<br>';
  echo '分类术语 ID: ' . $term->term_id . '<br>';
  echo '分类术语 slug: ' . $term->slug . '<br>';
} else {
  echo '未找到分类术语。';
}

2. get_term_by() 源码剖析

现在,让我们深入到 WordPress 源码中,看看 get_term_by() 函数是如何实现的。这个函数位于 /wp-includes/taxonomy.php 文件中。

function get_term_by( $field, $value, $taxonomy = 'category', $output = OBJECT, $filter = 'raw' ) {
    global $wpdb;

    if ( ! taxonomy_exists( $taxonomy ) ) {
        return false;
    }

    // 'id' is an alias for 'term_id'
    if ( 'id' === $field ) {
        $field = 'term_id';
    }

    if ( 'slug' === $field && empty( $value ) ) {
        return false;
    }

    $taxonomies = (array) $taxonomy;
    $term       = false;

    foreach ( $taxonomies as $taxonomy ) {
        if ( ! taxonomy_exists( $taxonomy ) ) {
            return false;
        }

        $term_id = false;

        switch ( $field ) {
            case 'term_id':
                $term_id = absint( $value );
                break;
            case 'id': // Redundant, but kept for backwards compatibility.
                $term_id = absint( $value );
                break;
            case 'slug':
                $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $value ) );
                break;
            case 'name':
                $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE name = %s", $value ) );
                break;
            case 'term_taxonomy_id':
                $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d AND taxonomy = %s", $value, $taxonomy ) );
                break;
            default:
                /**
                 * Fires when an invalid field is requested.
                 *
                 * @since 4.4.0
                 *
                 * @param string       $field    The field used to search.
                 * @param mixed        $value    The field's value.
                 * @param string       $taxonomy The taxonomy name.
                 */
                do_action( 'get_term_by_invalid_field', $field, $value, $taxonomy );
                return false;
        }

        if ( $term_id ) {
            $term = get_term( $term_id, $taxonomy, $output, $filter );

            if ( $term && ! is_wp_error( $term ) ) {
                break;
            }
            $term = false;
        }
    }

    return $term;
}

让我们逐步分析:

  1. 参数验证:

    • 首先,它检查指定的 taxonomy 是否存在。如果不存在,直接返回 false
    • 如果 $field'id',则将其转换为 'term_id',因为它们是等价的。
    • 如果 $field'slug' 并且 $value 为空,则返回 false,避免不必要的查询。
  2. 循环处理多个 Taxonomy:

    • $taxonomy 参数可以是一个 taxonomy 字符串或一个 taxonomy 字符串数组。函数会循环处理这些 taxonomy,如果找到了匹配的 term,就会停止循环。
  3. 根据 Field 选择查询方式:

    • switch 语句根据 $field 的值来选择不同的查询方式。
    • 如果 $field'term_id''id',则直接将 $value 转换为整数,作为 term_id。
    • 如果 $field'slug''name',则使用 $wpdb->get_var() 方法执行 SQL 查询,从 $wpdb->terms 表中获取 term_id
    • 如果 $field'term_taxonomy_id',则使用 $wpdb->get_var() 方法执行 SQL 查询,从 $wpdb->term_taxonomy 表中获取 term_id
    • 如果 $field 是其他值,则触发 get_term_by_invalid_field action,并返回 false
  4. 获取 Term 对象:

    • 如果找到了 term_id,则调用 get_term() 函数来获取完整的 term 对象。
    • 如果 get_term() 返回一个有效的 term 对象,并且不是 WP_Error 对象,则停止循环,返回 term 对象。
    • 如果 get_term() 返回 false 或 WP_Error 对象,则将 $term 设置为 false,继续循环。
  5. 返回结果:

    • 最后,函数返回 $term。如果找到了匹配的 term,则返回 term 对象;否则,返回 false

3. slugname 查询的性能分析

当我们使用 slugname 进行查询时,get_term_by() 函数会执行以下 SQL 查询:

使用 slug 查询:

SELECT term_id FROM wp_terms WHERE slug = '%s'

使用 name 查询:

SELECT term_id FROM wp_terms WHERE name = '%s'

这些查询语句都很简单,但是否高效取决于以下因素:

  • wp_terms 表的大小: 如果 wp_terms 表包含大量的分类术语,查询速度可能会变慢。
  • slugname 列的索引: wp_terms 表的 slugname 列默认都有索引。索引可以显著提高查询速度。

优化建议:

  • 确保 slugname 列都有索引: WordPress 默认会创建这些索引,但如果你的数据库发生了意外情况(例如,手动修改了数据库结构),你需要检查一下这些索引是否存在。
  • 避免使用过长的 slugname: 过长的字符串会增加索引的大小,并可能降低查询速度。
  • 如果可能,尽量使用 term_id 进行查询: 通过 term_id 查询是最快的,因为它直接通过主键索引进行查找。
  • 使用缓存: 如果你的网站需要频繁地查询相同的分类术语,可以考虑使用缓存来提高性能。WordPress 提供了 transient API,可以方便地缓存数据。

4. 代码示例:使用缓存优化 get_term_by()

/**
 * 通过 slug 获取分类术语,使用缓存优化。
 *
 * @param string $slug     分类术语 slug.
 * @param string $taxonomy 分类法.
 *
 * @return WP_Term|false 分类术语对象,如果未找到则返回 false.
 */
function get_term_by_slug_cached( $slug, $taxonomy = 'category' ) {
  $cache_key = 'term_by_slug_' . $slug . '_' . $taxonomy;
  $term = wp_cache_get( $cache_key, 'terms' );

  if ( false === $term ) {
    $term = get_term_by( 'slug', $slug, $taxonomy );

    if ( $term ) {
      wp_cache_set( $cache_key, $term, 'terms', 3600 ); // 缓存 1 小时
    }
  }

  return $term;
}

// 使用示例
$term = get_term_by_slug_cached( 'my-awesome-category', 'category' );

if ( $term ) {
  echo '分类术语名称: ' . $term->name . '<br>';
} else {
  echo '未找到分类术语。';
}

这个例子展示了如何使用 WordPress 的 wp_cache_get()wp_cache_set() 函数来缓存 get_term_by() 的结果。 这样可以避免每次都执行数据库查询,显著提高性能。

5. 总结与最佳实践

get_term_by() 函数是 WordPress 中一个非常重要的工具,可以帮助我们方便地检索分类术语信息。 通过深入了解它的源码和性能特点,我们可以更好地利用它,并避免一些常见的性能问题。

以下是一些最佳实践建议:

  • 优先使用 term_id 查询: 如果已知 term_id,则直接使用 get_term() 函数进行查询,这是最快的。
  • 使用缓存: 对于频繁查询的分类术语,使用缓存可以显著提高性能。
  • 注意 slugname 的唯一性: 虽然 WordPress 允许同名的分类术语存在于不同的分类法中,但最好保持 slug 的唯一性,以避免混淆。
  • 避免在循环中调用 get_term_by(): 如果在循环中需要查询多个分类术语,最好一次性获取所有需要的 term_id,然后使用 get_terms() 函数批量获取 term 对象。 这样可以减少数据库查询次数,提高性能。
  • 了解你的数据: 了解 wp_terms 表的大小、索引情况等,可以帮助你更好地优化查询。

表格总结:

查询方式 优点 缺点 适用场景
term_id 最快,直接使用主键索引 需要已知 term_id 已知 term_id 的情况下
slug 方便,易于使用 需要查询数据库,性能略低于 term_id 需要通过 slug 查找分类术语的情况下
name 更人性化,可以使用分类术语的名称进行查询 需要查询数据库,性能略低于 term_idslug 需要通过分类术语的名称查找分类术语的情况下

希望今天的分享对大家有所帮助。记住,深入理解 WordPress 的源码,就像拥有了一张藏宝图,可以帮助你更快地找到你想要的信息,并构建更高效的网站。 谢谢大家!

发表回复

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