Update on 3 Jan 2024: You may also be interested in this newer tutorial.
This Pro tutorial walks through setting up and using an ACF Relationship type of field in Bricks.
We are going to set up a bidirectional relationship between an event CPT (Custom Post Type) and venue CPT, then see how related venue(s) can be shown on single event pages and related event(s) on single venue pages.
Editing an event (Event 1):

Editing the venue that’s set for the above event (Venue 1):

A single event on the front end:

A single venue on the front end:

We shall also ensure that
- the Section having the related events/venues get output only if there’s at least 1 published related event/venue.
- heading inside the Section says Events or Event depending on whether there are/is more than 1 or 1 related event and similarly, Venues or Venue.
Step 1
Create both the CPTs using a plugin like CPT UI or otherwise.
Step 2
Create a ACF field group for one of the CPTs (doesn’t matter for which you do first) having a Relationship field.

In the “Filter by Post Type” field, select the other CPT.
Step 3
Create another field group similar to the above but for the other CPT. You may find going back to the field groups list and duplicating and editing easier.

Ensure that the Field Name is exactly the same as the one from the last step.
In the “Filter by Post Type” field, select the other CPT.
Step 4
Add the following code in your child theme’s functions.php or a code snippets plugin:
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=event_venue_relationship', 'bidirectional_acf_update_value', 10, 3);
In
acf/update_value/name=event_venue_relationship
replace event_venue_relationship with the name of your Relationship-type field.
Step 5
Add some posts of both the post types, in this example, events and venues.
Edit a post of one of your CPTs, in this example, events.
Select 1 or more venues and update.
Repeat for all other posts of this post type.
Edit a post of your other CPT, in this example, venues.
It should automatically show the event(s) that have been set for this venue.
When editing a post of either CPT, you could edit the related items of the other CPT and they should automatically be in sync/get updated.
If you have already set any related CPT posts before adding the code from Step 4, you’d need to edit and update all such posts.
Step 6
Create a Bricks template for single items of your first post type, in this example, events.
Edit it with Bricks.
Add a Section and inside its Container, Post Title and Post Content elements.
Add another Section and inside its Container a “Venue” Heading.
Add a Container below it and inside, a Block element.
Enable query loop for the Block.
You would normally be selecting the query type to be your ACF Relationship here. But as of Bricks 1.6.1, it doesn’t work for the first post type’s single template. Strangely, it does for the second post type.
Let’s work around this.
Select Venues (your second post type) for Post type.
Add Post Title (and any other desired elements) inside the Block.

If you check any of your events on the front end at this stage, it should show all the published venues and not just the related one(s).
Add the following code in your child theme’s functions.php or the code snippets plugin:
add_filter( 'bricks/posts/query_vars', function( $query_vars, $settings, $element_id ) {
if ( $element_id === 'odsfnq' && class_exists( 'ACF' ) ) {
$query_vars['post__in'] = wp_list_pluck( get_field( 'event_venue_relationship' ), 'ID' );
}
return $query_vars;
}, 10, 3 );
Replace odsfnq with the Bricks ID of your query loop element and event_venue_relationship with the ACF field name.
Next, let’s define a custom function that returns the count of related venues/events.
// Function to get the count of related venues for a single event or related events for a single venue when using ACF Relationship
function bl_get_related_venue_or_event_count() {
return count( get_field( 'event_venue_relationship' ) );
}
Apply a Dynamic data condition for the Section to make it be output only if there’s at least 1 related venue.

{echo:bl_get_related_venue_or_event_count}
and to add s at the end of “Venue” heading text,
// Add "s" at the end of a specific heading element's text if there is more than 1 related post (using ACF Relationship).
add_filter( 'bricks/element/settings', function( $settings, $element ) {
if ( $element->id === 'jweuno' && bl_get_related_venue_or_event_count() > 1 ) {
$settings['text'] .= 's';
}
return $settings;
}, 10, 3 );
Replace jweuno with the Bricks ID of your heading element.
Step 7
Create a Bricks template for single items of your second post type, in this example, venues.
Edit it with Bricks.
Add a Section and inside its Container, Post Title and Post Content elements.
Apply the Dynamic data condition on the Section like in the previous step.
Add another Section and inside its Container a “Event” Heading.
Add a Container below it and inside, a Block element.
Enable query loop for the Block.
Set the query type to be your ACF Relationship here.

Regarding adding s at the end of “Event” heading when there are more than 1 related events:
Edit the line of code inside the function hooked to bricks/element/settings filter.
Change
if ( $element->id === 'jweuno' && bl_get_related_venue_or_event_count() > 1 ) {
to
if ( ( $element->id === 'jweuno' || $element->id === 'wrjiqr' ) && bl_get_related_venue_or_event_count() > 1 ) {
where jweuno is the Bricks ID of your heading element having “Venue” text from the first CPT template and wrjiqr is the Bricks ID of your heading element having the “Event” text from the other CPT template.