1

This may not be the best place for this, and quite probably I need to provide more context by way of example – so I will understand if it gets judged to be ‘not a proper question’ – but here goes…

Background

When I learned some years ago of Marion’s Twig Perversion plugin I found it to be a game changer to how I write templates:

For example:

  • I frequently want to loop through elements and objects and update a hash which can then be deployed in multiple ways subject to context
  • The same compiled hash (which might itself be the outcome of iterating over myriad Matrix block macros) can subsequently be looped through to generate different ‘views’ of the content in the same page, such as:
    • A Matrix-derived sequence of multi-section content and a table of contents for it
    • Or a ‘report’ table which also generates a .csv or json of the same data.

So Twig Perversion's ability to return a variable from a macro instead of printing markup is invaluable.

I can probably dig out better examples of how I have been using this return ability, but here is a Gist of ‘Reporting all fields in a Craft instance’.

Oh no!… fingers crossed

A recent update to Twig seemed to undermine the on-going ability to do such ‘perverse’ things. As is so often the case, the inimitable Brandon may already have come up with a fix. Which would be great.

A way forward

But the question arises whether using Twig Perversion to do the kind of thing I’m referring to above is sensible. Is it just storing up future templating fragility?

But I’m not sure how to go about engineering what I have become accustomed to doing without creating incredibly verbose templates.

Any thoughts or suggestions welcome.

3 Answers 3

4

I think Marion chose a great name for her plugin—in her own words:

Making Twig do things it really shouldn't. Twig is not intended to be a general purpose programming language, and there are some things that really don't belong in the language. This plugin adds a few of those things anyway.

Emphasis added. return is a concept of languages that use functions to encapsulate bits of logic. Twig is an XML view layer that—in a perfect world—receives all the data it requires, and does minimal manipulation to that data before outputting it. Craft bends this paradigm a bit, because we often need to fetch additional elements, filter based on input/context, and so on… and it can get hairy, sometimes!

The best path forward is definitely moving this logic into a Twig extension, and/or a few services designed to pre-process your data.

You have a couple of options:

  1. Spin up a new Twig extension with Generator:
    # Make a new module (or skip, if you have one already)
    php craft make module
    # Stub a Twig extension:
    php craft make twig-extension --module=my-module
    
    Then, check out the documentation on extending Twig to learn about adding functions, filters, and tags!
  2. Use Twig Toolbox to inject a function or two. (I wrote this for exactly the scenario you're describing!)

Either option would allow you to pass off your Matrix data to a helper function, and receive a “munged” result:

{% set myReport = toReport(entry.myMatrixField) %}
{% set myCards = toCards(entry.myMatrixField) %}
1
  • That sounds incredibly helpful, August. Thank you! I will investigate :) Commented Sep 20 at 16:54
2

Check out my article Making Twig Macros Work Like Functions where it describes how you can return values from macros, includes, etc.

calculateSales.twig macro:

{% set result = 0.0 %}
{% for order in orders %}
    {% set result = result + order['price'] * order['quantity'] %}
{% endfor %}
{{ result }}

...and then in your template:

    {% set total = _self.calculateSales(orders) | spaceless | float %}

    <span>
        {{ total * 0.08 }}
    </span>
2
  • Thanks Andrew. Looks like I could have done with reading that article years ago. Commented Sep 22 at 10:36
  • Not your fault, the article didn't exist years ago :) Commented Sep 23 at 17:13
1

August's answer is obviously the "correct" one. But I'm assuming if you're already prepared to get that dirty with Twig you wouldn't mind something like this: With embed, you can set variables in a parent template that are then available to the template doing the embedding. Combined with Twig's whitespace trimmers and set...endset you can effectively centralise and reuse a chunk of processing logic. Here's an example:

{# ==================================
_partials/processorLogic.twig:
===================================== #}

{% set mode = mode ?? 'regular' %}

{%- set someVariable -%}
    {# Add a vast amount of crazy logic here and save the output into someVariable. #}
    {% switch mode %}   
        {% case 'alt' %}        
            <p>Alt mode</p>
        {% case 'regular' %}        
            <p>Regular mode</p>
    {% endswitch %} 
{%- endset -%}

{# Placeholder to output stuff: #}
{% block content %}{% endblock %}

{# ==================================
Any other template:
===================================== #}

{% embed '_partials/processorLogic.twig' %}
    {% block content %}
        <h1>First instance of someVariable:</h1>
        {{ someVariable }}
    {% endblock %}
{% endembed %}

{% embed '_partials/processorLogic.twig' with { mode: 'alt' } only %}
    {% block content %}
        <h1>Second instance of someVariable:</h1>
        {{ someVariable }}
    {% endblock %}
{% endembed %}
2
  • Thanks James. I confess I’ve never got my head around practical use of embeds. I guess I should [flushed face emoji] Commented Sep 20 at 17:38
  • Ah yep in my opinion everyone should be familiar with embeds. The Twig docs do a horrible job of attempting to explain them in my opinion. They're much simpler than they sound - it's really just a super-charged version of an include, which can be used when you need the calling template to pass in a lump of html. I use them extensively - mainly for my container partial: github.com/cld-agency/craftwind-boilerplate/blob/craft-4/… Commented Sep 23 at 10:18

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.