Posted on

ACF: Indexing relationship content

If your posts include content from related posts using the Advanced Custom Fields relationship functionality, Relevanssi doesn’t index that content by default. Even if you set Relevanssi up to index the ACF fields, the relationship fields do not include any content, just references to other posts. Those, even if indexed, are not particularly helpful.

ACF features couple of different relationship fields: Relationship, Page Link, Post Object, Taxonomy and User relationship. They all function in a similar fashion: the custom field has the IDs of the related objects. In the case of posts and pages, it’s the post ID. For users, the user ID is listed and for taxonomy relations, the term ID (the term taxonomy is fixed in the custom field settings).

Relationship fields
Sample relationship fields in ACF.

Some fields have the choice of return value being the ID or the object, but that doesn’t make any difference in the database: it’s always the ID that is stored, and that option only affects what get_field() returns.

Now, in order to get Relevanssi to index data from the related posts, we need an additional filter function on relevanssi_content_to_index:

add_filter( 'relevanssi_content_to_index', 'rlv_relationship_content', 10, 2 );
function rlv_relationship_content( $content, $post ) {
	// Fetching the post data by the relationship field.
	$relationships = get_post_meta( $post->ID, 'relationship_field', true );
	if ( ! is_array( $relationships ) ) {
		$relationships = array( $relationships );
	}
	foreach ( $relationships as $related_post ) {
		$content .= ' ' . get_the_title( $related_post );
	}
 
	// Fetching the user data.
	$users = get_post_meta( $post->ID, 'user_connection', true );
	if ( ! is_array( $users ) ) {
		$users = array( $users );
	}
	foreach ( $users as $user ) {
		$userdata = get_userdata( $user );
		$content .= ' ' . $userdata->display_name;
	}

	// Fetching the name of the taxonomy connection field
    // information field. The name of this field is the name
    // of your taxonomy connection field with an underscore prefix.
	$taxonomy_info_field_name = get_post_meta( $post->ID, '_taxonomy_connection', true );
 
	// Fetching the name of the taxonomy from the information field.
	global $wpdb;
	$taxonomy_field_info = $wpdb->get_var(
    	$wpdb->prepare(
        	"SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = %s",
        	$taxonomy_info_field_name
        )
    );
	$taxonomy_field_info = unserialize( $taxonomy_field_info ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
	$taxonomy            = '';
	if ( isset( $taxonomy_field_info['taxonomy'] ) ) {
		$taxonomy = $taxonomy_field_info['taxonomy'];
	}
 
	// Or you can just skip all that and set the
  	// $taxonomy variable directly.
 
	// Fetching the taxonomy term data.
	if ( isset( $taxonomy ) ) {
		$taxonomies = get_post_meta(
          	$post->ID,
          	'taxonomy_connection',
          	true
        );
		if ( ! is_array( $taxonomies ) ) {
			$taxonomies = array( $taxonomies );
		}
		foreach ( $taxonomies as $term_id ) {
			$term = get_term( $term_id, $taxonomy );
			$content .= ' ' . $term->name;
		}
	}

	return $content;
}

Change the field names to match the names of your fields. In this case, the relationship field is called relationship_field, the user connection field is called user_connection and the taxonomy connection field is called taxonomy_connection. Your fields name are likely different, so make sure the get_post_meta() calls reference the correct field name.

This function covers fetching post data, user data and taxonomy term data. For taxonomy terms, there’s the more complete solution that figures out the taxonomy from the field settings, but if the taxonomy is never going to change, you can skip all that and just set the taxonomy in the code and be done with that.

This function doesn’t use get_field() from ACF, but instead fetches the fields using get_post_meta(). This means the function doesn’t care about the post ID or post object setting, and only works on post IDs. In this example, the code takes the post title, user display name and taxonomy term name, but you can get any post data based on the post ID, use any user data provided by get_userdata() and any term content provided by get_term().

Sometimes you have a flexible content field, which makes it impossible to use get_post_meta(), because you don’t know the exact field name. In that case you can use a direct database call to fetch fields using wild cards. This function would find a relationship field called people inside a flexible content field sidebar_groups:

add_filter( 'relevanssi_content_to_index', 'rlv_relationship_content', 10, 2 );
function rlv_relationship_content( $content, $post ) {
	global $wpdb;
	$relationships = unserialize( $wpdb->get_var( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key LIKE 'sidebar_groups_%_people'" ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
	foreach ( $relationships as $related_post_id ) {
		$content .= ' ' . get_the_title( $related_post_id );
	}
	return $content;
}

2 comments ACF: Indexing relationship content

Leave a Reply

Are you a Relevanssi Premium customer looking for support? Please use the Premium support form.

Your email address will not be published. Required fields are marked *