2

I have a section of reviews that has a selection of entries fields that relate to entries in other sections. For instance Product A Review might relate to Product A pre-release news.

On the review template, if there is a related entry, then it is included in the page for the review.

But elsewhere on the News listing template, a teaser for the same news entry can also appear.

If the news entry is related to a review, then the link goes to the review detail page, but if the news entry isn't related, then it goes to its own news detail page.

I've tried using craft.entries.section(sectionHandle).relatedTo(entry) which would be fine if there was only one related entries field, but there are several which relate to different sections.

So how do I test if a particular entry is related to a particular field in another section?

EDIT:

Based on Evan's answer below, I'm using the code he posted but have modified it to look like this:

    {% set relatedReview = craft.entries.section('reviews').relatedTo({
        targetElement: entry,
        field: ['field1','field2','field3','field4']
      }).one()
    %}

That works fine in that it tells me if a relationship exists for one of those, but I need to modify the link that the entry goes to in the format {{ relatedReview.url ~ '#field1' }} or something similar, in other words, the link goes to a fragment anchor on the page which is the same as the field name.

How would I do that?

2
  • Ahh, so to clarify: you're trying to link not just to the review, but a specific section on the review page that pertains to the news article that was clicked on? Jul 1 at 18:51
  • @EvanWarner yes, correct.
    – Tyssen
    Jul 1 at 22:03
3

So if I'm understanding corrently, your Review entries contain multiple entries fields, one of which stores News entries related to the product review?

If that's correct, then let's assume that field is called relatedNews. You can utilize advanced relations to find what you're looking for. So for an individual News entry you could do the following:

{% set relatedReview = craft.entries.section('reviews').relatedTo({
    targetElement: myNewsEntry,
    field: 'relatedNews'
  }).one()
%}
{% if relatedReview %}
  {# link to review #}
{% else %}
  {# link to news #}
{% endif %}

Unfortunately while this works great at an individual level, this is a super inefficient thing to do for every News entry as you loop through them on an index page layout (you'd make an extra DB call for every article). What may resolve this is to reverse your relationship: put a relatedReviews field on your News entry type and select reviews from there. Then as you're looping through News on the index page you can check each one for the presence of a related review (remember to eager load the relatedReviews field).

On an individual review page you can then utilize the advanced relation lookup to find related news via:

{% set relatedNews = craft.entries.section('news').relatedTo(myReviewEntry).all() %}

Since you're just making this one call on a Review page, it's efficient and can be cached.

Hopefully this reversal is possible for you to implement. If not, there are other solutions, but they'd be heavier on your page performance.


Afterthought

It's worth noting (if I understand your setup correctly) that you've got a many-to-many situation: reviews can be related to multiple news articles, and news can be related to multiple reviews. Your direct relations are therefore going to break down at scale because for every new post, an admin would have to go back to previous entries and update relations where appropriate. The better way to manage this would be to have a Products section through which both other sections make their connections. In News you relate any products mentioned, and in Reviews you relate the products being reviewed. This way an entry's relations would never need to update unless the entry itself was updated to speak about different products. This is likely a much bigger change to your way of organizing/thinking than your original post asked for, but I thought it was worth mentioning in case it helps you avoid a huge future headache.


Sidebar: Improving Performance

Now that we know you need to stick with the relations as you had them originally, here's a tip to improve the page's query performance if you need to. Instead of running an additional DB query for every news article, you can first run one query for all reviews with their news entry fields eager loaded. The resulting dataset can then be used to find matching reviews. There would be many different ways to approach this, but performance will be even better if you can process the data once first to convert it to a lookup table where your news article IDs act as the keys, with arrays of matching reviews:

[
  '842' => [ // 842 is a news article id
    [
      'review' => reviewEntry,
      'viaField' => 'fieldName',
    ],
  ],
  '177' => [/* etc. */]
]

Whether this is worth the effort for the performance gain is going to be dependent on your real world situation, so only pursue it if you need to solve performance issues.

3
  • Unfortunately, this is such a large site already that adding extra relationship fields now is just not possible. The code you've posted above, although it may be inefficient, has got me close to where I need to be. I've edited my question though to provide a bit more context.
    – Tyssen
    Jul 1 at 9:32
  • I'm going to mark this as the accepted answer because it answered the question as I had it originally, but it was a combination of both this and RitterKnight's answer which got me what I was after. 👍
    – Tyssen
    Jul 1 at 22:15
  • 1
    @Tyssen cool! I just edited in a performance tip that may help if you find the page is sluggish with all the DB hits. Good luck! Jul 1 at 22:46
3

Lots of pieces to this question.

Since you need to check each field, something like:

{% set whichField = null %}
{% for checkField in ['field1','field2','field3','field4'] %}
  {% if attr(relatedReview,checkField) is not empty %}
    {% set whichField = checkField %}
  {%endif%}
{% endfor %}

{{ relatedReview.url ~ '#' ~ whichField }}
3
  • Thanks, that got me pretty close. I needed to change it to {% if attribute(relatedReview,checkField) is defined and attribute(relatedReview,checkField) is not empty %}
    – Tyssen
    Jul 1 at 22:08
  • 1
    I've accepted Evan's answer as it did answer the question as I originally posted it, but both your answers combined got me what I was after. 👍
    – Tyssen
    Jul 1 at 22:16
  • @Tyssen: no worries, glad it helped! Jul 6 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.