自定义分类:父项仍计入已删除的子项

时间:2013-10-10 作者:lastria

当我删除了两个子分类法,但它们似乎仍然被分配给它们的父分类法时,我遇到了这种奇怪的情况。

我需要一个概述网站,为我们所有的产品与分类标题提前。如果有子分类法,则产品应显示在子分类法下,而不是父分类法下。

the code

$args = array(
    \'type\'                     => \'anco_produkt\',
    \'orderby\'                  => \'menu_order\',
    \'order\'                    => \'ASC\',
    \'taxonomy\'                 => \'produkt_category\'
); 
$taxonomies = get_categories($args);

foreach ($taxonomies as $taxonomy) {
  if($taxonomy->parent == 0) {
    echo \'<h3 class="alignnone">\'.$taxonomy->name.\'</h3>\';
  } else {
    echo \'<h4>\'.$taxonomy->name.\'</h4>\';
  }

  // Get the children of current taxonomy
  $tax_children = get_term_children($taxonomy->term_id , \'produkt_category\');

  if(count($tax_children) == 0) { // Are there children?
    // Do something with the posts
  }
它工作得很好!

但我有一个分类法和两个以前的子分类法。我删除了它们,并将所有受影响的帖子分配到父类别,但这些帖子不会显示在父类别下。

我测试了我是否有以下孩子:

print_r($tax_children);
echo count($tax_children);
瞧,我得到了他们的身份证(19和22)以及这个“无子女”父母的两个孩子。数据库中没有具有这些ID的分类/类别。我试过了wp_delete_term()wp_delete_category(), 这位家长就是不能放过自己的孩子:((

the problem in action:http://ch-de.ancotech.com/produkte/

the taxonomiesthe taxonomies I currently use

“Spezialbewehrungen”下应该有15种产品。。。

有人有主意吗?

附言:我应该送父母去接受治疗,接受失去孩子的痛苦吗?

1 个回复
最合适的回答,由SO网友:kaiser 整理而成

问题是,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_cacheSource确实有一个部分可以做到这一点:

    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插件来自动修复这个垃圾:)

结束

相关推荐