ACF Pro Bi-Directional Updates

Hi,

I have been trying to set-up a bi-directional link in ACF between two post types. I have a post type “Memorials” which has an ACF field called “casualties_listed”. The second post type is called “Casualties” with an ACF field called “casualty_name”.

When “casualty_name” is filled out and the post is updated, I want to have the contents of “casualty_name” populating into “Memorial”'s “casualties_listed” field.

I have tried following the instructions in https://www.advancedcustomfields.com/resources/bidirectional-relationships/ and https://www.youtube.com/watch?v=oHFa7QwuPgU, but cannot seem to get it working

I am using single and archive layouts for the post types.

Are you able to help with this, please?

Thanks,
Christopher

Hey Christopher,

Thanks for reaching out!

You need to add the code from here https://www.advancedcustomfields.com/resources/bidirectional-relationships/ to your child theme functions.php so that the bi-directional ACF features will work. You just need to update the filter add_filter('acf/update_value/name=related_posts', 'bidirectional_acf_update_value', 10, 3); to the name of your relationship field. I am referring to the name=related_posts. It was properly explained in the youtube tutorial on how it is done.

Hope that helps and let us know how it goes.

Hi @marc_a,

That is exactly what I did. In my case name=casualties_listed. It does not populate that field though. I have tried with both adding a new casualty and updating an existing one. I don’t understand why it is not working.

Thanks,
Christopher

Any ideas @marc_a?

Hey Christopher,

Accessing your staging website requires another set of verifications. Please provide us with the username and password so we can properly check your issue because the credentials above is not working anymore.

Thank you.

HI @marc_a,

As with the last time, the directory protection and WP login use the same credentials - copy in Secure Note.

Thanks,
Christopher

Hey Christopher,

In my own understanding, the bi-directional will work with one ( relationship ) ACF field that is assigned in both Memorials and Casualties. You need to restructure your ACF field or create a new field that is assigned to the Memorials and Casualties post type.

Let’s say, for example, you created a relationship called casualties_memorial_listed. In order for the bi-directional function works, you need to add this code in your child theme functions.php.

function 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, $post_id2, false);
            
            
            // allow for selected posts to not contain a value
            if( empty($value2) ) {
                
                $value2 = array();
                
            }
            
            
            // 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, $post_id2);
            
        }
    
    }
    
    
    // find posts which have been removed
    $old_value = get_field($field_name, $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, $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, $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=casualties_memorial_listed', 'bidirectional_acf_update_value', 10, 3);

the casualties_memorial_listed is the field name of your relationship field.

Hope that helps and let us know how it goes.

Hi @marc_a,

Thank you again for your guidance. I have got around the issue in a similar, but slightly different way.

As you know my CPTs are Memorial and Casualty. Memorials has a Relationship ACF field = memorial_casualties. Casualties has a Relationship ACF field = casualty_memorial_listed.

I then have two sections of code for my functions.php:

function link_casualty_to_memorial( $value, $post_id, $field ) {
	$field_name  = $field['name'];
	$global_name = 'is_updating_' . $field_name;

	if ( ! empty( $GLOBALS[ $global_name ] ) ) {
		return $value;
	}

	$GLOBALS[ $global_name ] = 1;

	if ( is_array( $value ) ) {
		foreach ( $value as $memorial_post_id ) {
			$casualties = get_field( 'field_63daac69ede1b', $memorial_post_id );

			if ( empty( $casualties ) ) {
				$casualties = array();
			}

			if ( in_array( $post_id, $casualties ) ) {
				continue;
			}

			$casualties[] = $post_id;

			update_field( 'field_63daac69ede1b', $casualties, $memorial_post_id );
		}

	}

	$old_value = get_field( $field_name, $post_id, false );

	if ( is_array( $old_value ) ) {

	foreach ( $old_value as $memorial_post_id ) {

    			if ( is_array( $value ) && in_array( $memorial_post_id, $value ) ) {
    			continue;
    		}

			$casualties = get_field( 'field_63daac69ede1b', $memorial_post_id, false );

			if ( empty( $casualties ) ) {
				continue;
			}

			$pos = array_search( $post_id, $casualties );

			unset( $casualties[ $pos ] );

			update_field( 'field_63daac69ede1b', $casualties, $memorial_post_id );
		}
	}

	$GLOBALS[ $global_name ] = 0;

	return $value;
}

function link_memorial_to_casualty( $value, $post_id, $field ) {
	$field_name  = $field['name'];
	$global_name = 'is_updating_' . $field_name;

	if ( ! empty( $GLOBALS[ $global_name ] ) ) {
		return $value;
	}

	$GLOBALS[ $global_name ] = 1;

	if ( is_array( $value ) ) {
		foreach ( $value as $casualty_post_id ) {
			$memorials = get_field( 'field_63da97eec7d7f', $casualty_post_id );

			if ( empty( $memorials ) ) {
				$memorials = array();
			}

			if ( in_array( $post_id, $memorials ) ) {
				continue;
			}

			$memorials[] = $post_id;

			update_field( 'field_63da97eec7d7f', $memorials, $casualty_post_id );
		}

	}

	$old_value = get_field( $field_name, $post_id, false );

	if ( is_array( $old_value ) ) {

		foreach ( $old_value as $casualty_post_id ) {

			if ( is_array( $value ) && in_array( $casualty_post_id, $value ) ) {
				continue;
			}

			$memorials = get_field( 'field_63da97eec7d7f', $casualty_post_id, false );

			if ( empty( $memorials ) ) {
				continue;
			}

			$pos = array_search( $post_id, $memorials );

			unset( $memorials[ $pos ] );

			update_field( 'field_63da97eec7d7f', $memorials, $casualty_post_id );
		}
	}

	$GLOBALS[ $global_name ] = 0;

	return $value;
}

add_action( 'acf/update_value/name=casualty_memorial_casualties', 'link_casualty_to_memorial', 10, 3 );
add_action( 'acf/update_value/name=memorial_casualties', 'link_memorial_to_casualty', 10, 3 );

In the Relationship fields themselves, the “Filter By Post Type” field references the post_type that is being linked to.

This works for me and does what I need. I hope it is useful for other people looking to deal with Relationships between post_types.

Thanks again,
Christopher

Hey Christopher,

We’re glad that you figure it out! If you have any other concerns or clarifications regarding our theme features, feel free to open up a new thread.

Thank you.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.