tacman/twig-tree-tag

A Twig extension for succinctly traversing nested lists (e.g. navigation menus), supporting Twig 3

3.1.7 2024-07-23 14:14 UTC

This package is auto-updated.

Last update: 2024-10-23 14:51:19 UTC


README

A Twig extension for succinctly traversing nested lists (e.g. navigation menus). Based on https://github.com/jordanlev/twig-tree-tag, adapted for PHP 8 and Twig 3 by Tac Tacelosky.

Requirements

Requires PHP 8.1 or higher

Installation

composer require tacman/twig-tree-tag

Now register it in services.yaml

# services.yaml
services:
    twig.tree:
      class: JordanLev\TwigTreeTag\Twig\Extension\TreeExtension
      tags:
        - { name: twig.extension }

Idea

The {% tree %} tag works almost like {% for %}, but inside a {% tree %} you can call {% subtree var %} to recursively run your {% tree %} block with the given var. The primary use-case for this tag is nested navigation menus.

This extension was written by Alain Tiemblo, (with a few very minor changes by Jordan Lev).

Usage Example

In this example, menu is an array of objects, each containing name, url, and children properties (children is itself an array of objects with the same properties, etc).

{% tree item in menu %}
  {% if treeloop.first %}<ul>{% endif %}
    <li>
        <a href="{{ item.url }}">{{ item.name }}</a>
        {% subtree item.children %}
    </li>
  {% if treeloop.last %}</ul>{% endif %}
{% endtree %}

Just like a {% for %} loop, you can access the key of each list item:

{% tree key, item in menu %}
  <li>
    <b>Item {{ key }}</b>: {{ item.name }}
    {% subtree item.children %}
  </li>
{% endtree %}

See the demo directory for more examples

What is the treeloop var?

The treeloop var serves the same purpose inside a {% tree %} tag as the loop var does inside a {% for %} tag. It is named differently so that you can still use loop when you have a {% for %} tag inside your {% tree %} tag (otherwise they would conflict).

treeloop contains all the same special variables as loop:

  • treeloop.index: The current iteration of the loop within the current nesting level. (1 indexed)
  • treeloop.index0: The current iteration of the loop within the current nesting level. (0 indexed)
  • treeloop.revindex: The number of iterations from the end of the loop within the current nesting level (1 indexed)
  • treeloop.revindex0: The number of iterations from the end of the loop within the current nesting level (0 indexed)
  • treeloop.first: True if first iteration of the current nesting level
  • treeloop.last: True if last iteration of the current nesting level
  • treeloop.length: The number of items in the sequence of the current nesting level
  • treeloop.parent: The context of the parent nesting level (or the parent context of the tree tag itself if currently at the root level of the tree).

Additionally, treeloop also contains 2 extra variables that tell you about the current nesting level:

  • level: The current nesting level (1 indexed -- so root level of the tree is 1, 2nd-level is 2, etc)
  • level0: The current nesting level (0 indexed -- so root level of the tree is 0, 2nd level is 1, etc)

What if I want a tree tag inside another tree tag?

To handle the edge case where you want to start a new tree inside another tree (that is, a new tree "root" with its own markup), use as in your {% tree %} tag to assign each tree to a var name, then pass it into subtree via with. This allows Twig to know which {% tree %} should be called when it comes across the {% subtree %} tag. For example...

{% tree item in menu as treeA %}
  {% if treeloop.first %}<ul>{% endif %}
    <li>
        {{ item.name }}
        {% subtree item.children with treeA %}
        
        <h2>Some other tree (that has its own "root", not a sub-tree of treeA):</h2>
        {% tree otherthing in item.otherthings as treeB %}
          {{ otherthings.name }}
          {% subtree otherthings.subitems with treeB %}
          {# We use "with treeB" above so Twig knows which parent tree tag to call #}
        {% endtree %}
    </li>
  {% if treeloop.last %}</ul>{% endif %}
{% endtree %}

License

The MIT License (MIT)

Please read the LICENSE file for more details.