ACF Relationship + WP Template Parts

Any help with this would be greatly appreciated – I’ve been grappling with it for days 🙂

I have 2 post types – product + offer

I have an ACF relationship field related_products.

This field returns an array of post IDs Array ( [0] => 395 [1] => 120 [2] => 388 [3] => 391 )

I am using related_products on the offer post type – it’s a one-way relationship (not bi-directional).

Each of my post types has a “card” template part that I use in all my loops – that’s what I want to do here … use the related_products IDs to get the product card parts and show them on the offer.

I had no luck with the ACF documentation – but that’s probably because I’m a noob.

  • https://www.advancedcustomfields.com/resources/querying-relationship-fields/
  • https://www.advancedcustomfields.com/resources/acf-fields-relationship-query/

Instead, I set up a custom WP_Query that get’s me close, but not there.

The if ( $custom_query->have_posts() ) IS working – when an offer has related products, the correct product cards ARE displayed.

But, when an offer has no related_products, ALL products are being shown.

My questions are:

  • Is a custom WP_QUERY the right/best way to go about this?
  • If so, what do I need to fix in the query?

Thank you for your time and help 🙂

// Array ( [0] => 395 [1] => 120 [2] => 388 [3] => 391 )
$related_products = get_field('related_products');

$args = array( 
    'post_type' => 'product',
    'post__in' => $related_products,    
    'fields' => 'ids',
    'cache_results'  => false,
    'update_post_meta_cache' => false, 
    'update_post_term_cache' => false, 
    'posts_per_page' => -1, 
    'paged' => false,
);

$custom_query = new WP_Query( $args );

if ( $custom_query->have_posts() ) :  
    while ( $custom_query->have_posts() ) : 
        $custom_query->the_post(); 
        get_template_part( 'parts/card', get_post_type() );
    endwhile;
else : 
    // do something else
endif; 
wp_reset_query();

3 Answers
3

But, when an offer has no related_products, ALL products are being
shown.

This is because you’re not doing anything to check if the field has a value before running your query. If this is empty:

$related_products = get_field('related_products');

Then that makes the query argument equivalent to:

'post__in' => [],

And if that argument value is empty, it doesn’t query no posts, it just gets ignored, which means you’re query is the equivalent of:

$args = array( 
    'post_type'              => 'product',
    'fields'                 => 'ids',
    'cache_results'          => false,
    'update_post_meta_cache' => false, 
    'update_post_term_cache' => false, 
    'posts_per_page'         => -1, 
    'paged'                  => false,
);

Which is querying all products.

So you need to check if your field has any values before doing anything, then only querying if there are any.

Your other problem is that you have fields set to ids. If you do this then the result is just an array of posts IDs, which you already have because that’s what you’re querying. If you want to use the loop with your results, you need to remove that line. So all you should have is:

$related_products = get_field( 'related_products' );

if ( $related_products ) {
    $args = array( 
        'post_type' => 'product',
        'post__in'  => $related_products,    
    );

    $custom_query = new WP_Query( $args );

    if ( $custom_query->have_posts() ) :  
        while ( $custom_query->have_posts() ) : 
            $custom_query->the_post(); 
            get_template_part( 'parts/card', get_post_type() );
        endwhile;
    else : 
    // do something else
    endif;

    wp_reset_postdata();
}

But doing this query at all is unnecessary. If you set the field to return post objects, rather than IDs, you can just loop through those:

$related_products = get_field( 'related_products' );

if ( $related_products ) {
    global $post; // Necessary.

    foreach ( $related_products as $post ) : // Must be called $post. 
        setup_postdata( $post ); 
        get_template_part( 'parts/card', get_post_type() );
    endforeach;

    wp_reset_postdata();
}

This is the same as Faye’s answer, I’m just including it for completeness. If you’re receiving any errors from that, then the issue is somewhere else. Probably inside your card template.

Leave a Comment