6

I have a half dozen reference fields on a content type that sits at the bottom of a page under a heading of "Related" and some markup structure. I was checking if node.field_name is not empty, ... in twig before entering and printing "Related" and then each individual field, but in cases where the referenced entities are unpublished, this results in just "Related" and nothing else.

How can I figure out ahead of time if the field I am about to render has actual accessible content to show the user? is content.field_name|render|striptags|trim still the only way?

<div class="info-grid {% if horizontal %}info-grid--horizontal{% endif %}">
    <h2 class="info-grid__title">Related</h2>
    <div class="info-grid__grid">
      {% if node.field_topics is not empty  %}
        {{ content.field_topics }}
      {% endif %}

      {% if node.field_programs is not empty  %}
        {{ content.field_programs }}
      {% endif %}

      {% if node.field_working_groups is not empty  %}
        {{ content.field_working_groups }}
      {% endif %}

      {% if node.field_projects is not empty  %}
        {{ content.field_projects }}
      {% endif %}

      {% if node.field_papers is not empty  %}
        {{ content.field_papers }}
      {% endif %}

      {% if node.field_datasets is not empty  %}
        {{ content.field_datasets }}
      {% endif %}
    </div>
  </div>

Edit: updating with Hudri suggestion, it still prints the h2 of Related:

{% set display_related = false %}

{% if not (node.field_programs.isEmpty == true) and content.field_programs is defined %}
  {% set display_related = true %}
{% endif %}

{% if display_related %}
  <div class="info-grid {% if horizontal %}info-grid--horizontal{% endif %}">
...

enter image description here

3
  • Might need to test this but could you instead move your "Related" heading into the field_name twig template? As it sounds pretty fixed to that field and I think the field's rendering wouldn't be called if there's no content to render (due to the user not having access to the content)
    – Leigh
    Commented Nov 19, 2019 at 16:42
  • There are multiple fields, not just one. The heading is outside of them in a section that renders the fields
    – Kevin
    Commented Nov 19, 2019 at 16:52
  • @Kevin seems to me that you would have to write a long conditional statement that checks all of them and print the title if one of them passes. If I was doing this, I would just create a View block and then I wouldn't have to deal with all these conditionals.
    – No Sssweat
    Commented Nov 19, 2019 at 17:44

3 Answers 3

7

The answers so far are only valid for non reference fields. A reference field is different, because the referenced entities can have different access results than the parent entity. The rendered field can be empty although the field in the node object is not. As explained in How do I hide an empty field if my custom field formatter removes all items? there are two unambiguous empty conditions for the output of the field formatter in {{ content.field_name }}:

  1. Check the first field delta, which always starts with 0:

    {% set display_related = content.field_name.0 is defined %}
    
  2. or check whether the field formatter could find any renderable children and has added the field wrapper:

    {% set display_related = content.field_name['#theme'] is defined %}
    

For a reference field it is important to render content.field_name even if the result is negative, because it contains the cacheable metadata of the access checks. When for example a referenced node is published, the parent node needs to be invalidated and rerendered.

So checking content.field_name|render|striptags|trim is not so bad at all, because this check renders the field content and if the result is negative you don't have to render the field again, because the metadata bubbled up already.


Field Groups

For halve a dozen fields you could use Field Groups. Place all reference fields in a group "Related" and display the header in the field group template. If the field group template doesn't hide automatically you can check with striptags as before. You get the entire rendered result of all fields in the variable children.

Although I would prefer to check the specific content you expect to be inside of the field group and so ignore labels or other things that may be added later. The already rendered field group content is in a markup object and you need to render it again in twig, so you can check it casted as a string. For example whether it contains a linked node:

field-group-html-element.html.twig:

{% set display_related = '<a href' in children|render %}
0

Is content.field_name|render|striptags|trim still the only way?

That's a way a lot of people choose to do this check, if you're doing it purely in twig. But I would argue it's not the only way to achieve this.

What you can also do is check the node (or paragraph, term etc any Drupal fieldable content entity) object's field instead of the content array. So instead of {% if content.field_name... you do {% if not node.field_name.isEmpty %} which also works iirc...

What's also possible is to just use a PHP preprocessor to set a count or some such variable, which counted the number of values in the node, and you can just {% if not count %}. Hope this helps.

2
  • 2
    I dont think the issue is if the field has no values set, its if the user doesn't have permission to view the referenced content due to it being unpublished. So he doesn't want his "Related" heading shown when none of the referenced entities are viewable to them
    – Leigh
    Commented Nov 19, 2019 at 16:43
  • @Leigh that's not how I interpreted the question, but I may be wrong. I feel like permissions etc should be handled at PHP level or maybe even at the Query level (filter unpublished nodes), but Twig seems like the wrong place to do this. Please correct me if I'm wrong :)
    – Beebee
    Commented Nov 19, 2019 at 16:45
0

My own bullet-proof version that worked even in the most weirdest edge cases:

  • it works for all field types
  • it checks if the field exists
  • it checks if the field is not empty
  • it checks if the field is not hidden in display mode
{% if not (node.field_whatever.isEmpty == true) and content.field_whatever is defined %}
  <div class="whatever_markup">
    {{ content.field_whatever }}
  </div>
{% endif %}

Replace node and you can drop it into any entity template.

8
  • 2
    Does this check if the user has access & is published? The question is talking about entity references.
    – No Sssweat
    Commented Nov 19, 2019 at 17:27
  • AFAIK if the referenced entity from field_foo is not renderable, content.field_foo should be empty.
    – Hudri
    Commented Nov 19, 2019 at 17:29
  • 1
    You're 100% correct, but Kevin wants to print a header/title that says "Related", but if he was to follow this answer, his "Related" header/title would print no matter what. Thus, he wants to find a way to check if user has access to those referenced entities so he can condition the printing of the header/title.
    – No Sssweat
    Commented Nov 19, 2019 at 17:33
  • Same procedure, it is just going to be a damn long {% if (not (node.field_foo.isEmpty == true) and content.field_foo is defined) OR (not (node.field_bar.isEmpty == true) and content.field_bar is defined) ... %}
    – Hudri
    Commented Nov 19, 2019 at 17:38
  • It still prints the header, I will update question with what I am trying as a test.
    – Kevin
    Commented Nov 19, 2019 at 17:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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