各位好,今天咱们来聊聊 WordPress 里的一个相当重要的函数——wp_set_post_terms()
。 简单来说,它就是个“分类术语搬运工”,专门负责给文章安排分类、标签等等。
开场白:分类术语的重要性
在 WordPress 的世界里,文章(Post)就像一个个独立的个体,而分类术语(Taxonomy Terms)则像是它们的“标签”或“分类”。通过这些标签,我们能更好地组织内容,方便用户查找,也能让搜索引擎更容易理解文章的主题。 如果没有分类术语,你的博客文章就会像一堆散落的玩具,乱七八糟,没人知道该从哪里开始玩。
wp_set_post_terms()
函数:核心功能
wp_set_post_terms()
函数的功能非常明确: 为指定的文章设置指定的分类术语。
- 文章: 就是你想给它贴标签的文章。
- 分类术语:就是你想给文章贴上的标签,比如“科技”、“美食”、“旅行”等等。
源码剖析:一步一步揭秘
咱们直接上源码,来扒一扒 wp_set_post_terms()
的老底。为了方便理解,我们尽量简化一些不重要的细节。
function wp_set_post_terms( $post_id, $terms, $taxonomy = 'category', $append = false ) {
$post_id = (int) $post_id;
$taxonomy = sanitize_key( $taxonomy );
$id_based = false; // 默认是按名称匹配
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
if ( ! is_array( $terms ) ) {
$terms = array( $terms );
}
$term_ids = array();
if ( ! empty( $terms ) ) {
foreach ( $terms as $term ) {
$id = false;
if ( is_int( $term ) ) {
$id = $term;
$id_based = true;
} else {
// 尝试通过名称获取术语 ID
$term_info = term_exists( $term, $taxonomy );
if ( $term_info ) {
$id = intval( $term_info['term_id'] );
}
}
if ( $id ) {
$term_ids[] = (int) $id;
} else {
// 如果术语不存在,则创建它
$term_info = wp_insert_term( $term, $taxonomy );
if ( ! is_wp_error( $term_info ) ) {
$term_ids[] = (int) $term_info['term_id'];
}
}
}
}
$term_ids = array_unique( array_map( 'intval', $term_ids ) );
if ( empty( $term_ids ) ) {
return wp_delete_object_term_relationships( $post_id, $taxonomy );
}
$tt_ids = wp_set_object_terms( $post_id, $term_ids, $taxonomy, $append, $id_based );
wp_cache_delete( $post_id, 'terms' ); // 清除缓存
return $tt_ids;
}
源码解读:逐行剖析
-
参数准备阶段:
$post_id = (int) $post_id;
: 确保文章 ID 是整数,类型转换是好习惯。$taxonomy = sanitize_key( $taxonomy );
: 对分类术语的名称进行清理,防止恶意代码注入。if ( ! taxonomy_exists( $taxonomy ) ) { ... }
: 检查分类术语是否存在,如果不存在,就返回一个错误。
-
术语处理阶段:
if ( ! is_array( $terms ) ) { $terms = array( $terms ); }
: 确保$terms
是一个数组,方便后续处理。foreach ( $terms as $term ) { ... }
: 循环处理每一个术语。if ( is_int( $term ) ) { ... }
: 如果术语是一个整数,那么就认为它是一个术语 ID。else { ... }
: 如果术语不是一个整数,那么就认为它是一个术语名称,尝试通过term_exists()
函数获取术语 ID。 如果获取不到,就通过wp_insert_term()
函数创建新的术语。
-
核心操作:
$tt_ids = wp_set_object_terms( $post_id, $term_ids, $taxonomy, $append, $id_based );
: 调用wp_set_object_terms()
函数,完成真正的术语设置操作。
-
清理缓存:
wp_cache_delete( $post_id, 'terms' );
: 清除文章的术语缓存,确保下次获取时是最新的数据。
wp_set_object_terms()
函数:幕后英雄
wp_set_post_terms()
函数本身并没有直接操作数据库,它只是调用了另一个函数 wp_set_object_terms()
来完成真正的术语设置操作。 wp_set_object_terms()
函数才是真正的幕后英雄。
function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false, $id_based = false ) {
global $wpdb;
$object_id = (int) $object_id;
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
if ( ! is_array( $terms ) ) {
$terms = array( $terms );
}
$terms = array_map( 'intval', $terms );
$terms = array_unique( $terms );
$old_tt_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'tt_ids' ) );
$old_tt_ids = array_map( 'intval', $old_tt_ids );
$old_tt_ids = array_unique( $old_tt_ids );
$tt_ids = array();
if ( ! empty( $terms ) ) {
$existing_terms = array();
$new_terms = array();
foreach ( $terms as $term_id ) {
$term_exists = term_exists( $term_id, $taxonomy );
if ( $term_exists ) {
$existing_terms[] = intval( $term_exists['term_id'] );
} else {
// 处理不存在的术语(虽然理论上不应该发生)
// 可以选择创建,也可以直接跳过
// 这里选择跳过
}
}
if ( ! empty( $existing_terms ) ) {
$term_ids = array_unique( $existing_terms );
$tt_ids = array();
foreach ( $term_ids as $term_id ) {
$tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id = %d AND taxonomy = %s", $term_id, $taxonomy ) );
if ( $tt_id ) {
$tt_ids[] = (int) $tt_id;
}
}
}
}
if ( true === $append ) {
$tt_ids = array_merge( $old_tt_ids, $tt_ids );
$tt_ids = array_unique( $tt_ids );
} else {
$delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
if ( ! empty( $delete_tt_ids ) ) {
$delete_tt_ids = array_map( 'intval', $delete_tt_ids );
$query = "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN (" . implode( ',', $delete_tt_ids ) . ")";
$wpdb->query( $wpdb->prepare( $query, $object_id ) );
wp_cache_delete( $object_id, 'terms' );
}
}
$new_tt_ids = array_diff( $tt_ids, $old_tt_ids );
if ( ! empty( $new_tt_ids ) ) {
$query = "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES ";
$values = array();
foreach ( $new_tt_ids as $tt_id ) {
$values[] = $wpdb->prepare( "(%d, %d, 0)", $object_id, $tt_id );
}
$query .= implode( ',', $values );
$wpdb->query( $query );
wp_cache_delete( $object_id, 'terms' );
}
wp_cache_delete( $object_id, 'terms' );
return $tt_ids;
}
wp_set_object_terms()
函数解读:
-
参数校验:
- 确保参数
$object_id
是整数,并且$taxonomy
是有效的分类法。
- 确保参数
-
获取旧的关联:
- 使用
wp_get_object_terms()
获取文章当前关联的术语 ID (term_taxonomy_id)。
- 使用
-
处理新的术语:
- 遍历
$terms
数组,确保每个术语都存在。 - 通过
term_exists()
检查术语是否存在,如果不存在,可以选择创建或者跳过。
- 遍历
-
判断
append
参数:$append = true
:将新的术语追加到旧的术语列表中。$append = false
:替换旧的术语列表。
-
删除旧的关联:
- 如果
$append
为false
,则需要删除文章与旧术语之间的关联。 - 使用
array_diff()
找出需要删除的术语 ID,并使用DELETE
语句从$wpdb->term_relationships
表中删除相应的记录。
- 如果
-
添加新的关联:
- 使用
array_diff()
找出需要添加的术语 ID,并使用INSERT
语句将文章与新术语之间的关联添加到$wpdb->term_relationships
表中。
- 使用
-
清除缓存:
- 清除文章的术语缓存。
数据库结构:幕后存储
要理解 wp_set_post_terms()
的工作原理,还需要了解 WordPress 的数据库结构。
表名 | 作用 |
---|---|
wp_terms |
存储术语的信息,比如术语 ID、术语名称、术语别名等。 |
wp_term_taxonomy |
存储术语的分类信息,比如分类术语 ID、术语 ID、分类法名称、描述、文章数量等。 |
wp_term_relationships |
存储文章和术语之间的关联关系,比如文章 ID、分类术语 ID、排序等。 |
wp_term_relationships
表是关键,它将文章(object_id
)和分类术语(term_taxonomy_id
)联系起来。 wp_set_object_terms()
函数的核心操作就是在这个表中插入或删除记录。
实战演练:代码示例
<?php
// 获取文章 ID
$post_id = 123;
// 设置分类(category)
$categories = array( '科技', '互联网' );
wp_set_post_terms( $post_id, $categories, 'category' );
// 设置标签(post_tag)
$tags = array( 'WordPress', '函数', '源码' );
wp_set_post_terms( $post_id, $tags, 'post_tag', true ); // 追加标签,而不是替换
// 设置自定义分类法(my_custom_taxonomy)
$custom_terms = array( 4, 5, 6 ); // 使用术语 ID
wp_set_post_terms( $post_id, $custom_terms, 'my_custom_taxonomy' );
?>
注意事项:小技巧和陷阱
- 性能优化: 如果你需要批量设置大量文章的分类术语,建议使用
wp_insert_term()
和wp_set_object_terms()
函数的底层方法,并尽量减少数据库查询次数。 - 错误处理: 在使用
wp_insert_term()
函数创建新术语时,要检查返回值是否为WP_Error
对象,以便及时处理错误。 - 术语 ID vs 术语名称:
wp_set_post_terms()
函数既可以接受术语 ID,也可以接受术语名称。 如果使用术语名称,函数会自动查找或创建相应的术语。 $append
参数: 要注意$append
参数的作用,它决定了是追加术语还是替换术语。
总结:分类术语的艺术
wp_set_post_terms()
函数是 WordPress 中一个非常重要的函数,它负责为文章设置分类术语。 理解它的工作原理,可以帮助我们更好地组织内容,优化网站性能,并为用户提供更好的浏览体验。 下次再有文章需要贴标签,你就知道该找谁了! 别忘了,好的分类就像好的导游,能让你的读者轻松找到他们想看的东西。