Home › Forums › Backend Issues (wp-admin) › Bidirectional term-to-term relationship
Ive read about ACF Bidirectional Relationships (https://www.advancedcustomfields.com/resources/bidirectional-relationships/) but this is between posts (Relationship).
What if I want, on a term edit page, to have a field allowing the selection of a term from a different Taxonomy, and to have that relationship be reciprocated in the other side?
Not strictly a “Relationship”and I don’t believe WordPress even supports term-to-term relationships… (?).
+1 for this.
I don’t know if you have checked out https://wordpress.org/plugins/acf-extended/ – it seems to add bidirectional relationships as a feature, but I’m not sure if this is between taxonomy terms or just between posts.
I don’t know if that plugin will do what you want or not, first I’ve heard of it.
Ad far as doing this with code it would work in a similar way. The biggest difference would be that anywhere that you’re getting or setting a value, instead of $post_id
you would use 'term_'.$post_id
for the post you want to get or set the value from. The value you’re setting would be the same $post_id
as this would be the term ID for a taxonomy field.
Thanks for the pointer here, John – I think I’m really close to getting this to work.
I am using an ACF field named surname_linked
to create a relationship between one term in the surname
custom taxonomy and another.
The code below successfully adds a two way relationship between the taxonomy terms, but fails to remove taxonomy terms from the linked term when the term is removed.
Maybe you can spot where I’m going wrong?
/* Bi-directional Surname taxonomy term updating - to keep Surname terms in sync */
function gwsfhs_bidirectional_acf_update_value( $value, $post_id, $field ) {
// vars
$field_name = $field['name'];
$field_key = $field['key'];
$global_name = 'is_updating_' . $field_name;
// bail early if this filter was triggered from the update_field() function called within the loop below
// - this prevents an inifinte loop
if( !empty($GLOBALS[ $global_name ]) ) return $value;
// set global variable to avoid inifite loop
// - could also remove_filter() then add_filter() again, but this is simpler
$GLOBALS[ $global_name ] = 1;
// loop over selected posts and add this $post_id
if( is_array($value) ) {
foreach( $value as $post_id2 ) {
// load existing related posts
$value2 = get_field($field_name, 'surname_'.$post_id2, false);
// allow for selected posts to not contain a value
if( empty($value2) ) {
$value2 = array();
}
$prefix = 'term_';
$post_id = preg_replace('/^' . preg_quote($prefix, '/') . '/', '', $post_id);
// bail early if the current $post_id is already found in selected post's $value2
if( in_array($post_id, $value2) ) continue;
// append the current $post_id to the selected post's 'related_posts' value
$value2[] = $post_id;
// update the selected post's value (use field's key for performance)
update_field($field_key, $value2, 'surname_'.$post_id2);
}
}
// find posts which have been removed
$old_value = get_field($field_name, 'surname_'.$post_id, false);
if( is_array($old_value) ) {
foreach( $old_value as $post_id2 ) {
// bail early if this value has not been removed
if( is_array($value) && in_array($post_id2, $value) ) continue;
// load existing related posts
$value2 = get_field($field_name, 'surname_'.$post_id2, false);
// bail early if no value
if( empty($value2) ) continue;
// find the position of $post_id within $value2 so we can remove it
$pos = array_search($post_id, $value2);
// remove
unset( $value2[$pos] );
// update the un-selected post's value (use field's key for performance)
update_field($field_key, $value2, 'surname_'.$post_id2);
}
}
// reset global varibale to allow this filter to function as per normal
$GLOBALS[ $global_name ] = 0;
// return
return $value;
}
add_filter('acf/update_value/name=surname_linked', 'gwsfhs_bidirectional_acf_update_value', 10, 3);
I don’t know for sure, I think it may have something to do with this part of the code
// find the position of $post_id within $value2 so we can remove it
$pos = array_search($post_id, $value2);
// remove
unset( $value2[$pos] );
Maybe the value you’re getting for $pos is somehow incorrect or somehow does not translate to the correct index, but I can’t say for sure.
Generally, when I’m removing things from an array I build a new array rather than manipulate the existing array and it saves me a lot of headaches.
$new_array = array();
foreach ($old_array as $value) {
if (/*condition to keep value*/) {
$new_array[] = $value;
}
}
$old_array = $new_array;
Looping back on this, I’m surprised to find I can natively set a term-to-term relationship across terms in two different taxonomies (person
and company
) using wp_set_object_terms()
…
$term_taxonomy_ids = wp_set_object_terms( $bill_term_id, $microsoft_term_id, 'company' );
They are just objects.
And I can retrieve the company
connected to a person with wp_get_object_terms
like…
$bills_company_terms = wp_get_object_terms($bill_term_id, 'company');
However, putting a backend UI on that is another matter. Don’t know how to accomplish that. Any ideas?
You would need to create an acf/update_value filter for the taxonomy fields. In this filter you would need to:
1) Get the current value of the field before it will be updated
2) Compare the old value with the new value to see what relationships are being added or removed and update the other end of the relationship accordingly.
3) When updating the other end you will need to get the value of the other end, add or remove the new relationship and then update the other end.
Hi marcusjwilson, have you achieved a working solution for this please?
Sorry @martinko – Not had the time to implement all of John’s solution here. Would be interested if anyone else has come up with code for this.
The topic ‘Bidirectional term-to-term relationship’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.