wp_set_post_terms()
uses wp_set_object_terms()
. There is an action hook called set_object_terms
which fires on successful setting of an object’s terms. The action hook looks like this
do_action ( 'set_object_terms', int $object_id, array $terms, array $tt_ids, string $taxonomy, bool $append, array $old_tt_ids )
What we can do here is, inside our action callback function, we can check whether the terms that we inserted is top level, and if not, we can get the parent ID’s from the term objects and then add the parent terms to the post object
You can try the following:
add_action( 'set_object_terms', function ( $object_id, $terms, $tt_ids, $taxonomy )
{
// Lets make sure we run this only once
remove_action( current_action(), __FUNCTION__ );
// Lets only target the category taxonomy, if not, lets bail
if ( 'category' !== $taxonomy )
return;
// Make sure we have terms to avoid bugs
if ( !$tt_ids )
return;
// Get all the terms already assinged to the post-
$post_terms = get_the_terms( $object_id, $taxonomy );
if ( $post_terms ) {
$post_term_ids = wp_list_pluck( $post_terms, 'term_id' );
// Bail if $post_term_ids === $tt_ids
if ( $post_term_ids === $tt_ids )
return;
}
// We are busy with the category taxonomy, continue to execute
$parent_ids = [];
// Lets loop through the terms and get their parents
foreach ( $tt_ids as $term ) {
// Get the term object
$term_object = get_term_by( 'id', $term, $taxonomy );
// If top level term, just continue to the next one
if ( 0 === $term_object->parent )
continue;
// Our term is not top level, save the parent term in an array
$parent_ids[] = $term_object->parent;
}
// Make sure we have parent terms, if not, bail
if ( !$parent_ids )
return;
// Make sure we do not have duplicate parent term ID's, if so, remove duplicates
$parent_ids = array_unique( $parent_ids );
// Make sure that our parent id's not in the $terms array, if so, remove them
$parent_ids = array_diff( $parent_ids, $tt_ids );
// Make sure we still have parent ID's left
if ( !$parent_ids )
return;
// Lets add our parent terms to the object's other terms
wp_set_object_terms( $object_id, $parent_ids, $taxonomy, true );
}, 10, 4 );
EDIT – Use-case
The above code goes into your functions.php
and will automatically add the parent terms to the post if we pass any child terms to wp_set_object_terms()
.
Now, in your template, you can do the following
$child_cat_ids = [120]; // Array of child categories
wp_set_object_terms(
147, // Post ID
$child_cat_ids, // Array of child category ID's
'category', // Taxonomy the terms belongs to
true // Only append terms to existing ones
);
Note that you only need to worry about the child category you want to add to the post. As I said, the action above will take care to add the correct parent term to the post