选中父类别时自动检查子类别/术语 [英] Automatically check child categories/terms when parent category is checked

查看:23
本文介绍了选中父类别时自动检查子类别/术语的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个大陆 -> 自定义帖子类型的国家/地区类别设置.

I have this Continent -> Country category setup for a custom post type.

- Africa
    - Uganda
    - Zambia
    - Zimbabwe
- Asia
    - Afghanistan
    - Bahrain
    - Bangladesh
    - Bhutan

我认为这可以通过某种 WordPress 功能来解决,如果检查父类别(非洲),它会自动检查所有子类别(大陆的国家),而不是像 这个插件.

I think this could be solved by some kind of WordPress function that will auto check all the child categories (countries of a continent) if the parent category (Africa) is checked, not the other way around like this plugin.

例如,如果选中Africa,则应自动选中所有非洲国家.如果只勾选Zimbabwe,则不应勾选父类别Africa.

For example, if Africa is checked, all the African Countries should be automatically checked. If only Zimbabwe is checked, the parent category Africa should not be checked.

此外,当 Africa取消选中时,非洲国家也应该自动取消选中.

Also when Africa is unchecked, the African Countries should be unchecked automatically as well.

推荐答案

我有一个相对冗长的答案,可以很好地检查子项,但在取消选中父项时取消选中它们就不那么好了.我已在此处支持该答案:原始答案:60079535(也可在编辑历史记录中找到).

好吧,实际上我为这个结果感到非常自豪.在做了一些研究之后,我遇到了 set_object_terms钩子,在 wp_set_object_terms() 函数,位于 /wp-includes/taxonomy.php.

Okay, I'm pretty proud of this result actually. After doing some reasearch, I came across the set_object_terms hook, which is fired at the end of the wp_set_object_terms() function, located in /wp-includes/taxonomy.php.

在那个钩子上,它接受 6 个参数:$object_id、$terms、$tt_ids、$taxonomy、$append、$old_tt_ids.这里对于检查孩子"的重要部分是取消检查孩子"是 $tt_ids$old_tt_ids.这些分别是新术语 id 和旧术语 id 的数组.

On that hook, it accepts 6 arguments: $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids. The important ones here for "check children" and "uncheck children" are $tt_ids and $old_tt_ids. These are arrays of the new term ids, and the old term ids, respectively.

这让我们可以比较两个数组,看看哪些 id 被添加,哪些 id 被删除.这很重要,因为您可以选中非洲,然后取消选中非洲,现在选中亚洲.这是一个方便的功能,可让您查看两者的差异:

This allows us to compare the two arrays and see what ids were added and which were removed. This is important because you may check Africa, then later uncheck Africa and now check Asia. Here's a handy function that will allow you to see both differences:

function array_diff_once($a1, $a2){
    foreach($a2 as $val){
        if( false !== ($pos = array_search($val, $a1)) ){
            unset($a1[$pos]);
        }
    }
    
    return array_values($a1);
}

因此,我们可以不使用 save_post 钩子,而是比较 set_object_terms 钩子上添加/删除的术语,并为其中的每一个添加/删除子术语.请注意,这也可能在不合时宜的时候触发(自动保存,如果帖子未发布等,所以我设置了一些中止条件.)

So instead of using the save_post hook, we can instead compare the added/removed terms on the set_object_terms hook, and add/remove child terms for each one there. Note, this can also fire during inopportune times (autosaving, if the post isn't published, etc, so I've put in a few abort conditions.)

add_action( 'set_object_terms', 'so_60079535_toggle_child_terms', 10, 6 );
function so_60079535_toggle_child_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ){
    // Abort if this is an autosave/backup
    if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;

    // Abort if no ids are set from before or now
    if( empty($tt_ids) && empty($old_tt_ids) )
        return;

    // Only do things if this post is published (front facing)
    $post_status = get_post_status( $object_id );
    if( $post_status != 'publish' )
        return;

    // What terms where ADDED, and which were REMOVED?
    $added_terms   = array_diff_once( $tt_ids, $old_tt_ids );
    $removed_terms = array_diff_once( $old_tt_ids, $tt_ids );

    // Any terms ADDED this time?
    if( !empty($added_terms) ){
        foreach( $added_terms as $added_term ){
            // Do any of these added terms have children?
            if( $added_child_terms = get_term_children( $added_term, $taxonomy ) ){
                // Append those children
                wp_set_object_terms( $object_id, $added_child_terms, $taxonomy, true );
            }
        }
    }

    // Any terms REMOVED?
    if( !empty($removed_terms) ){
        foreach( $removed_terms as $removed_term ){
            // Do any of the removed terms have children?
            if( $removed_child_terms = get_term_children( $removed_term, $taxonomy ) ){
                // Remove them all
                wp_remove_object_terms( $object_id, $removed_child_terms, $taxonomy, true );
            }
        }
    }
}

实际上,我已将此代码放在我的测试站点上,无论(孙子/曾孙子条款)术语有多深,以及一次添加或删除多少项,它似乎都能完美运行.另一个很好的事情是这个钩子已经传递了 $taxonomy 参数,所以它应该可以自动用于任何和所有添加的分类法.如果不需要,您可以随时为某些分类法、帖子类型等添加中止条件,非常轻松.

I've actually put this code on my test site and it seems to work flawlessly, not matter how deeply (grand-child/great grand-child terms) terms are, and how many are added or removed at a time. Another neat thing is that this hook is already passed the $taxonomy parameter, so it should work for any and all taxonomies that are ever added, automatically. If that's not desired, you can always add an abort condition for certain taxonomies, post types, etc, very easily.

这篇关于选中父类别时自动检查子类别/术语的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆