Score:0

When iterating over multi-value fields is it considered best practice to override the field template vs loop over the var in node or block template?

kr flag

I have a link field that allows multiple (3 max) values on a custom block for which I'm using a twig template.

I want to iterate over the values using a for loop.

I got this to work the way I wanted in my block twig like so:

{% for key in content.field_footer_cta_buttons|keys %}          
  {% if key matches '/^\\d+$/' %}
    <a href='{{content.field_footer_cta_buttons[key]['#url']}}'>{{ content.field_footer_cta_buttons[key]['#title'] }}</a>     
  {% endif %}
{% endfor %}

However, according to: Iterate through multiple value content field in Twig template

You should override the field template, loop there, and then print it in a node template, or presumably, a block template depending on your situation. Is this correct? If so why?

Is it bad practice to iterate over render arrays even though they are part of the render API? I would think their structure would be constant.

Thank you.

abe-cedarian avatar
kr flag
@Hudri - Thanks for commenting. I did see the example you're linking to which involves looping through the multi-value field in a field level twig template and printing it in a node level template whereas I've been working in a block level template. Are you suggesting that when looping through multi-value fields it's best practice to do so in a field template? I loop through multi value image fields in node templates all the time and it seems pretty straight forward. It seems like it should be the same across the board.
ru flag
If it is possible to do your job in fields, you should try this first, because it is more "Drupalish" (e.g. re-orderung fields in Field UI still works). It won't be possible all the time, but I'd suggest fields first, and only use entity templates when necessary.
Score:0
kr flag

I solved this by adding this to my custom block twig:

{{ dump(content.field_footer_cta_buttons) }}

Which should've been like the first thing that I did.

I then saw that the structure actully looks like:

^ array:20 [▼
  "#theme" => "field"
  "#title" => "Footer CTA Buttons"
  "#label_display" => "hidden"
  "#view_mode" => "full"
  "#language" => "en"
  "#field_name" => "field_footer_cta_buttons"
  "#field_type" => "link"
  "#field_translatable" => false
  "#entity_type" => "block_content"
  "#bundle" => "footer_block"
  "#object" => Drupal\block_content\Entity\BlockContent {#2804 ▶}
  "#items" => Drupal\Core\Field\FieldItemList {#3601 ▶}
  "#formatter" => "link"
  "#is_multiple" => true
  "#third_party_settings" => []
  0 => array:4 [▼
    "#type" => "link"
    "#title" => "Some Link Text"
    "#options" => array:1 [▶]
    "#url" => Drupal\Core\Url {#3583 ▶}
  ]
  1 => array:4 [▼
    "#type" => "link"
    "#title" => "Some Other Link Text"
    "#options" => array:1 [▶]
    "#url" => Drupal\Core\Url {#3118 ▶}
  ]
  2 => array:4 [▼
    "#type" => "link"
    "#title" => "Yet More Link Text"
    "#options" => array:1 [▶]
    "#url" => Drupal\Core\Url {#3685 ▶}
  ]
  "#cache" => array:3 [▶]
  "#weight" => 2
]

To me this seems unintuitive and not conducive to iteration which I would think would be a common requirement. However, I'm betting someone way more knowledgeable than myself designed this so there's likely a very good reason for it and it's also likely that my approach is fundamentally flawed in some way.

My ultimate solution was:

{% for key in content.field_footer_cta_buttons|keys %}
  {% if key == 0 or key == 1 or key == 2 %}
    <a class='some-class' href='{{content.field_footer_cta_buttons[key]['#url']}}'>{{ content.field_footer_cta_buttons[key]['#title'] }}</a>     
  {% endif %}
{% endfor %}

I do realize this assumes the link field will always have a maximum of 3 values. So, something like:

{% if key matches '/^\\d+$/' %}

might be better than:

{% if key == 0 or key == 1 or key == 2 %}

If someone posts a better answer, I'll happily accept it. Thank you.

4uk4 avatar
cn flag
The var dump you've posted is clearly the render array of a field template and shouldn't be hacked. The structure of a render array is not an API and can change without notice. So your code will probably just stop working someday in the future by running updates or installing additional modules.
4uk4 avatar
cn flag
Enable Twig Debugging and look for the right template you can override.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.