各位观众老爷,晚上好!我是你们今晚的 WordPress “拆家” 指南特约讲解员,今天咱们不聊情怀,专啃硬骨头,一起扒一扒 wp_delete_term()
这个“辣手摧花”的函数,看看它是如何把 WordPress 的分类术语,以及跟它沾亲带故的文章和子分类,一锅端走的。
一、开场白:wp_delete_term()
是个什么玩意儿?
简单来说,wp_delete_term()
就是 WordPress 用来删除分类、标签等术语的利器。你辛辛苦苦创建的分类,不想要了?一个命令搞定!但别高兴太早,它可不是简单的“删除”操作,背后还隐藏着一系列复杂而精妙的逻辑。
二、源码剖析:一步一步揭开它的神秘面纱
好了,废话不多说,直接上代码(基于 WordPress 6.4 版本):
function wp_delete_term( $term, $taxonomy, $args = array() ) {
$term = (int) $term;
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
$term_obj = get_term( $term, $taxonomy );
if ( is_wp_error( $term_obj ) ) {
return $term_obj;
}
if ( ! $term_obj ) {
return false;
}
$defaults = array( 'default' => 0 );
$args = wp_parse_args( $args, $defaults );
/**
* Fires immediately before a term is deleted from the database.
*
* @since 2.9.0
*
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
*/
do_action( 'pre_delete_term', $term, $taxonomy );
$id = $term_obj->term_id;
/**
* Filters whether to short-circuit deleting the term.
*
* Passing a non-null value will effectively short-circuit the function,
* returning the passed value instead.
*
* @since 3.5.0
*
* @param mixed $pre Whether to short-circuit the deletion. Default null.
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
*/
$pre = apply_filters( 'pre_delete_term', null, $term, $taxonomy );
if ( null !== $pre ) {
return $pre;
}
$object_terms = get_objects_in_term( $term, $taxonomy );
if ( ! is_wp_error( $object_terms ) ) {
foreach ( (array) $object_terms as $object ) {
wp_remove_object_terms( $object, $term, $taxonomy );
}
}
$term_children = get_terms(
array(
'taxonomy' => $taxonomy,
'parent' => $term,
'get' => 'all',
'fields' => 'ids',
)
);
if ( ! is_wp_error( $term_children ) && ! empty( $term_children ) ) {
foreach ( $term_children as $child ) {
wp_delete_term( $child, $taxonomy, $args );
}
}
$deleted = wp_delete_term_taxonomy( $term, $taxonomy );
if ( is_wp_error( $deleted ) ) {
return $deleted;
}
/**
* Fires after a term is deleted from the database.
*
* @since 2.2.0
*
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
* @param mixed $deleted The result of the deletion.
*/
do_action( 'delete_term', $term, $taxonomy, $deleted );
/**
* Fires after a term is deleted from the database.
*
* The dynamic portion of the hook name, `$taxonomy`, refers
* to the taxonomy slug.
*
* @since 2.2.0
*
* @param int $term Term ID.
* @param mixed $deleted The result of the deletion.
*/
do_action( "delete_$taxonomy", $term, $deleted );
if ( ! empty( $args['default'] ) ) {
$default = (int) $args['default'];
wp_set_object_terms( $object_terms, $default, $taxonomy );
}
wp_cache_delete_last_changed( 'terms', $taxonomy );
return $deleted;
}
接下来,我们逐行分析,就像剥洋葱一样,一层一层揭开它的真面目:
第一层:参数校验和准备工作
$term = (int) $term;
:强制将$term
转换为整数,确保传入的是 Term ID。if ( ! taxonomy_exists( $taxonomy ) ) { ... }
:检查$taxonomy
是否存在,不存在就直接返回错误,告诉你“老铁,没这个分类!”$term_obj = get_term( $term, $taxonomy );
:通过 Term ID 和 Taxonomy 获取 Term 对象。if ( is_wp_error( $term_obj ) ) { ... }
:如果获取 Term 对象失败,说明 Term 不存在,直接返回错误。if ( ! $term_obj ) { ... }
:再来一次,以防万一 Term 对象为空,直接返回 false。$defaults = array( 'default' => 0 ); $args = wp_parse_args( $args, $defaults );
:处理参数,主要是设置默认的“default”参数,这个参数后面会用到,用于指定删除 Term 后,文章应该被分配到的默认 Term。
第二层:钩子(Hooks)初体验
do_action( 'pre_delete_term', $term, $taxonomy );
:在删除 Term 之前,触发pre_delete_term
动作钩子。这个钩子允许开发者在删除 Term 之前执行一些自定义操作,比如记录日志、发送通知等等。$pre = apply_filters( 'pre_delete_term', null, $term, $taxonomy ); if ( null !== $pre ) { ... }
:这是个过滤器钩子,允许开发者通过pre_delete_term
过滤器来“短路”删除操作。如果过滤器返回非 null 值,则直接返回该值,不再执行后续的删除操作。这个功能非常强大,可以用来实现一些复杂的权限控制或者数据验证。
第三层:解除文章与 Term 的关联
$object_terms = get_objects_in_term( $term, $taxonomy );
:获取所有与该 Term 关联的文章 ID。if ( ! is_wp_error( $object_terms ) ) { ... }
:遍历所有文章 ID,并使用wp_remove_object_terms()
函数将这些文章与该 Term 解除关联。这一步至关重要,否则删除 Term 后,文章就“脱离组织”了。
第四层:递归删除子分类
$term_children = get_terms( ... );
:获取所有该 Term 的子分类。if ( ! is_wp_error( $term_children ) && ! empty( $term_children ) ) { ... }
:如果存在子分类,则递归调用wp_delete_term()
函数,将子分类也一并删除。这个递归操作保证了删除 Term 时,其下的所有子分类都会被干净彻底地清除。
第五层:真正删除 Term 的核心函数
$deleted = wp_delete_term_taxonomy( $term, $taxonomy );
:调用wp_delete_term_taxonomy()
函数,真正执行删除 Term 的操作。这个函数才是删除 Term 的“幕后黑手”,它负责从数据库中删除 Term 的相关数据。
第六层:删除后的扫尾工作
do_action( 'delete_term', $term, $taxonomy, $deleted );
:删除 Term 之后,触发delete_term
动作钩子。do_action( "delete_$taxonomy", $term, $deleted );
:触发动态动作钩子delete_$taxonomy
。这两个钩子允许开发者在删除 Term 之后执行一些自定义操作,比如更新缓存、发送通知等等。if ( ! empty( $args['default'] ) ) { ... }
:如果设置了default
参数,则将所有与该 Term 关联的文章,重新分配到指定的默认 Term。wp_cache_delete_last_changed( 'terms', $taxonomy );
:清除 Term 缓存。return $deleted;
:返回删除结果。
三、核心函数:wp_delete_term_taxonomy()
的剖析
wp_delete_term()
函数的灵魂在于 wp_delete_term_taxonomy()
函数,它负责执行真正的数据库删除操作。我们继续深入分析这个函数:
function wp_delete_term_taxonomy( $term, $taxonomy ) {
global $wpdb;
$term = (int) $term;
$taxonomy = sanitize_key( $taxonomy );
/**
* Fires immediately before a term taxonomy ID is deleted.
*
* @since 5.1.0
*
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
*/
do_action( 'pre_delete_term_taxonomy', $term, $taxonomy );
$tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id = %d AND taxonomy = %s", $term, $taxonomy ) );
if ( ! $tt_id ) {
return false;
}
/**
* Filters whether to short-circuit deleting the term taxonomy.
*
* Passing a non-null value will effectively short-circuit the function,
* returning the passed value instead.
*
* @since 5.1.0
*
* @param mixed $pre Whether to short-circuit the deletion. Default null.
* @param int $term Term ID.
* @param string $taxonomy Taxonomy name.
*/
$pre = apply_filters( 'pre_delete_term_taxonomy', null, $term, $taxonomy );
if ( null !== $pre ) {
return $pre;
}
$term_taxonomy_id = (int) $tt_id;
/**
* Fires before term taxonomy is deleted.
*
* @since 2.3.0
*
* @param int $term_taxonomy_id Term taxonomy ID.
* @param string $taxonomy Taxonomy name.
*/
do_action( 'delete_term_taxonomy', $term_taxonomy_id, $taxonomy );
$result = $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $term_taxonomy_id ) );
if ( ! $result ) {
return false;
}
$wpdb->delete( $wpdb->termmeta, array( 'term_id' => $term ) );
wp_cache_delete_last_changed( 'terms', $taxonomy );
/**
* Fires after term taxonomy is deleted.
*
* @since 2.3.0
*
* @param int $term_taxonomy_id Term taxonomy ID.
* @param string $taxonomy Taxonomy name.
*/
do_action( 'deleted_term_taxonomy', $term_taxonomy_id, $taxonomy );
return true;
}
$tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id = %d AND taxonomy = %s", $term, $taxonomy ) );
:从$wpdb->term_taxonomy
表中查询term_taxonomy_id
,这个 ID 是 Term 和 Taxonomy 关联的关键。$result = $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $term_taxonomy_id ) );
:从$wpdb->term_taxonomy
表中删除对应的记录。$wpdb->delete( $wpdb->termmeta, array( 'term_id' => $term ) );
:删除与该 Term 相关的 Term Meta 数据。- 一系列的钩子(
pre_delete_term_taxonomy
,delete_term_taxonomy
,deleted_term_taxonomy
),允许开发者在删除 Term Taxonomy 的前后执行自定义操作。
四、参数详解:$args
数组的奥秘
wp_delete_term()
函数接受一个可选的 $args
数组,用于控制删除 Term 的行为。目前,唯一有效的参数是 'default'
:
参数 | 类型 | 描述 |
---|---|---|
'default' |
int |
指定删除 Term 后,文章应该被分配到的默认 Term ID。如果未指定,则文章将不再属于任何 Term。 注意: 如果你的 Taxonomy 是类似 Category 这种必须要有 Term 的,不设置 default 会导致文章显示异常。 |
五、使用场景:一些实用的例子
-
删除分类,并将文章分配到默认分类:
$term_id = 123; // 要删除的分类 ID $taxonomy = 'category'; // 分类法 $default_term_id = 1; // 默认分类 ID $args = array( 'default' => $default_term_id, ); $result = wp_delete_term( $term_id, $taxonomy, $args ); if ( is_wp_error( $result ) ) { echo '删除失败:' . $result->get_error_message(); } else { echo '删除成功!'; }
-
仅仅删除分类,不设置默认分类:
$term_id = 456; // 要删除的分类 ID $taxonomy = 'post_tag'; // 分类法 $result = wp_delete_term( $term_id, $taxonomy ); if ( is_wp_error( $result ) ) { echo '删除失败:' . $result->get_error_message(); } else { echo '删除成功!'; }
-
通过钩子阻止删除分类:
add_filter( 'pre_delete_term', 'my_prevent_term_deletion', 10, 3 ); function my_prevent_term_deletion( $pre, $term, $taxonomy ) { if ( $term == 789 && $taxonomy == 'category' ) { // 假设要阻止删除 ID 为 789 的 Category return new WP_Error( 'deletion_denied', '不能删除这个分类!' ); } return $pre; } $term_id = 789; // 要删除的分类 ID $taxonomy = 'category'; // 分类法 $result = wp_delete_term( $term_id, $taxonomy ); if ( is_wp_error( $result ) ) { echo '删除失败:' . $result->get_error_message(); // 输出:不能删除这个分类! } else { echo '删除成功!'; // 不会执行到这里 }
六、注意事项:踩坑指南
- 权限问题: 确保当前用户拥有删除 Term 的权限。
- Term Meta:
wp_delete_term()
会删除与 Term 相关的 Term Meta 数据,所以在删除 Term 之前,请务必备份重要的 Term Meta 数据。 - 子分类:
wp_delete_term()
会递归删除子分类,请谨慎操作,以免误删数据。 - 关联文章: 如果没有设置
default
参数,删除 Term 后,与该 Term 关联的文章将不再属于任何 Term,可能会影响文章的显示。 - 钩子: 利用钩子可以实现很多自定义功能,比如记录删除日志、发送通知、阻止删除操作等等。
七、总结:wp_delete_term()
的正确打开方式
wp_delete_term()
函数是 WordPress 中一个非常重要的函数,用于删除分类、标签等术语。它不仅可以删除 Term 本身,还可以处理与 Term 关联的文章和子分类。通过理解 wp_delete_term()
函数的源码和参数,我们可以更好地控制删除 Term 的行为,避免出现意外情况。
记住,删除操作需谨慎,备份数据是王道!希望今天的讲解能帮助你更好地理解 wp_delete_term()
函数,并在实际开发中灵活运用。
好啦,今天的“拆家”指南就到这里,希望各位观众老爷喜欢,我们下期再见!