Support

Account

Home Forums Backend Issues (wp-admin) Bidirectional term-to-term relationship

Solving

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;
    
  • Much appreciated, John. I’ll take another look.

Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.

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 Cookie Policy. If you continue to use this site, you consent to our use of cookies.