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
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It only takes a minute to sign up.
Sign up to join this communityHooking 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 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
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');
}
}
}
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);
}
}
}
}
}