1

Anyone know if it's possible to check what the current field is while in a loop of a matrix block? Running into an issue with a matrix block in my loop for how I want to output the content.

{% case 'testimonials' %}
{% if block.getPrev() %}
    {# if the previous block isn't the "testimonials" block start container #}
    {% if block.getPrev().type != 'testimonials' %}
    <div class="container-fluid add-top">
        <div class="row">
            <div class="text-center testimonials">
    {% endif %}
    {# if there isn't a previous block start a div could be the first block#}
    {% else %}
    <div class="container-fluid add-top">
        <div class="row">
            <div class="text-center testimonials">
{% endif %}

            {# Output Content #}
            {# Output each testimonial here #}
            <blockquote class="blockquote-unstyled" style="display:none;">
                <footer class="text-uppercase">
                    <span title="Source Title">{{block.sourceTitle}}</span>
                </footer>
                <p class="lead">“{{block.lead}}”</p>
            </blockquote>

            {% if block.getPrev().type != 'testimonials' %}
            <ul class="list-inline">
            {% endif %}

            {# Output image for each testimonial here #}
            {% set image = block.image.first() %}
            <li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>

            {% if block.getNext().type != 'testimonials' %}
            </ul>
            {% endif %}
            {# Output Content #}

{# if this is the "testimonials" block type #}
{% if block.type == 'testimonials' %}
    {# if there is another block to check #}
    {% if block.getNext() %}

    {# if the next block isn't the "testimonials" block end div #}
    {% if block.getNext().type != 'testimonials' %}
            </div>
        </div>
    </div>
    {% endif %}

    {# if there isn't another block end a ul might be the last block#}
    {% else %}
            </div>
        </div>
    </div>
    {% endif %}
{% endif %}
<!-- End Testimonials Block -->

So if I enter three testimonials I want the content to appear like this.

<blockquote class="blockquote-unstyled" style="display:none;">
    <footer class="text-uppercase">
        <span title="Source Title">{{block.sourceTitle}}</span>
    </footer>
    <p class="lead">“{{block.lead}}”</p>
</blockquote>
<blockquote class="blockquote-unstyled" style="display:none;">
    <footer class="text-uppercase">
        <span title="Source Title">{{block.sourceTitle}}</span>
    </footer>
    <p class="lead">“{{block.lead}}”</p>
</blockquote>
<blockquote class="blockquote-unstyled" style="display:none;">
    <footer class="text-uppercase">
        <span title="Source Title">{{block.sourceTitle}}</span>
    </footer>
    <p class="lead">“{{block.lead}}”</p>
</blockquote>
<ul class="list-inline">
<li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>
<li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>
<li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>
</ul>

Before changing to use a switch I was using the following which worked great, just can't think of an equivalent for switch.

<!-- Testimonials Block -->
{% if entry.testimonials|length %}
<div class="container-fluid add-top">
    <div class="row">
        <div class="text-center testimonials">
        {% for block in entry.testimonials %}
            {% if block.type == "testimonial" %}
                {% set image = block.image.first() %}
                <blockquote class="blockquote-unstyled" style="display:none;">
                    <footer class="text-uppercase">
                        <span title="Source Title">{{block.sourceTitle}}</span>
                    </footer>
                    <p class="lead">“{{block.lead}}”</p>
                </blockquote>
            {% endif %}
        {% endfor %} 
        <div class="list-inline">
        {% for block in entry.testimonials %}
            {% if block.type == "testimonial" %}
                {% set image = block.image.first() %}
                    <li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>
            {% endif %}
        {% endfor %} 
        </div>
        </div>
    </div>
</div>
{% endif %}
1

The way you describe the output you want (3 blockquotes followed by a list of 3 images), you are going to need to loop over the testimonials twice. Here is a solution detects the first of the testimonials blocks and starts a secondary loop for the blockquotes. You will need the break and continue plugin to exit out of that inner loop.

{% for block in entry.matrixField %}
  {% switch block.type %}
    {% case 'testimonials' %}

      {# is this the first or last block ? #}
      {% set isFirst = not block.getPrev() or block.getPrev().type != 'testimonials' %}
      {% set isLast = not block.getNext() or block.getNext().type != 'testimonials' %}

      {% if isFirst %}
        {# we are going to fake a loop for the blockquotes #}
        {% set currentBlock = block %}
        {# twig has no while loop, so... #}
        {% for x in [1..1000] %}

          {% if not currentBlock or currentBlock.type != 'testimonials' %}
            {% break %} {# from the breakandcontinue plugin #}
          {% endif %}

          <blockquote class="blockquote-unstyled" style="display:none;">
            <footer class="text-uppercase">
              <span title="Source Title">{{currentBlock.sourceTitle}}</span>
            </footer>
            <p class="lead">“{{currentBlock.lead}}”</p>
          </blockquote>

          {# on to the next #}
          {% set currentBlock = currentBlock.getNext() %}
        {% endfor %}

        {# first one, so open the image list #}
        <ul class="list-inline">
      {% endif %}

      {# Output image for this testimonial here #}
      {% set image = block.image.first() %}
      <li><img class="img-responsive img-circle" alt="Profile" src="{{ image.getUrl('testimonials') }}" width="{{ image.getWidth('testimonials') }}" height="{{ image.getHeight('testimonials') }}"/></li>

      {% if isLast %} {# last one, close the list #}
        </ul>
      {% endif %}
    {# other cases here... #}
  {% endswitch %}
{% endfor %}
  • Worked great was a typo in your {% if not currentBlock or currentBlock.type != testimonials' %} opening single quote on testimonials. But was quickly spotted. – Bowenac May 13 '15 at 0:05
  • Glad it worked! Fixed the typo for the next person. – Marion Newlevant May 13 '15 at 1:03
2

I think you're going to drive yourself crazy with all the if then statements ;) — I might suggest you try a different approach to make this a bit more manageable. I can think of a few options.

Option 1. Create a 'testimonials' matrix field and a 'layout' matrix field. The 'testimonials' matrix can be used to organize the testimonials, and the 'layout' matrix can be used to define the page layout order — you can then simply include the testimonials by adding a 'dummy' testimonials blockType to the layout matrix with no content in it.

{% for block in entry.layout %}
    {% switch entry.layout %}

        {% case 'testimonials'%}

            <div class="container-fluid add-top">
                <div class="row">
                    <div class="text-center testimonials">

                        {% set imageHTML = '' %}
                        {% for block in entry.testimonials %}

                            <blockquote class="blockquote-unstyled" style="display:none;">
                                <footer class="text-uppercase">
                                    <span title="Source Title">{{block.sourceTitle}}</span>
                                </footer>
                                <p class="lead">“{{block.lead}}”</p>
                            </blockquote>

                            {% set image = block.image.first() %}
                            {% set imageHTML = imageHTML ~ '<li><img class="img-responsive img-circle" alt="Profile" src="%url%" width="%width%" height="%height%"/></li>'|replace({
                                %url%: image.getUrl('testimonials'),
                                %height%: image.getWidth('testimonials'), 
                                %width%: image.getHeight('testimonials')    
                            }) %}

                        {% endfor %}

                        {% if imageHTML %}
                            {{ imageHTML }}
                        {% endif %}

                    </div>
                </div>
            </div>

        {% case 'someOtherBlock' %}

            {# output other blocks as needed #}

    {% endswitch %}
{% endfor %}

Option 2. Something else to consider is to use the 'superTable' plugin, which if I understand correctly, can be placed inside a matrix field. You can then loop through the matrix (i.e. 'layout') using switch, and then loop through the 'testimonials' inside the table. Unlike the solution above this would allow for multiple testimonial areas on your page, if needed.

Option 3. You might also consider creating a separate channel for your 'testimonials', and then use an entries fieldType to include multiple testimonials in your testimonials blocktype. While slightly more difficult for data entry, the advantage would be that you could reuse your testimonials on multiple pages. This would also allow for multiple testimonial areas on the same page.

  • Any field type you can recommend to place in a dummy matrix block type? It doesn't work without any, right? And I think Super Table only works the other way round, Super Table inside Matrix field. – carlcs May 12 '15 at 5:43
  • Not sure you need any fields — but if so a 'lightswitch' would work nicely. Regarding the superTable inside Matrix... you would certainly know better! I'll update the answer. Thanks @carlcs! – Douglas McDonald May 12 '15 at 5:47
  • Or a read-only field type like fieldnotes. Haven't tested that though. – carlcs May 12 '15 at 6:34
  • Thanks for the suggestion but I don't think that will workout as some pages might need multiple testimonial areas. If I was to do that I would only be able to use it once. – Bowenac May 12 '15 at 12:01
  • Understood. I would seriously consider option 2 then, using the superTable plugin, which should be ideal for this. Yet another option would be to create another channel with testimonial snippets, that you can add to an entries field (i.e. 'testimonials') in one of your matrix blocks. Although a bit more difficult for data entry, the advantage is that you could reuse the same testimonial on several pages. – Douglas McDonald May 12 '15 at 15:48

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.