2

I'm in a situation where I have a handful of matrix blocks which have similar subfields. For example, I have a "Bios" block where there's an intro etc., but the a few repeating fields, imagine:

  • Bio 1 Name (bioName1)
  • Bio 1 Image (bioImage1)
  • Bio 2 Name (bioName2)
  • Bio 2 Image (bioImage2)
  • etc. up to 6

In my template, I have some pretty redundent code when outputting these fields, like:

    {% if block.bioName1 %}
    <div class="bit">
        <div class="bio">
            {% for asset in block.bioImage1 %}
            <img src="{{ asset.url }}" alt="" />
            {% endfor %}
            <header>
                <h3>{{ block.bioName1 }}</h3>
                <p>{{ block.bioTitle1 }}</p>
            </header>
            {{ block.bioText1 }}
        </div>
    </div>
    {% endif %}

    {% if block.bioName2 %}
    <div class="bit">
        <div class="bio">
            {% for asset in block.bioImage2 %}
            <img src="{{ asset.url }}" alt="" />
            {% endfor %}
            <header>
                <h3>{{ block.bioName2 }}</h3>
                <p>{{ block.bioTitle2 }}</p>
            </header>
            {{ block.bioText2 }}
        </div>
    </div>
    {% endif %}

I'm wondering if it would be possible to somehow set this up as a loop with a counter to increment the vars (the field names always end with the count)? Any ideas? I tried a few things but have had no luck :/

2
  • Can you share screenshot your field set up? Would you be able to move the"bio" to its own block type so all the fields inside of a bio do not need to be numbered? Commented Apr 12, 2015 at 17:40
  • Hi Aaron - A stand alone block, or a "bios" channel isn't a good fit for this project. After trying those, we decided on this approach b.c it makes life a lot easier for the site's managers. It's working out fine, just trying to see if the templates can be a touch dry-er. If not, no biggie. Tks.
    – philzelnar
    Commented Apr 12, 2015 at 19:16

3 Answers 3

2

You can use the "subscript" variable syntax to add the loop index to your field names automatically.

http://twig.sensiolabs.org/doc/templates.html#variables

{% for i in 1..6 %}
  {% if block['bioName'~i] %}
    <div class="bit">
      <div class="bio">
        {% for asset in block['bioImage'~i] %}
          <img src="{{ asset.url }}" alt="" />
        {% endfor %}
        <header>
          <h3>{{ block['bioName'~i] }}</h3>
          <p>{{ block['bioTitle'~i] }}</p>
        </header>
        {{ block['bioText'~i] }}
      </div>
    </div>
  {% endif %}
{% endfor %}

I prefer this to the attribute function because it's a little simpler to look at. But the attribute function will work in some circumstances where dot notation and subscript syntax can't.

This is taken from the Twig docs link above:

When the attribute contains special characters (like - that would be interpreted as the minus operator), use the attribute function instead to access the variable attribute:

{# equivalent to the non-working foo.data-foo #}
{{ attribute(foo, 'data-foo') }}
4

I think this is an excellent use case for twig's attribute function.

The attribute function can be used to access a "dynamic" attribute of a variable:

{% for i in 1..6 %}
  {% if attribute(block, 'bioName'~i) %}
    <div class="bit">
      <div class="bio">
        {% for asset in attribute(block, 'bioImage'~i) %}
          <img src="{{asset.url}}"/>
          ...etc...
        {% endfor %}
      </div>
    </div>
  {% endif %}
{% endfor %}
1
  • Way better than my answer! Great idea to use attribute. Commented Apr 13, 2015 at 2:18
1

This solution requires a little bit of set-up code, but it will keep all your HTML dry. Set up arrays with the values from your block fields. Loop through one of the arrays and use loop.index0 to get the values you need in your HTML.

{% set names = [block.bioName1, block.bioName2, ...] %}
{% set titles = [block.bioTitle1, block.bioTitle2, ...] %}
{% set assets = [block.bioImage1, block.bioImage2, ...] %}
{% set texts = [block.bioText1, block.bioText2, ...] %}

{% for field in nameFields %}
    {% if field != '' %}
        <div class="bit">
            <div class="bio">
                {% for asset in assets[loop.index0] %}
                    <img src="{{ asset.url }}" alt="" />
                {% endfor %}
                <header>
                    <h3>{{ names[loop.index0] }}</h3>
                    <p>{{ titles[loop.index0] }}</p>
                </header>
                {{ block.texts[loop.index0] }}
            </div>
        </div>
    {% endif %}
{% endfor %}

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.