剖析 `get_term_by()` 函数的源码,它是如何根据不同的字段查询分类术语的?

各位观众老爷,晚上好! 今天咱们来聊聊 WordPress 里一个相当实用,但又经常被忽略的小家伙:get_term_by() 函数。 别看它名字平平无奇,功能却相当强大,能让你根据各种不同的字段来精准地找到你想要的分类术语(Term)。 就像个百变金刚,能根据你的指令变换搜索方式。

咱们今天就来把它扒个精光,从源码到用法,保证让你彻底掌握!

一、初识 get_term_by() :分类术语的万能钥匙

首先,简单介绍一下 get_term_by() 函数的作用:

  • 功能: 根据指定字段的值,从指定的分类法(taxonomy)中获取一个分类术语对象。
  • 参数:
    • $field (string) (Required): 要搜索的字段名,比如 id, slug, name 等等。
    • $value (mixed) (Required): 要搜索的字段值。
    • $taxonomy (string) (Optional): 分类法的名称,比如 category, post_tag。 默认为 category
    • $output (string) (Optional): 输出格式。 默认为 OBJECT。 可以是 OBJECT, ARRAY_A, ARRAY_N
  • 返回值:
    • 成功时,返回一个分类术语对象 (WP_Term 对象) 或者数组,取决于 $output 参数。
    • 失败时,返回 false

简单来说,你想找一个分类,但你只知道它的名字,或者 slug,或者 ID,就可以用 get_term_by() 函数来帮你搞定。 它就像一个数据库查询工具,只不过专门为 WordPress 的分类术语量身定制。

二、直击源码: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;

    $taxonomy = sanitize_key( $taxonomy );

    if ( empty( $taxonomy ) ) {
        return false;
    }

    $tax = get_taxonomy( $taxonomy );
    if ( ! $tax ) {
        return false;
    }

    if ( ! is_scalar( $value ) ) {
        return false;
    }

    if ( 'id' === $field ) {
        $value = (int) $value;
        if ( $value < 1 ) {
            return false;
        }

        $term = get_term( $value, $taxonomy, $output, $filter );
        if ( is_wp_error( $term ) ) {
            return false;
        }

        return $term;
    }

    if ( 'slug' === $field ) {
        $slug = sanitize_title( $value );
        $term = get_term_by( 'name', $value, $taxonomy, $output, $filter );

        if ($term && $term->slug === $slug) {
            return $term;
        }

        $term = get_terms(
            array(
                'taxonomy' => $taxonomy,
                'slug'     => $slug,
                'get'      => 'all',
            )
        );
        if ( is_wp_error( $term ) || empty( $term ) ) {
            return false;
        }
        if ( is_array( $term ) ) {
            $term = array_shift( $term );
        }
        return get_term( $term, $taxonomy, $output, $filter );
    }

    $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE $field = %s", $value ) );

    if ( ! $id ) {
        return false;
    }

    return get_term( $id, $taxonomy, $output, $filter );
}

咱们来一行行地解读这段代码:

  1. global $wpdb;: 引入全局的 WordPress 数据库对象 $wpdb。 咱们要查数据库,肯定离不开它。

  2. $taxonomy = sanitize_key( $taxonomy );: 对分类法名称进行安全处理,防止恶意代码注入。

  3. if ( empty( $taxonomy ) ) { return false; }: 如果分类法名称为空,直接返回 false。 没有指定分类法,查个寂寞啊!

  4. $tax = get_taxonomy( $taxonomy ); if ( ! $tax ) { return false; }: 检查指定的分类法是否存在。 如果不存在,也返回 false。 你要查的分类法都不存在,还查啥?

  5. if ( ! is_scalar( $value ) ) { return false; }: 检查要搜索的值是否为标量类型(例如,字符串、整数、浮点数、布尔值)。 如果不是标量类型,也返回 false。 不支持数组和对象作为搜索值。

  6. if ( 'id' === $field ) { ... }: 如果搜索字段是 id

    • $value 转换为整数。
    • 如果 $value 小于 1,返回 false。 ID 必须是正整数。
    • 直接调用 get_term() 函数,通过 ID 获取分类术语对象。 这是最高效的方式,因为 WordPress 内部就是用 ID 来索引分类术语的。
  7. if ( 'slug' === $field ) { ... }: 如果搜索字段是 slug

    • 首先对 $value 进行slug验证和转义。
    • 尝试通过 name字段来查找,如果找到了,并且 slug 匹配,则直接返回。
    • 如果没找到,就使用 get_terms() 函数,通过 slug 精确查找。
    • 如果找到了多个结果,就返回第一个。
  8. $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE $field = %s", $value ) );: 如果搜索字段不是 idslug,就执行一个 SQL 查询,从 $wpdb->terms 表中查找符合条件的 term_id$wpdb->prepare() 函数用于防止 SQL 注入。

  9. if ( ! $id ) { return false; }: 如果查询结果为空,说明没有找到符合条件的分类术语,返回 false

  10. return get_term( $id, $taxonomy, $output, $filter );: 如果找到了 term_id,就调用 get_term() 函数,通过 ID 获取分类术语对象并返回。

总结一下:

  • get_term_by() 函数首先会进行一系列的参数检查和安全处理。
  • 如果搜索字段是 id,就直接调用 get_term() 函数,这是最快的。
  • 如果搜索字段是 slug,先尝试通过 name查找,如果找不到,再调用 get_terms() 函数通过 slug 精确查找。
  • 如果搜索字段是其他字段,就执行一个 SQL 查询,从数据库中查找 term_id,然后调用 get_term() 函数获取分类术语对象。

三、实战演练:get_term_by() 的各种用法

光说不练假把式,咱们来看一些实际的例子,演示 get_term_by() 函数的各种用法。

1. 通过 ID 获取分类术语:

$term_id = 123; // 假设你要查找的分类术语的 ID 是 123
$term = get_term_by( 'id', $term_id, 'category' );

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

这段代码会根据 ID 123 查找 category 分类法下的分类术语,如果找到了,就输出分类的名称、slug 和 ID。

2. 通过 Slug 获取分类术语:

$term_slug = 'my-awesome-category'; // 假设你要查找的分类术语的 Slug 是 my-awesome-category
$term = get_term_by( 'slug', $term_slug, 'category' );

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

这段代码会根据 Slug my-awesome-category 查找 category 分类法下的分类术语,如果找到了,就输出分类的名称、slug 和 ID。

3. 通过名称获取分类术语:

$term_name = 'My Awesome Category'; // 假设你要查找的分类术语的名称是 My Awesome Category
$term = get_term_by( 'name', $term_name, 'category' );

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

这段代码会根据名称 My Awesome Category 查找 category 分类法下的分类术语,如果找到了,就输出分类的名称、slug 和 ID。

4. 获取自定义分类法下的分类术语:

$term_slug = 'my-custom-term'; // 假设你要查找的分类术语的 Slug 是 my-custom-term
$term = get_term_by( 'slug', $term_slug, 'my_custom_taxonomy' ); // my_custom_taxonomy 是你自定义的分类法名称

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

这段代码和前面的例子类似,只不过指定了分类法为 my_custom_taxonomy,这是你自定义的分类法名称。

5. 以数组形式获取分类术语信息:

$term_id = 123; // 假设你要查找的分类术语的 ID 是 123
$term = get_term_by( 'id', $term_id, 'category', ARRAY_A ); // 指定输出格式为数组

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

这段代码和第一个例子类似,只不过指定了输出格式为 ARRAY_A,这意味着 get_term_by() 函数会返回一个关联数组,而不是一个 WP_Term 对象。 你可以通过数组的键来访问分类术语的信息。

6. 安全使用 get_term_by()

由于 get_term_by() 最终可能会执行 SQL 查询,所以在使用时务必注意安全性,防止 SQL 注入。

  • 参数验证: 确保传入的 $value 参数是经过验证和转义的。 可以使用 sanitize_text_field()esc_sql() 函数进行处理。
  • 避免直接使用用户输入: 尽量避免直接将用户输入作为 $value 参数传递给 get_term_by() 函数。 如果必须使用用户输入,一定要进行严格的验证和过滤。

四、get_term_by()get_term()get_terms() 的区别

很多小伙伴可能对这三个函数感到困惑,咱们来简单对比一下:

函数名 功能 参数 返回值
get_term_by() 根据指定字段的值,从指定的分类法中获取一个分类术语对象。 相当于一个过滤器,让你根据特定条件来查找分类术语。 1. $field (string): 要搜索的字段名,比如 id, slug, name 等等。 2. $value (mixed): 要搜索的字段值。 3. $taxonomy (string) (Optional): 分类法的名称。 默认为 category。 4. $output (string) (Optional): 输出格式。 默认为 OBJECT。 可以是 OBJECT, ARRAY_A, ARRAY_N 成功时,返回一个分类术语对象 (WP_Term 对象) 或者数组,取决于 $output 参数。 失败时,返回 false
get_term() 根据 ID 获取一个分类术语对象。 相当于一个直接访问工具,直接通过 ID 来获取分类术语。 1. $term (int object string): 分类术语的 ID、对象或 Slug。 2. $taxonomy (string) (Optional): 分类法的名称。 默认为空字符串。 3. $output (string) (Optional): 输出格式。 默认为 OBJECT。 可以是 OBJECT, ARRAY_A, ARRAY_N。 4. $filter (string) (Optional): 过滤器名称。 默认为 raw 成功时,返回一个分类术语对象 (WP_Term 对象) 或者数组,取决于 $output 参数。 失败时,返回 WP_Error 对象或者 false
get_terms() 获取指定分类法下的所有分类术语,或者根据指定的参数进行筛选。 相当于一个列表工具,可以获取多个分类术语。 $args (array string) (Optional): 参数数组或者参数字符串。 用于指定分类法名称、排序方式、筛选条件等等。 成功时,返回一个包含分类术语对象的数组。 失败时,返回 WP_Error 对象或者空数组。

总结:

  • 如果你知道分类术语的 ID,使用 get_term() 函数是最快的。
  • 如果你知道分类术语的其他字段值(比如 slug 或 name),使用 get_term_by() 函数。
  • 如果你要获取多个分类术语,或者需要根据复杂的条件进行筛选,使用 get_terms() 函数。

五、性能优化:避免过度使用 get_term_by()

虽然 get_term_by() 函数很方便,但是如果过度使用,可能会影响网站的性能。 尤其是当你使用非 id 字段进行搜索时,get_term_by() 函数需要执行 SQL 查询,这会增加数据库的负担。

建议:

  • 尽量使用 ID 进行搜索: 如果可以,尽量使用分类术语的 ID 来获取信息,因为这是最快的。
  • 缓存结果: 如果需要多次使用同一个分类术语的信息,可以将结果缓存起来,避免重复查询数据库。 可以使用 WordPress 的 Transient API 来实现缓存。
  • 减少 SQL 查询次数: 尽量避免在循环中调用 get_term_by() 函数。 可以先使用 get_terms() 函数获取所有需要的分类术语,然后进行循环处理。

六、总结

今天咱们深入剖析了 WordPress 的 get_term_by() 函数,从源码到用法,再到性能优化,相信你已经对它有了全面的了解。 get_term_by() 函数就像一个分类术语的万能钥匙,能让你根据各种不同的字段来精准地找到你想要的分类。

记住,合理使用 get_term_by() 函数,能让你的 WordPress 开发更加高效。 但也要注意性能优化,避免过度使用,让你的网站飞起来!

今天的讲座就到这里,感谢各位的观看! 如果有什么问题,欢迎在评论区留言,咱们一起探讨!

发表回复

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