Exclude Current Post in an ACF Relationship Loop

TLDR;
I have narrowed down that the <Loop> query param of exclude isn’t working in combination with an ACF relationship <Loop>. Any idea what is going on here?

I have a post type for artists and a post type for artwork. I have an ACF bidirectional relationship connecting them.

On the artwork page, I want to display other artwork by that artist. So I have this:

<Set current_id>
  <Field id />
</Set>

<Loop acf_relationship=artist_artwork>
  <Loop acf_relationship=artwork_artist exclude="{Get current_id}">
    <ul>
      <li><Field title /></li>
    </ul>
  </Loop>
</Loop>

The first loop gets you into the artist.
The second loop gets you into the artwork by at artist.
Then we list out all the artwork. That all works!

But since this is on an artwork page, I want to exclude the current art from that list. So I have a <Set> that captures the current artwork’s post id. That also works.

However when I then try to exclude that post ID in the art loop (inner loop), it doesn’t exclude it. It actually doesn’t even exclude it if I just hardcode an ID in there either like:

  <Loop acf_relationship=artwork_artist exclude=24752>

So that means I have narrowed down that it’s the exclude itself that isn’t working in combination with an ACF relationship loop. Any idea what is going on here?

If include doesn’t work, try id:

<Loop post_type=post id="{Field acf_relationship_field_name}" exclude=24752>

I’ve asked Eliot whether we can make relationship loops natively accept query parameters from the post loop, so maybe that will get added in a future version.

@avanti Haha, looks like you’ve ran into this before…

Both include and id pull the relationship objects in.

But exclude still didn’t work for either of them? That seems unexpected? (but then again, it is a real query happening inside of a relationship query, which is a little odd?)

I also tried doing both Loops as the type=post and passing the acf relationship field that way, which pulls in values correctly but the exclude still didn’t work… I really thought that one was going to do it…

I wonder if both id and include work the same way and the inclusion is taking precedence over the exclusion.

@eliot has got a link to this thread so maybe he’ll chime in with insights or a solution.

If you want to get extra creative:

<Loop post_type=post include="{Format replace=24752 with=''}{Field acf_relationship_field_name /}{/Format}">

:laughing:

Sounds good. @eliot :pray:t2:

As for the creative solution, it didn’t output anything… Good try though haha

Hi @zack, you’ve probably read the method i used to exclude the current post then:

<Set name=current_post><Field id /></Set>

<ul>
  <Loop acf_relationship="relationship_name">
      <If field="id" is_not value="{Get current_post}">
        <li><Field title /></li>
      </If>
  </Loop>
</ul>

Yes, the only problem there is I’m trying to show 2 items (using count=2 ). And if the current post is one of the 2, then it will only show 1 haha

But one option that I may just go with could be pulling all, but then only showing 2 with a button to reveal all using js

This looks challenging.

[EDIT]
Is there away to get the ACF Relationship’s data index?
If so, there might be a way using a conditional to detect if the current post is among the two first, and shift the output if this is the case.

[EDIT 2]
<Get loop=count /> returns the data index in the loop

This is working but it’s pretty twisted and requires 2 ACF Relationship loops:

<Set name="current_post"><Field id /></Set>

<Set name="related_current_post"><Loop acf_relationship="my_test_relationship"><If count less_than_or_equal value=2><If field="id" is value="{Get current_post}">true</If></If></Loop></Set>

<ul>
  <Loop acf_relationship="my_test_relationship">
    
    <If check="{Get related_current_post}" includes value=true>
      <If count less_than_or_equal value=3>
        <If field="id" is_not value="{Get current_post}">
          <li>A | <Field title /> (index <Get loop=count />)</li>
        </If>
      </If>
    <Else />
      <If count less_than_or_equal value=2>
        <li>B | <Field title /> (index <Get loop=count />)</li>
      </If>
    </If>
    
  </Loop>    
</ul>

First it checks if the current post is in the 2 first posts of the ACF Relationship loop, and stores the result in a variable (true or blank).

Then it loops through the ACF Relationship again by checking the variable above:

  • If the var is true, the 3 first posts are returned and the current post is skipped, which finally makes 2 posts (screenshot below)
    CleanShot 2024-01-12 at 01.36.55

  • Else, it just returns the 2 first posts (screenshot below)
    CleanShot 2024-01-12 at 01.37.39

Too bad the exclude query parameter doesn’t work for the ACF Relationship loop, it would simplify all that. :wink:

Wow! Now that’s creative!

Weird, it worked for me, but in any case doing a format-replace doesn’t feel like a serious solution haha

Maybe the approach then would just be to run the conditional logic on a list variable beforehand instead of running the logic within the relationship loop. Something like this maybe:

<Set current_id><Field id /></Set>

<Loop type="post" id="419">
  <List name="related_posts">
    <Loop acf_relationship="my_relationship_field">
      <If field="id" is not value="{Get current_id}">
        <Item><Field id /></Item>
      </If>
    </Loop>
  </List>
</Loop>

<ul>
  <Loop post_type="post" id="{Get list=related_posts}" count=2>
    <li><Field title /></li>
  </Loop>
</ul>

My gut feeling is that a relationship field loop is just looping through the values in the field and isn’t actually making a query. If that’s actually the case, then it wouldn’t make sense for it to accept query parameters, since that would “force” the relationship loop type to act as a query, making it less efficient than it is currently. If my intuition is right, then our “hacky” approaches might really be as efficient an approach as any, since any approach that involves filtering with query parameters is going to be introducing an additional query. Hopefully @eliot can chime in with some clarification here about what’s going on behind the scenes.

If I’m right (I very well might not be), then the only change that would make sense to implement would be to have the values of include and exclude take precedence over the value of id so that you could specify a list of IDs and then exclude one/some of them, which doesn’t currently seem to be possible.

That’s another good approach. Thanks!!

Yeah, as for fixing going forward, we can of course apply the same query params to the L&L syntax but do different things behind the scenes instead of forcing it into a query.

So doing exclude on a <Loop acf_relationship=field_name> could just do a separate function on the backend to remove that post from the array without “forcing” it into a loop query?

1 Like

Hi @benjamin, by curiosity, what do you call “doing a format-replace”?
Is it related to the hack i’ve posted?

[EDIT] Sorry, found, it’s in your hack a few days ago:

1 Like

This has been remedied in L&L 4.0.2, where loop query parameters such as exclude (as well as sort, orderby, paged, etc.) now work with the ACF Relationship field.

<Loop acf_relationship=field_name exclude=current>

It was a bit tricky to implement because WP_Query doesn’t natively support combining exclude and include, which the relationship field loop uses.

Note: you cannot combine post__in and post__not_in in the same query.

(From WP_Query: Post & Page Parameters)

The workaround solution was to manually remove IDs from include, if it’s used together with exclude.

4 Likes

Amazing! Thank you @eliot!

1 Like

In this latest version does it also work to do do something like this?

<ul>
<Loop type=artist orderby_field=artist_last_name>
  <li><Field title />
    <Loop acf_relationship=artwork_artist taxonomy=artwork-status exclude=sold>
      <strong><Field title /></strong>
    </Loop>
  </li>
</Loop>
</ul>

This should output artists, along with their artwork (connected with an ACF relationship), but only artwork that isn’t Sold?

I haven’t played around with it myself yet, but it seems that all the query parameters from the post loop now work on the acf_relationship loop. That being said, your particular example definitely wouldn’t work because that’s not what the exclude query parameter is meant for. The post loop docs mention this:

exclude - Exclude by ID or name

Rereading that now, I supposed it could be more clear that it’s intended to “exclude posts by post ID or post name,” but I think the idea was that that was implied since these are all post-related query parameters. I assume you’re trying to exclude something with a particular taxonomy term applied, in which case you’d want to use query parameters intended for that purpose. This might work but I don’t have your data structure to test it:

<Loop acf_relationship=artwork_artist taxonomy=artwork-status taxonomy_compare=not terms=sold>

Thanks Benjamin,

I knew the exclude was wrong, but I couldn’t figure out the taxonomy tags documentation for what I needed. This is great: taxonomy_compare=not terms=sold>

Having some examples on how to use those in the docs for the custom taxonomy (not categories or tags) would be great!

I ended up doing this in php, so I don’t have the setup to test your solution, but it looks accurate! (assuming acf_relationship can use taxonomy_compare - which I think was the root of my question)

1 Like