2

Is anyone able to tell me why variables which I've defined inside of a for loop are persisting and retaining their values on into consecutive iterations? In order to overcome this, I've had to set them back to null each time. I'm relatively new to Craft and Twig but this seems like a bug. Has anyone else experienced this?

    {% for entry in entries %}

      {# I shouldn't have to set these to null for each loop iteration, #}
      {# but they seem to be retaining their values #}

      {% set photo = null %}
      {% set width = null %}
      {% set height = null %}
      {% set orientation = null %}

      {% if entry.photo | length %}
        {% set photo = entry.photo.first() %}
        {% set width = photo.width %}
        {% set height = photo.height %}
        {% set orientation = '' %}

        {% if width > height %}
          {% set orientation = 'landscape' %}
        {% elseif height > width %}
          {% set orientation = 'portrait' %}
        {% elseif width == height %}
          {% set orientation = 'square' %}
        {% endif %}
      {% endif %}

      <article class="entry{% if orientation %} {{ orientation }}{% endif %}">
        {% if entry.photo | length %}
          <img src="{{ photo.getUrl('small') }}" width="{{ photo.getWidth('small') }}" height="{{ photo.getHeight('small') }}" alt="{{ photo.title }}">
        {% endif %}
      </article>

    {% endfor %}
4

This is totally normal and expected behavior. In fact, it's critical for some looping situations, and pretty standard across programming languages. Wouldn't you expect to find this same behavior in PHP?

Think about situations where previous loops build on each other. Here's an example of a situation where loop values need to be retained...

{% set totalPets = 0 %}

{% for petOwner in craft.entries.section('petOwners').find %}

    {% set totalPets = totalPets + petOwner.numberOwned %}

{% endfor %}

<p>This group of people owns {{ totalPets }} pets total.</p>

Ultimately, this is a simple scope issue. Generally speaking, for loops don't exist in their own scope... they are a part of the scope created by the parent script.

If you want to ensure that your logic takes place in a separate scope, take a look into Twig macros... A macro would probably be very helpful in your situation.

| improve this answer | |
  • Sorry, you're right. I guess I was confused about scope. I was thinking that for blocks were scoped like functions but of course they're not. I'll try using a macro instead. – MarkPlewis Mar 25 '15 at 18:07
  • According to Twig's documentation here: twig.sensiolabs.org/doc/tags/set.html variables inside a for loop in Twig is indeed scoped. Is this wrong? – Alf Vestre Mar 26 '15 at 7:40
  • Good catch @AlfVestre! Looks like my scope answer is a half-truth. I said "generally speaking", because I knew that the loop variable couldn't exist outside of the loop. I didn't realize that loops are considered an entirely separate scope (which obviously inherit the context of the parent script). Regardless, within the loop you'd still be dealing with a single scope... it wouldn't be refreshed every time the loop cycles through. – Lindsey D Mar 26 '15 at 17:14
  • "it wouldn't be refreshed every time the loop cycles through" That's true, but I'm not sure the totalPets variable in your answer will work if it is not declared outside (before) the forloop? I know this is not what the OP asked about, but since the comments brought up the behaviour of scoping I felt it was worth mentioning :) – Alf Vestre Mar 26 '15 at 17:49
  • Another good catch. :) I had originally defined totalPets outside of the loop, but felt it didn't properly address the OP's question. However, you're right... If defined this way, it won't be accessible after the loop ends. I'll go ahead and change the example, thanks! – Lindsey D Mar 26 '15 at 17:53

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.