2

I'm not sure why this isn't working as I set the variable outside the scope of the matrix block. The variable is working inside the matrix block, but not accessible outside of it. What am I missing?

Index template:

{% set slideImg = "" %}

{% block hero %}
    {% for block in entry.hero %}
        {% set slideImg = block.heroImg.first().url %}
    {% endfor %}
{% endblock %}

{% block footerJs %}
    <script>
        $(function() {
            $('#slide-1').backstretch('{{ slideImg }}');
        )};
    </script>
{% endblock %}

Update: Full Index template

{% extends "_layout" %}

{% set metaTitle = entry.seoTitle %}
{% set metaDescription = entry.seoDescription %}
{% set metaKeywords = entry.seoKeywords %}

{% set slideImg = "" %}

{% block hero %}
    {% for block in entry.hero %}
        <h2>{{ block.headline|raw }}</h2>
        {% set slideImg = block.heroImg.first().url %}
        {% set link1 = block.buttonLink1.first() %}
        <a href="{{ link1.url }}" class="btn-gradient">{{ block.buttonLabel1 }}</a>
        {% if block.buttonLabel2%}
        {% set link2 = block.buttonLink1.first() %}
        <a href="{{ link2.url }}" class="btn-gradient">{{ block.buttonLabel2 }}</a>
        {% endif %}
    {% endfor %}
{% endblock %}

{% block footerJs %}
    <script>
        $(function() {
            $('#slide-1').backstretch('{{ slideImg }}');
        )};
    </script>
{% endblock %}

Update #2 _layout

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    {% block head %}
        <title>{% if metaTitle is defined %}{{ metaTitle }}{% else %}{{ entry.title }}{% endif %}{{siteName}}</title>
        {% if metaDescription is defined %}<meta name="description" content="{{ metaDescription }}">{% endif %}
        {% if metaKeywords is defined %}<meta name="keywords" content="{{ metaKeywords }}">{% endif %}
    {% endblock %}

    <meta name="author" content="@siebird">

    <link rel="stylesheet" href="/assets/css/normalize.min.css">
    <link href='http://fonts.googleapis.com/css?family=Arvo:400,400italic|PT+Sans+Narrow:400,700' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="/assets/css/styles.css">

</head>
<body>
    <!--[if lt IE 7]>
        <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
    <![endif]-->
    <div class="header{% if craft.request.firstSegment == '' %} big{% endif %}">
        <div id="slide{% if craft.request.firstSegment == '' %}-int{% endif %}" class="slide">
            <div class="row">
                <h1>{{ general.companyName}}</h1>

                {% block hero %}

                {% endblock %}

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

    <div class="nav-bar">
        <div class="buns">
            <span>MENU</span>
            <a href="#" class="hamburger nav-main">
                <span></span>
                <span></span>
                <span></span>
            </a>
        </div>
        <ul class="nav nav-main">
            <li{% if craft.request.firstSegment == '' %} class="active"{% endif %}><a href="{{ siteUrl }}">Home</a></li>
            <li{% if craft.request.firstSegment == 'who-we-are' %} class="active"{% endif %}><a href="{{ url('who-we-are') }}">Who We Are</a></li>
            <li{% if craft.request.firstSegment == 'community' %} class="active"{% endif %}><a href="{{ url('community') }}">Community</a></li>
            <li{% if craft.request.firstSegment == 'floorplans' %} class="active"{% endif %}><a href="{{ url('floorplans') }}">Floor Plans</a></li>
            <li{% if craft.request.firstSegment == 'energy' %} class="active"{% endif %}><a href="{{ url('energy') }}">Energy</a></li>
            <li{% if craft.request.firstSegment == 'gallery' %} class="active"{% endif %}><a href="{{ url('gallery') }}">Gallery</a></li>
            <li{% if craft.request.firstSegment == 'agents' %} class="active"{% endif %}><a href="{{ url('agents') }}">Agents</a></li>
            <li class="nav-btn"><a href="{{ url('visit') }}">Schedule a Visit</a></li>
        </ul>
    </div>

    {% block main %}

    {% endblock %}

    <div class="footer">
        <div class="row">
            <div class="block-3">
                <address>{{ general.address }}<br> <a href="{{ general.directions }}" target="_blank">Get Directions!</a></address>
            </div>

            <div class="block-3">
                <p>Contact Us Today<br> <a href="tel:{{ general.phoneNumber }}" class="tel">{{ general.phoneNumber }}</a></p>
            </div>

            <div class="block-6">
                <small>&copy; {{ now.year }} {{ general.companyName }}. All Rights Reserved.<br> <a href="http://siebird.com">Website design &amp; development by <em>Siebird</em></a></small>
                <img src="assets/img/eho.png" class="pull-right" alt="equal housing opportunity" height="51">
            </div>
        </div>
    </div>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="assets/js/vendor/jquery-1.10.2.min.js"><\/script>')</script>
    <script src="/assets/js/plugins.js"></script>
    <script src="/assets/js/application.js"></script>

    {% block footerJs %}

    {% endblock %}

  {#
  Google Analytics: change UA-XXXXX-X to be your site's ID.
    <script>
        (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
        function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
        e=o.createElement(i);r=o.getElementsByTagName(i)[0];
        e.src='//www.google-analytics.com/analytics.js';
        r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
        ga('create','UA-XXXXX-X');ga('send','pageview');
    </script>
    #}

</body>
</html>
10
  • Are you getting any errors? What's getting output for slideImg here? $('#slide-1').backstretch('{{ slideImg }}'); The way your code currently is, the slideImg in the footerJs block should be equal to the first heroImg URL of the last Matrix block in entry.hero. – Brad Bell Sep 23 '14 at 17:30
  • No template errors, just JS error as the {{ slideImg }} within the script tag does not parse anything. If I put it within the matrix for loop it parse the correct file path. To add context, the matrix can only have one row – Siebird Sep 23 '14 at 18:27
  • So if you {{ slideImg }} after the {% endfor %} but before the hero {% endblock %} it shows up correctly? – Brad Bell Sep 23 '14 at 18:30
  • Yep, just tested it and it works – Siebird Sep 23 '14 at 18:45
  • Hrm... I'm stumped. I think that should work. Something else on the page overwriting it? Maybe you're leaving out some other template code that complicates things? – Brad Bell Sep 23 '14 at 18:58
3

You're running into an issue with the way you are setting variables in the processing order. I believe {% block %} tags are processed after all other tags in the template, and then they are processed all at once, with any variables available at that point in time, and the related content in their respective block tags in the parent templates. So while you are creating your slideImg variable higher on the page, the hero and footerJs blocks are not processed from top to bottom on the page, they are processed simultaneously, and independently.

So, when you set {% set slideImg = block.heroImg.first().url %} within your Matrix loop, it's already too late to have that variable available modify the existing slideImg variable that you set outside of the block tags.

There are three approaches I can think of to address the issue:

  1. Use set tags instead of block tags
  2. Process your matrix field outside of the block tags higher on the page
  3. Write a plugin to help you out (I won't go into an example of this one here)

1. Use set tags instead of block tags

While most of the examples in learning Twig use block tags for page layouts, it's less common to see people actually using them in a way that takes advantage of their uniqueness and very frequently you can just swap them out for set tags and get the same result.

For this, you'd need to modify your layout template and page template accordingly. Here's a simplified example of your code above that should work:

_layout

{% if hero is defined %}
    {{ hero }}
{% endif %}

{% if footerJs is defined %}
    {{ footerJs }}
{% endif %}

index.html

{% extends "layout" %}

{% set slideImg = "" %}

{% set hero %}
  {% set slideImg = "image.png" %}
{% endset %}

{% set footerJs %}
  {{ slideImg }}
{% endset %}

I believe in this example, all that you would need to update to use the set tag is the hero block, and if you left the footerJs as a block, things would still work out because you'd be processing the Matrix block within the set tag higher on the page, and the variable would be updated by the time Twig was processing the block tag in your footer.

2. Process your matrix field outside of the block tags higher on the page

In this workaround, the goal is to process the variables you need outside of the block tags higher on the page, so the variables you set will be available to all of the block tags on your page when they get processed.

In the simplified example below, I assume your parent template stays the same and uses block tags for hero and footerJs, and set a new variable at the top of the page called {{ heroContent }} where we can loop through our Matrix blocks, set additional variables that are available to us in the page template, and that later gets output farther down the page within the hero block.

index.html

{% extends "_layout" %}

{% set slideImg = "" %}

{% set heroContent %}
    {% for block in entry.hero %}

      {% set slideImg = block.heroImg.first().url %}

      {# Everything else you want to output in your hero block #}

    {% endfor %}
{% endset %}

{% block hero %}
  {{ heroContent }}
{% endblock %}

{% block footerJs %}
  {{ slideImg }}
{% endblock %}

For a longer discussion of the Twig processing order and there is a related article on Straight Up Craft called The Twig processing order in Craft templates.

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.