问题是,WordPress和分类法及其术语层次结构(和子级)存在一个严重的问题:它们并不是真正从实际状态中提取出来的,但有人认为他可能真的很“聪明”,将其塞进了*_options
桌子
只要看看get_term_children()
: 它打电话给_get_term_hierarchy()
. 其中,以下内容用于检索分类法的子级:
get_option( "{$taxonomy}_children" )
现在,一开始利用静态数组而不是真正的计数听起来可能很聪明,但从长远来看,这是一场维护噩梦。WordPress必须保持该值的更新,如果有人忘记以编程方式触发该更新,它将失去同步并失败。
现实世界的例子要证明这一点,您可以执行一个简单的DB调用(例如)phpMyAdmin(或任何您使用的):只需替换{$wpdb->prefix}
使用DB表前缀。
SELECT *
FROM `{$wpdb->prefix}_options`
WHERE `option_name` LIKE \'%children\'
ORDER BY `{$wpdb->prefix}_options`.`option_name` ASC
LIMIT 0 , 1000
结果如下所示-序列化数组:
a:2:{i:23;a:5:{i:0;i:38;i:1;i:39;i:2;i:40;i:3;i:41;i:4;i:42;}i:40;a:1:{i:0;i:43;}}
或反序列化时:
array (
23 =>
array (
0 => 38,
1 => 39,
2 => 40,
3 => 41,
4 => 42,
),
40 =>
array (
0 => 43,
),
)
因此,键是父项,而子数组是关联的子项。
怎么了
首先:我不能完全确定这一点,因为WP使用了大量的普通函数和DB调用,跟踪所有路由非常困难-也许我在某个兔子洞里迷路了。
当我看着wp_delete_term()
似乎实际选项的更新还没有发生。和wp_delete_category()
只是一个包装。所以为了让你的孩子保持同步,你必须manually 更新该选项。
我曾经写过一个导入程序,在那里我偶然发现了同样的问题,并且不得不手动更新选项。因此,除非没有比我更聪明的人上台,否则我认为这是唯一的出路:update_option()
:
$taxonomy = \'your_current_taxonomy\';
$children = get_option( "{$taxonomy}_children" );
// Merge here
update_option( "{$taxonomy}_children", $your_new_value );
编辑(1)对于每个想复制或获得证据的人来说,还有一件事:没有办法
actually see 孩子们不同步,
unless 您可以在admin中查看分类列表屏幕,或者手动比较选项返回值。其他一切都会像预期的那样正常工作。
编辑(2)
正如@MannyFleurmond刚刚评论的那样,可能还有另一个选项:删除该选项并让WP为您重新生成它。我搜索了核心并查看
wp_delete_term()
在里面
~/wp-includes/taxonomy.php
... 发现了一些东西:
clean_term_cache
Source确实有一个部分可以做到这一点:
if ( $clean_taxonomy ) {
wp_cache_delete(\'all_ids\', $taxonomy);
wp_cache_delete(\'get\', $taxonomy);
delete_option("{$taxonomy}_children");
// Regenerate {$taxonomy}_children
_get_term_hierarchy($taxonomy);
}
重点仍然是,它不会触发。原因很简单:第三个参数是
true
按默认值。因此,请参见
source - 它不会触发更新。
可能的解决方案如下:使用挂钩并手动清理以触发更新:
// The last hook before everything happens in core:
do_action( \'deleted_term_taxonomy\', $tt_id );
所以我们可以使用它:
<?php
defined( \'ABSPATH\' ) OR exit;
/** Plugin Name: (#117373) Fix Child term relationships */
add_action( \'deleted_term_taxonomy\', \'wpse117374UpdateTaxChildCount\' );
function wpse117374UpdateTaxChildCount( $termID )
{
$tax = get_current_screen()->taxonomy;
delete_option( "{$tax}_children" );
# OR: ... alternate solution
// clear_term_cache( $termID, get_current_screen()->taxonomy, false );
}
请记住,上述插件未经测试。但如果它有效,请留下评论,这样人们就可以简单地将其作为mu插件来自动修复这个垃圾:)