各位老铁,早上好!今天咱们来聊聊 WordPress 里面一个神奇的函数:get_term_by()
。这玩意儿就像个万能钥匙,能根据各种条件帮你找到想要的分类术语(taxonomy term)。但它到底是怎么做到的呢?别急,咱们今天就扒开它的源码,看看里面藏着什么乾坤。
Part 1: 开场白和函数概览
在WordPress的世界里,taxonomy 就是分类法,比如 category(分类)、tag(标签) 等。而 term 则是 taxonomy 下面的具体条目,比如一个 category 叫 "科技",一个 tag 叫 "WordPress"。
get_term_by()
的作用就是根据你给定的条件(比如 slug、name、id),去数据库里把对应的 term 找出来。
简单来说,它的基本用法是这样的:
<?php
$term = get_term_by( 'slug', 'my-awesome-category', 'category' );
if ( $term ) {
echo 'Category Name: ' . $term->name;
} else {
echo 'Category not found!';
}
?>
这个例子就是根据 slug ‘my-awesome-category’ 在 ‘category’ 这个 taxonomy 下查找对应的 term。如果找到了,就输出它的名字。
Part 2: 源码剖析(核心部分)
好了,废话不多说,直接上源码。以下是 get_term_by()
函数的核心部分(为了方便理解,我对源码做了一些简化和注释):
function get_term_by( $field, $value, $taxonomy, $output = OBJECT, $filter = 'raw' ) {
global $wpdb;
$taxonomy = sanitize_taxonomy( $taxonomy ); // 确保 taxonomy 是合法的
if ( ! taxonomy_exists( $taxonomy ) ) { // 检查 taxonomy 是否存在
return false;
}
$id = false;
// 根据不同的 $field 进行不同的查询
switch ( $field ) {
case 'id':
case 'term_id':
$id = intval( $value ); // 转换为整数
if ( empty( $id ) ) {
return false;
}
break;
case 'slug':
$slug = sanitize_title( $value ); // 对 slug 进行安全处理
if ( empty( $slug ) ) {
return false;
}
$term = get_term( $slug, $taxonomy ); // 尝试用 get_term 直接获取
if ( $term && ! is_wp_error( $term ) ) {
return $term;
}
$id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) ); // 查询 term_id
if ( empty( $id ) ) {
return false;
}
break;
case 'name':
$name = trim( $value ); // 去除首尾空格
if ( '' === $name ) {
return false;
}
$id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE name = %s", $name ) ); // 查询 term_id
if ( empty( $id ) ) {
return false;
}
break;
case 'term_taxonomy_id':
$term_taxonomy_id = intval( $value );
if ( empty( $term_taxonomy_id ) ) {
return false;
}
$term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
if ( empty( $term_id ) ) {
return false;
}
$id = $term_id;
break;
default:
return false; // 不支持的 $field
}
if ( $id ) {
$term = get_term( $id, $taxonomy, $output, $filter ); // 通过 term_id 获取 term 对象
if ( is_wp_error( $term ) ) {
return false;
}
return $term;
}
return false;
}
看完这段代码,是不是感觉有点眼花缭乱?别怕,咱们一步一步来分析。
2.1 参数校验和准备
首先,函数接收几个参数:
$field
: 要查询的字段,比如 ‘id’, ‘slug’, ‘name’ 等。$value
:$field
对应的值,比如 slug 是 ‘my-awesome-category’。$taxonomy
: 分类法的名称,比如 ‘category’, ‘post_tag’。$output
: 输出的格式,默认是OBJECT
(对象),还可以是ARRAY_A
(关联数组)或ARRAY_N
(数字索引数组)。$filter
: 对 term 数据进行过滤的方式,默认是 ‘raw’。
函数一开始会对 $taxonomy
进行安全处理,并检查它是否存在。如果 taxonomy 不存在,直接返回 false
。
2.2 根据 $field
选择查询方式(核心逻辑)
这部分是整个函数的核心,它根据 $field
的不同,采取不同的查询策略。
-
$field
是 ‘id’ 或 ‘term_id’这是最简单的情况,直接把
$value
转换成整数$id
,然后跳到最后的get_term()
函数去获取 term 对象。case 'id': case 'term_id': $id = intval( $value ); // 转换为整数 if ( empty( $id ) ) { return false; } break;
-
$field
是 ‘slug’这种情况稍微复杂一点。首先,它会对
$value
(也就是 slug) 进行安全处理。然后,它会尝试直接使用get_term()
函数来获取 term。如果get_term()
能够成功获取 term,就直接返回。为什么这里要先用
get_term()
尝试一下呢?因为get_term()
内部有缓存机制,如果之前已经获取过这个 term,就可以直接从缓存中取,而不用再去查询数据库,提高效率。如果
get_term()
没有成功获取 term,那说明这个 term 可能不在缓存里,或者根本不存在。这时候,就需要去数据库里查询term_id
。case 'slug': $slug = sanitize_title( $value ); // 对 slug 进行安全处理 if ( empty( $slug ) ) { return false; } $term = get_term( $slug, $taxonomy ); // 尝试用 get_term 直接获取 if ( $term && ! is_wp_error( $term ) ) { return $term; } $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) ); // 查询 term_id if ( empty( $id ) ) { return false; } break;
这里用到了
$wpdb->prepare()
函数,这是 WordPress 推荐的安全的 SQL 查询方式,可以防止 SQL 注入攻击。$wpdb->get_var()
函数用于执行 SQL 查询,并返回查询结果的第一行第一列的值,也就是term_id
。 -
$field
是 ‘name’这种情况和 ‘slug’ 类似,也是先对
$value
(也就是 name) 进行安全处理,然后去数据库里查询term_id
。case 'name': $name = trim( $value ); // 去除首尾空格 if ( '' === $name ) { return false; } $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE name = %s", $name ) ); // 查询 term_id if ( empty( $id ) ) { return false; } break;
-
$field
是 ‘term_taxonomy_id’这种情况是根据
term_taxonomy_id
来查找 term。term_taxonomy_id
是wp_term_taxonomy
表中的主键,用于关联 term 和 taxonomy。case 'term_taxonomy_id': $term_taxonomy_id = intval( $value ); if ( empty( $term_taxonomy_id ) ) { return false; } $term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); if ( empty( $term_id ) ) { return false; } $id = $term_id; break;
-
$field
是其他值如果
$field
是其他不支持的值,函数直接返回false
。default: return false; // 不支持的 $field
2.3 获取 Term 对象
如果通过上面的查询,成功获取到了 $id
(也就是 term_id
),那么就可以使用 get_term()
函数来获取对应的 term 对象了。
if ( $id ) {
$term = get_term( $id, $taxonomy, $output, $filter ); // 通过 term_id 获取 term 对象
if ( is_wp_error( $term ) ) {
return false;
}
return $term;
}
get_term()
函数会根据 $output
参数,返回不同格式的 term 数据。
Part 3: get_term()
函数的简单介绍
在 get_term_by()
函数中,最终是通过 get_term()
函数来获取 term 对象的。所以,我们简单了解一下 get_term()
函数。
get_term()
函数的主要作用是:
- 从缓存中获取 term 数据: 如果 term 数据已经在缓存中,直接返回缓存中的数据,避免重复查询数据库。
- 查询数据库获取 term 数据: 如果 term 数据不在缓存中,就查询数据库获取 term 数据。
- 对 term 数据进行过滤: 根据
$filter
参数,对 term 数据进行过滤,比如进行 HTML 转义等。 - 返回 term 数据: 根据
$output
参数,返回不同格式的 term 数据,比如对象、关联数组或数字索引数组。
Part 4: 数据库表结构
为了更好地理解 get_term_by()
函数的查询过程,我们需要了解一下 WordPress 数据库中与 term 相关的表结构。
主要涉及以下两个表:
-
wp_terms
表: 存储 term 的基本信息,比如term_id
、name
、slug
。字段 类型 描述 term_id
bigint(20) term 的 ID (主键) name
varchar(200) term 的名称 slug
varchar(200) term 的 slug (URL 友好型) term_group
bigint(10) term 的分组 (很少使用) -
wp_term_taxonomy
表: 存储 term 和 taxonomy 之间的关联关系,以及 term 的统计信息。字段 类型 描述 term_taxonomy_id
bigint(20) term taxonomy 的 ID (主键) term_id
bigint(20) 关联的 term 的 ID taxonomy
varchar(32) 分类法的名称 (category, post_tag 等) description
longtext term 的描述 parent
bigint(20) 父级 term 的 ID count
bigint(20) 使用该 term 的文章数量
Part 5: 总结和注意事项
好了,咱们来总结一下:
get_term_by()
函数是一个根据不同字段查找分类术语的万能钥匙。- 它会根据
$field
的不同,采取不同的查询策略,包括直接从缓存获取、查询数据库等。 get_term_by()
函数内部使用了get_term()
函数来获取 term 对象。- 理解 WordPress 数据库中
wp_terms
和wp_term_taxonomy
表的结构,有助于更好地理解get_term_by()
函数的查询过程。
注意事项:
- 在使用
get_term_by()
函数时,一定要注意对$value
进行安全处理,防止 SQL 注入攻击。 - 尽量使用 ‘id’ 或 ‘term_id’ 来查询 term,因为这种方式效率最高。
- 如果需要频繁查询同一个 term,可以考虑使用
wp_cache_set()
函数将 term 数据缓存起来,提高效率。
Part 6: 举个栗子
假设我们有一个 category,它的 name 是 "WordPress 开发",slug 是 "wordpress-development",term_id 是 5。
我们可以使用 get_term_by()
函数来获取这个 category:
<?php
// 根据 term_id 获取
$term_by_id = get_term_by( 'id', 5, 'category' );
if ( $term_by_id ) {
echo 'Term Name (by ID): ' . $term_by_id->name . '<br>';
}
// 根据 slug 获取
$term_by_slug = get_term_by( 'slug', 'wordpress-development', 'category' );
if ( $term_by_slug ) {
echo 'Term Name (by Slug): ' . $term_by_slug->name . '<br>';
}
// 根据 name 获取
$term_by_name = get_term_by( 'name', 'WordPress 开发', 'category' );
if ( $term_by_name ) {
echo 'Term Name (by Name): ' . $term_by_name->name . '<br>';
}
?>
这段代码会输出:
Term Name (by ID): WordPress 开发
Term Name (by Slug): WordPress 开发
Term Name (by Name): WordPress 开发
Part 7: 扩展思考
get_term_by()
函数的源码虽然不复杂,但它体现了一些重要的编程思想:
- 分层设计:
get_term_by()
函数只是一个入口,它会将具体的查询工作委托给其他函数,比如get_term()
。 - 缓存机制: 通过使用缓存,可以避免重复查询数据库,提高效率。
- 安全性: 使用
$wpdb->prepare()
函数,可以防止 SQL 注入攻击。 - 灵活性: 通过不同的
$field
参数,可以支持多种查询方式。
这些思想在 WordPress 的其他函数中也经常出现,理解它们有助于我们更好地理解 WordPress 的架构和设计。
Part 8: 结束语
好了,今天的 get_term_by()
函数源码剖析就到这里了。希望通过今天的讲解,大家对这个函数有了更深入的了解。记住,源码是最好的老师,多看源码,多思考,才能真正提高自己的编程水平。下次有机会,咱们再聊聊 WordPress 的其他有趣函数! 溜了溜了~