36

I need to take control over the rendering of a field_admin_tags field in a node.html.twig template.

This WORKS:

  • {{ content.field_admin_tags }} — Renders everything (label + all field values)
  • {{ content.field_admin_tags.0 }} — Renders only the first value in the field, and no label

PROBLEM: I have no control over the markup surrounding the tags, e.g. <ul><li>...</li></ul>.

So my idea was to iterate over the render array.

But that DOES NOT work:

{% for tag in content.field_admin_tags %}
  {{ tag }}
{% endfor %}

I get: Exception: Object of type Drupal\node\Entity\Node cannot be printed.

I think I'm iterating over the keys/values of the render array vs the items inside the field (if I print out an "X" in each loop, I get 20 X's while I only have two or three values in this field).

I'd like to iterate over content.field_admin_tags.0, content.field_admin_tags.1, etc.

Any idea how to fix this? Thanks.

1

8 Answers 8

25

You can fix this in a field twig. There you can use the existing loop to iterate over the field items:

node.html.twig

{{ content.field_admin_tags }}

field--field-admin-tags.html.twig

<ul{{ attributes }}>
  {% for item in items %}
    <li>{{ item.content }}</li>
  {% endfor %}
</ul>

This example replaces <div> with <ul>. Don't remove {{ attributes }} or bypass the field template, see What can break quickedit, and how do I fix it?

2
  • This is called from the parent template with {{ content.field_admin_tags }}
    – aydow
    Nov 12, 2018 at 23:32
  • This is the way
    – JFC
    Mar 22 at 20:44
36

Agree with 4k4 the field template is the best place, if you really want it in the entity template (e.g. node) you can do something like this:

{% for key, item in content.field_tags if key|first != '#' %}
  <div class="item-{{ key + 1 }}">{{ item }}</div>
{% endfor %}

But honestly I think it's a bit ugly, the field template is the right place.

2
  • 2
    Agreed, it's a bit ugly. ;) Thanks for the code snippet, though. Jul 29, 2016 at 8:42
  • 1
    Works perfectly with different types of entites May 14, 2019 at 14:59
18

If you, like me, are looking for a way to iterate through paragraphs on a node's twig template, here is how to do it:

Suppose you have a node with a multivalued paragraph field, so a content editor can create multiple paragraphs and you wish to iterate through each paragraph on the nodes twig template (for example to add a wrapper around each paragraph):

{% for key,value in node.my_paragraph_field.value %}
    {{ content.my_paragraph_field[key] }}
{% endfor %}

UPDATE: I needed to find another way to print all paragraphs without using content. The content variable contains everything you set up in the 'Manage display' section of the node, but my current work method is to never use 'Manage display' nor layouts since you can actually access all data in the node twig file, and almost all settings you would do on 'Manage display', like applying an image style, or setting a date format, ... you can do directly in twig.

For me this is an advantage because I know that everything I see comes from the twig file, and I do not need to look for some obscure field settings that may add classes somewhere. So everything I see comes from just one place (the nodes twig file) and not a combination of the twig file and the manage display screen.

Anyway, using the awesome Twig Tweak module, here is how to print a multi value paragraph field in a node's twig file without having to use the content variable:

{% for item in node.field_paragraphs %}
    {{ drupal_entity('paragraph', item.target_id) }}
{% endfor %}
0
17

I found a method that is similar to the answer by @chris-ruppel, but a bit more elegant IMHO. It uses the keys filter to get an array of available indexes. I use it to build an HTML list.

<ul>
  {% for i in content.field_foo['#items']|keys %}
    <li>{{ content.field_foo[i] }}</li>
  {% endfor %}
</ul>
2
  • 1
    Only thing that has worked for me for nested paragraphs in twig. Jun 15, 2021 at 19:04
  • Hi I want same like need image url on this
    – Naveen
    Feb 5, 2022 at 10:05
6

I have found the #items property to be useful when building loops of unknown length in Twig:

print number of values within field:
{{ content.field_admin_tags['#items']|length }}

---

{# remember length in variable (minus 1 because it starts from 0): #}
{% set numTagsIndex = content.field_admin_tags['#items']|length - 1 %}

{# loop until the max value is reached: #}
{% for i in 0..numTagsIndex %}
  {{ content.field_admin_tags[i] }}
{% endfor %}
1

If you want to place additional wrappers around the fields inside the paragraph field or need for some reason a particular paragraph reference field value, you can do the following:

{% for key,value in node.paragraph_field_name.value %}

<div class="example-wrapper">
{{ content.paragraph_field_name[key]['#paragraph'].field_content.value }}
</div>

{% endfor %}

By doing {{kint(content.paragraph_field_name[key])}}, you'll see that the fields are accessible inside the ['#paragraph'] part of the array.

1

The below also works

{% for tag in node.field_tag %}
   {{ tag.entity.name.value }}
{% endfor %}
3
  • Thank you for this! Why are so many people doing these other crazy workarounds, when this solution is so simple? Sep 16, 2020 at 14:15
  • 3
    @aaronbauman Different people may give different answers, but personally I use "crazy workarounds" because I consider it best practice to only render variables from the preprocessed content variable, not from the raw node variable. Using node can work if you know what you're doing, but people might shoot themselves in the foot because they are bypassing preprocessors and formatters. In some cases it could even lead to information disclosure security leaks. Dec 1, 2020 at 11:54
  • that makes sense. thanks for that context @marcvangend Dec 1, 2020 at 16:00
0

I needed to iterate a multiple field in twig, what I did was add the value to it.

{% for tag in content.field_admin_tags %}
  {{ tag**.value** }}
{% endfor %}

This worked for me.

Your Answer

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

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