_wp_batch_split_terms()
云策文档标注
概述
_wp_batch_split_terms() 是 WordPress 内部函数,用于批量拆分共享的分类法术语,通过数据库锁机制确保并发安全,并分批处理以避免性能问题。
关键要点
- 函数通过数据库锁(term_split.lock)防止并发执行,若锁存在则调度 wp_split_shared_term_batch 事件延迟重试。
- 每次处理最多 10 个共享术语(term_taxonomy 表中关联行数大于 1 的术语),使用 _split_shared_term() 进行拆分。
- 拆分后更新 _split_terms 选项记录,并刷新受影响分类法的层级缓存(如删除 {$tax}_children 选项)。
- 函数在 WordPress 4.3.0 版本引入,主要用于内部术语管理,开发者通常无需直接调用。
代码示例
// 示例:函数核心锁机制和查询逻辑
$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'off') /* LOCK */", $lock_name, time() ) );
if ( ! $lock_result ) {
wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
return;
}注意事项
- 此函数为内部使用,直接调用可能影响系统稳定性,建议通过相关 Hook 或事件触发。
- 处理共享术语时,会跳过每个 term_id 的第一个 term_taxonomy 条目,以保留原始术语。
- 函数依赖 wpdb 类进行数据库操作,确保在 WordPress 环境内执行。
原文内容
Splits a batch of shared taxonomy terms.
Source
function _wp_batch_split_terms() {
global $wpdb;
$lock_name = 'term_split.lock';
// Try to lock.
$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'off') /* LOCK */", $lock_name, time() ) );
if ( ! $lock_result ) {
$lock_result = get_option( $lock_name );
// Bail if we were unable to create a lock, or if the existing lock is still valid.
if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) {
wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
return;
}
}
// Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
update_option( $lock_name, time() );
// Get a list of shared terms (those with more than one associated row in term_taxonomy).
$shared_terms = $wpdb->get_results(
"SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
GROUP BY t.term_id
HAVING term_tt_count > 1
LIMIT 10"
);
// No more terms, we're done here.
if ( ! $shared_terms ) {
update_option( 'finished_splitting_shared_terms', true );
delete_option( $lock_name );
return;
}
// Shared terms found? We'll need to run this script again.
wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
// Rekey shared term array for faster lookups.
$_shared_terms = array();
foreach ( $shared_terms as $shared_term ) {
$term_id = (int) $shared_term->term_id;
$_shared_terms[ $term_id ] = $shared_term;
}
$shared_terms = $_shared_terms;
// Get term taxonomy data for all shared terms.
$shared_term_ids = implode( ',', array_keys( $shared_terms ) );
$shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
// Split term data recording is slow, so we do it just once, outside the loop.
$split_term_data = get_option( '_split_terms', array() );
$skipped_first_term = array();
$taxonomies = array();
foreach ( $shared_tts as $shared_tt ) {
$term_id = (int) $shared_tt->term_id;
// Don't split the first tt belonging to a given term_id.
if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
$skipped_first_term[ $term_id ] = 1;
continue;
}
if ( ! isset( $split_term_data[ $term_id ] ) ) {
$split_term_data[ $term_id ] = array();
}
// Keep track of taxonomies whose hierarchies need flushing.
if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) {
$taxonomies[ $shared_tt->taxonomy ] = 1;
}
// Split the term.
$split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false );
}
// Rebuild the cached hierarchy for each affected taxonomy.
foreach ( array_keys( $taxonomies ) as $tax ) {
delete_option( "{$tax}_children" );
_get_term_hierarchy( $tax );
}
update_option( '_split_terms', $split_term_data );
delete_option( $lock_name );
}
Changelog
| Version | Description |
|---|---|
| 4.3.0 | Introduced. |