2

Trying to get my head around this and make my code a little DRYer.

I have a _helpers macro file. Like so:

{% macro date_formatted(givenDate) %}
    {{ givenDate|date("l, jS F Y") }}
{% endmacro %}

{% macro product_title(product) %}
    {{ product|replace(' HA', '<sup>HA</sup>')|raw }}
{% endmacro %}

This file is used in various places throughout the website and is included in various base templates using {% import '_macros/_helpers' as helpers %}

I then have another macro for creating products (teasers and various code that would be repeated). This contains:

  {% macro teaser(product, imgSize, className) %}
    {% set cart = craft.commerce.getCart() %}
    {% set category = product.category.first() %}
    {% import '_macros/_helpers' as helpers %}

    <div class="product-teaser{% if className %} // {{ className }}{% endif %}">
        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}
        <a href="{{ product.url }}">
            <img
                src="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}}"
                srcset="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}} 1x, {{ craft.imager.transformImage(thumbAsset, { width:imgSize * 2, height:imgSize * 2 }) }} 2x"
                alt="{{ product.title }}"
                class="product-teaser__img"
            />
        </a>
        {% endif %}
        <h3 class="product-teaser__title{% if className %} // {{ className }}__title{% endif %}">{{ helpers.product_title(product.title) }}</h3>
        <p class="product-teaser__price{% if className %} // {{ className }}__price{% endif %}">{{ product.defaultPrice|currency(cart.currency) }}</p>

        <p>
            <a href="{{ product.url }}" class="btn // btn--sub">View Product</a>

            {% if className == "product-teaser--featured" %}
                <a href="{{ category.url }}" class="btn // btn--base">{{ category.title }} Range</a>
            {% endif %}
        </p>
    </div>
{% endmacro %}


{% macro alsoPurchased(product, imgSize) %}
    {% set cart = craft.commerce.getCart() %}
    {% import '_macros/_helpers' as helpers %}

    <li class="productAlsoPurchased__item">
        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}
        <a href="{{ product.url }}">
            <img
                src="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}}"
                srcset="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}} 1x, {{ craft.imager.transformImage(thumbAsset, { width:imgSize * 2, height:imgSize * 2 }) }} 2x"
                alt="{{ product.title }}"
                class="productAlsoPurchased__img"
            />
        </a>
        {% endif %}
        <p class="productAlsoPurchased__content">
            <strong>{{ helpers.product_title(product.title) }}</strong><br />
            <span class="product-teaser__price">{{ product.defaultPrice|currency(cart.currency) }}</span>
        </p>
    </li>
{% endmacro %}

The problem/question I have come up against is that it seems I have to include {% import '_macros/_helpers' as helpers %} in each Macro and also the same goes for setting the variable for cart. {% set cart = craft.commerce.getCart() %}

Is there a better way of doing this? Or a DRYer way of doing this? So I don't have to repeat my includes and setting of variables for each Macro block?

3

You aren't able to pass an import into a macro. So helpers needs to be imported into each macro file that uses it.

You can however pass the cart to your macros. As a side note, it's definitely best to set the cart variable in a global template - this means you're only ever setting it once. All templates that extend this global template then inherit cart. The way macro's work though means they need to have these variables explicitly passed to them. They don't inherit variables in the same way includes do or when you extend templates.

You can then pass cart to your macro like so:

{# Variable set in an extended template or current template #}
{% set cart = craft.commerce.cart %}

{# Variable is passed to the macro #}
{{ teaser(product, imgSize, className, cart) }}

Macro file then edited to take variables:

{% macro teaser(product, imgSize, className, cart) %}
    {# We still need to import our helpers into this macro file #}
    {% import '_macros/_helpers' as helpers %}

    {% set category = product.category.first() %}

    <div class="product-teaser{% if className %} // {{ className }}{% endif %}">
        {% set thumbAsset = product.productImage.first() %}
        {% if thumbAsset %}
        <a href="{{ product.url }}">
            <img
                src="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}}"
                srcset="{{ craft.imager.transformImage(thumbAsset, { width:imgSize, height:imgSize })}} 1x, {{ craft.imager.transformImage(thumbAsset, { width:imgSize * 2, height:imgSize * 2 }) }} 2x"
                alt="{{ product.title }}"
                class="product-teaser__img"
            />
        </a>
        {% endif %}
        <h3 class="product-teaser__title{% if className %} // {{ className }}__title{% endif %}">{{ helpers.product_title(product.title) }}</h3>
        <p class="product-teaser__price{% if className %} // {{ className }}__price{% endif %}">{{ product.defaultPrice|currency(cart.currency) }}</p>

        <p>
            <a href="{{ product.url }}" class="btn // btn--sub">View Product</a>

            {% if className == "product-teaser--featured" %}
                <a href="{{ category.url }}" class="btn // btn--base">{{ category.title }} Range</a>
            {% endif %}
        </p>
    </div>
{% endmacro %}
  • I never knew you could pass imported macros into a macro. That opens up all sorts of possible complexity! – Marion Newlevant Sep 1 '16 at 18:39
  • I made a mistake, you can't pass imported macros into other macros. You'll need to import them in each macro that uses it. – Luke Pearce Sep 2 '16 at 8:41

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.