Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Twig recursive macro
{% macro recursiveCategory(category) %}
<li>
<h4><a href="{{ path(category.route, category.routeParams) }}">{{ category }}</a></h4>
{% if category.children|length %}
<ul>
{% for child in category.children %}
{{ _self.recursiveCategory(child) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}
{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category) }}
{% endfor %}
</ul>
</div>
{% endif %}
@rcwsr
Copy link

rcwsr commented May 9, 2013

Thanks for this.

@lukeholder
Copy link

lukeholder commented Jun 7, 2013

thanks!

@rccc
Copy link

rccc commented Sep 13, 2013

"When you define a macro in the template where you are going to use it, you might be tempted to call the macro directly via _self.input() instead of importing it; even if seems to work, this is just a side-effect of the current implementation and it won't work anymore in Twig 2.x." http://twig.sensiolabs.org/doc/tags/macro.html

@cbacelar
Copy link

cbacelar commented Oct 30, 2013

hi.. it was very very useful.. but this macro generates a lot of queries to get all items.. is there a way to do this recursive function without to do much queries? or is there a kind of optimization that turns these queries in something "soft"?

@dkisselev
Copy link

dkisselev commented Dec 23, 2013

Thanks so much for posting this. It took a while to finally find it, but I've been struggling with recursive twig macros for an hour now.

@ureimers
Copy link

ureimers commented Jan 11, 2014

@cccc: I don't think, that this will affect the actual recursion call _self.recursiveCategory(child) inside the macro but the initial call in the template self. This can be fixed by using:

{# Twig 2.x compatible version #}

{# ... macro ... #}

{% import _self as macros %}

{% if categories %}
    <div id="categories">
        <ul>
            {% for category in categories %}
                {{ macros.recursiveCategory(category) }}
            {% endfor %}
        </ul>
    </div>
{% endif %}

@mohsen-jsh
Copy link

mohsen-jsh commented May 20, 2014

very good! thank you

@joshbloomfield
Copy link

joshbloomfield commented Jun 18, 2015

Thanks!

@mriso79
Copy link

mriso79 commented Mar 7, 2016

This works perfectly! Outstanding.

@richard-integral
Copy link

richard-integral commented Sep 27, 2016

Well done ! Thank you :)

@garak
Copy link

garak commented Jan 2, 2017

It looks like this is deprecated and will not work anymore in twig 2 😢

@garak
Copy link

garak commented Jan 2, 2017

@dimd13
Copy link

dimd13 commented Apr 4, 2017

thanks!

@jordanlev
Copy link

jordanlev commented Apr 16, 2017

Another solution for this situation is to use the "tree" twig tag: https://github.com/jordanlev/twig-tree-tag -- it's less hacky, works in Twig 1 and 2, and IMO keeps the markup more straightforward (less ceremony around the mechanics of the loop and/or the macro). Only potential problem is that it requires PHP 5.4 or higher (but if you're using Twig v2 then that's no problem because you're already on PHP 5.5 or higher for that).

@AlexanderMatveev
Copy link

AlexanderMatveev commented May 4, 2018

@ureimers your example gives exception:

Impossible to invoke a method ("recursiveCategory") on a string variable ("...html.twig").

@Smanst3r
Copy link

Smanst3r commented Mar 25, 2021

Hi!
How to be with categories duplicates.
I mean if category has been rendered as a child, but it also will be rendered as a root category? So on page will be the two same categories rendered as a child category and as a root category.
Kind regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment