paul_ngc
paul_ngc

Reputation: 111

Reuse Twig for loop

For a website I have two loops. The loop over the same fields which is of course not very good for the performance. This is how the current code looks like.

<div id="slider-overview">
    {% for item in post.get_field('work_gallery') %}
      <div class="slider-overview_index-link cell" data-index="{{ loop.index0 }}">
        <img src="{{ TimberImage(item).src|resize(180) }}" data-index="{{ loop.index0 }}" alt="{{ post.post_title}} | kiosk">
      </div>
    {% endfor %}
  </div>

and

<div id="slider">

{% for item in post.get_field('work_gallery') %}

  <div class="img-slide cell">
    <img class=""
      src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
      data-flickity-lazyload="{{ TimberImage(item).src|resize(1800) }}" alt="{% if item.caption %} {{ item.caption }} &ndash; {% endif %} {{ post.post_title }}">
      <p class="image-caption">
        {{ item.caption }}
      </p>
  </div>

{% endfor %}

I cannot pack these wrapper divs inside the for loops or wrap those wrapper inside each other. Now I was wondering if I can use only one loop and put all the info into an array? Then I read out in two for loops that don't require the database but loop over that array.

Is this possible or is Twig smart enough to recognise these for loops are over the same fields and caches the results from the first for loop?

Upvotes: 0

Views: 118

Answers (1)

insertusernamehere
insertusernamehere

Reputation: 23610

If post.get_field('work_gallery') is from the Advanced Custom Fields you shouldn't worry about multiple database requests. get_field will call acf_get_value, which then checks the Wordpress cache using wp_cache_get and only loads a new instance, if the element hasn't been available before:

$cache = wp_cache_get($cache_slug, 'acf', false, $found);
if( $found ) return $cache;

See: advanced-custom-fields-pro/api/api-value.php


Also running over a couple of items multiple times will not be a performance problem. It seems that you're building a slider using Flickity which will likely not have that many elements.


If you still worry about the second loop, you could create the content within one loop, store it in temporary variables and output it where it's needed. However, this will reduce maintainability and also readability of your source code and it's questionable whether it increases performance over your current solution.

{% set _temp_first = '' %}
{% set _temp_second = '' %}

{% for item in post.get_field('work_gallery') %}
  {% set _temp_first = _temp_first ~ '
    <div class="slider-overview_index-link cell" data-index="' ~ loop.index0 ~ '">
      <img src="' ~ TimberImage(item).src|resize(180) ~ '" data-index="' ~ loop.index0 ~ '" alt="' ~ post.post_title ~ ' | kiosk">
    </div>
  ' %}

  {% set _temp_second = _temp_second ~ '
    <div class="img-slide cell">
      <img class="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
           data-flickity-lazyload="' ~ TimberImage(item).src|resize(1800) ~ '"
           alt="' ~  ( item.caption ? item.caption ~ ' &ndash; ' ) ~ post.post_title ~ '">
      <p class="image-caption">' ~ item.caption ~ '</p>
    </div>
  ' %}
{% endfor %}

<div id="slider-overview">
    {{ _temp_first|raw }}
</div>

<div id="slider">
    {{ _temp_second|raw }}
</div>

Upvotes: 1

Related Questions