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

Taxonomy Name: product_cat

up vote 10 down vote accepted

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.

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');
     }
  }
}
  • save_post hook also passes the $post object. Removed global on my code and used the passed object instead. This should fix the issue :) – Sisir Jul 11 '14 at 4:18
  • I am not very used to these kind of modifications. In what file do I put this to make it work? – Oscar May 18 '15 at 9:33

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);
                }
            }
        }
    }
}
  • 1
    Please add an explanation to your answer: why could that solve the problem better? – fuxia Jul 17 '15 at 21:18
  • Done @toscho tks – Marcio Dias Jul 27 '15 at 21:06

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 post types to only set parents on.  Set $post_types = FALSE to set parents for ALL 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

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.