各位老铁,早上好!今天咱们来聊聊 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_idbigint(20) term 的 ID (主键) namevarchar(200) term 的名称 slugvarchar(200) term 的 slug (URL 友好型) term_groupbigint(10) term 的分组 (很少使用) -
wp_term_taxonomy表: 存储 term 和 taxonomy 之间的关联关系,以及 term 的统计信息。字段 类型 描述 term_taxonomy_idbigint(20) term taxonomy 的 ID (主键) term_idbigint(20) 关联的 term 的 ID taxonomyvarchar(32) 分类法的名称 (category, post_tag 等) descriptionlongtext term 的描述 parentbigint(20) 父级 term 的 ID countbigint(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 的其他有趣函数! 溜了溜了~