Automatically Assign Parent Terms When A Child Term is Selected

I have deep hierarchical taxonomy and I want to have all parent term assigned when I select a child term. I need it for category structure on a online listing/classified site.

CPT name: product

Read More

Taxonomy Name: product_cat

Related posts

4 comments

  1. Hooking into save_post action.

    add_action('save_post', 'assign_parent_terms', 10, 2);
    
    function assign_parent_terms($post_id, $post){
    
        if($post->post_type != 'product')
            return $post_id;
    
        // get all assigned terms   
        $terms = wp_get_post_terms($post_id, 'product_cat' );
        foreach($terms as $term){
            while($term->parent != 0 && !has_term( $term->parent, 'product_cat', $post )){
                // move upward until we get to 0 level terms
                wp_set_post_terms($post_id, array($term->parent), 'product_cat', true);
                $term = get_term($term->parent, 'product_cat');
            }
        }
    }
    

    While loop ensures we go upward until we hit top level terms.

  2. The options above should work, this function will work for any object whenever terms are set, and using set_object_terms allows you to let the action handle traversing up the hierarchy

    add_action( 'set_object_terms', 'auto_set_parent_terms', 9999, 6 );
    
    /**
     * Automatically set/assign parent taxonomy terms to posts
     * 
     * This function will automatically set parent taxonomy terms whenever terms are set on a post,
     * with the option to configure specific post types, and/or taxonomies.
     *
     *
     * @param int    $object_id  Object ID.
     * @param array  $terms      An array of object terms.
     * @param array  $tt_ids     An array of term taxonomy IDs.
     * @param string $taxonomy   Taxonomy slug.
     * @param bool   $append     Whether to append new terms to the old terms.
     * @param array  $old_tt_ids Old array of term taxonomy IDs.
     */
    function auto_set_parent_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
    
        /**
         * We only want to move forward if there are taxonomies to set
         */
        if( empty( $tt_ids ) ) return FALSE;
    
        /**
         * Set specific post types to only set parents on.  Set $post_types = FALSE to set parents for ALL post types.
         */
        $post_types = array( 'product' );
        if( $post_types !== FALSE && ! in_array( get_post_type( $object_id ), $post_types ) ) return FALSE;
    
        /**
         * Set specific taxonomy types to only set parents on.  Set $tax_types = FALSE to set parents for ALL taxonomies of this post types.
         */
        $tax_types = array( 'product_cat' );
        if( $tax_types !== FALSE && ! in_array( get_post_type( $object_id ), $post_types ) ) return FALSE;
    
        foreach( $tt_ids as $tt_id ) {
    
            $parent = wp_get_term_taxonomy_parent_id( $tt_id, $taxonomy );
    
            if( $parent ) {
                wp_set_post_terms( $object_id, array($parent), $taxonomy, TRUE );
            }
    
        }
    
    }
    

    This gist will have any updates or patches if I add them later:
    https://gist.github.com/tripflex/65dbffc4342cf7077e49d641462b46ad

  3. The code has some bugs as provided above. Use the following code to also make in working in the quick edit modus: How to hook into the quick edit action? (provided by Pieter Goosen)

    add_action('save_post', 'assign_parent_terms');
    
    function assign_parent_terms($post_id){
    global $post;
    
    if(isset($post) && $post->post_type != 'product')
    return $post_id;
    
    // get all assigned terms   
    $terms = wp_get_post_terms($post_id, 'product_cat' );
    foreach($terms as $term){
    while($term->parent != 0 && !has_term( $term->parent, 'product_cat', $post )){
        // move upward until we get to 0 level terms
        wp_set_object_terms($post_id, array($term->parent), 'product_cat', true);
        $term = get_term($term->parent, 'product_cat');
         }
      }
    }
    
  4. Improved! Thks @Sisir

    Now, you can define more than one post type and term.

    You can define Allowed Post Types in ($arrayPostTypeAllowed) array, and Allowed Terms in ($arrayTermsAllowed) array.

    add_action('save_post', 'assign_parent_terms', 10, 2);
    
    function assign_parent_terms($post_id, $post){
        $arrayPostTypeAllowed = array('product');
        $arrayTermsAllowed = array('product_cat');
    
        //Check post type
        if(!in_array($post->post_type, $arrayPostTypeAllowed)){
            return $post_id;
        }else{
    
            // get all assigned terms   
            foreach($arrayTermsAllowed AS $t_name){
                $terms = wp_get_post_terms($post_id, $t_name );
    
                foreach($terms as $term){
    
                    while($term->parent != 0 && !has_term( $term->parent, $t_name, $post )){
    
                        // move upward until we get to 0 level terms
                        wp_set_post_terms($post_id, array($term->parent), $t_name, true);
                        $term = get_term($term->parent, $t_name);
                    }
                }
            }
        }
    }
    

Comments are closed.