{{craftSnippets}}
Home Articles Plugins Starter theme About
  • Home
  • Articles
  • Fetching routes into Twig templates in Craft CMS
Posted on Feb 22, 2019 by Piotr Pogorzelski

Fetching routes into Twig templates in Craft CMS

Some time after writing this article, I released Named Routes plugin which handles functionality described here.
I recommend using this plugin instead of method described in this article.

Most Craft developers hardcode routes structure within links created in Twig templates. There is however a way to fetch routes directly into templates and avoid creating duplicate code.

This article deals only with routes defined in config/routes.php file - also called URL rules. It is also written with the assumption that you have basic understanding of Craft Cms routing functionality. You can learn more about routes in Craft Cms documentation.

What's it all about? #

One of the most common applications of routing functionality in Craft Cms is creating a tag page. Let's consider such situation.

First, we need to define route in config/routes.php file:

<?php
return [
    tag-list/<slug>' => ['template' => '_pages/single_tag'],`
];

Now, we need to create link to tag page inside Twig template. In example below we are looping trough tags assigned to some entry:

{% for singletag in entry.tags.all() %}
<a href="tag-list/{{singletag.slug}}">{{singletag.title}}</a>`
{% endfor %}

Do you already see the problem? tag-list keyword is hardcoded inside routes.php, but also in Twig file. What if we create ten such links within various fragments of our twig templates? And then we need to change tag-list fragment of route to - for example, tags? In such situation, we would need to change it in 11 places - one time inside routes.php and ten times within Twig templates. This is in direct contradiction of DRY (dont repeat yourself) rule - route URL structure should be defined only in one place.

Accessing routes from within Twig templates #

Craft CMS exposes most of its core functionality within craft.app Twig variable. Let's use dump to inspect our routes, using craft.app.routes.getConfigFileRoutes method:

<pre>{{ dump(craft.app.routes.getConfigFileRoutes) }}</pre>
array(1) {
  ["tag-list/<slug>"]=>
  array(1) {
    ["template"]=>
    string(28) "_pages/single_tag"
  }
}

As we can see, route URL structure IS available for us inside Twig templates. But array returned by getConfigFileRoutes is numeric - do we need to remember numeric index of each route? Let's modify routes.php file a little, by giving each route name attribute.

<?php
return [
    'tag-list/<slug>' => ['template' => '_pages/single_tag', 'name' => 'tag'],
];

Now, we can loop through array of routes and find the one we need - route that has name attribute with value of tag.


{% set routeName == 'tag' %}

{% set keyword = 'name' %}
{% set routeString = null %}
{% for route, routeSettings in craft.app.routes.getConfigFileRoutes %}
    {% if routeSettings[keyword] is defined and routeSettings[keyword] == routeName %}
    {% set routeString = route %}
    {% endif %}
{% endfor %}

Twig code above will assign url structure of route to variable - in our example this structure is tags/<slug>. Now, we just need to replace <slug> token with actual slug of specific tag we are linking to. In order to do that, we need to divide route structure into an array of segments using split filter, use regular expression to find segment with token and replace it.

{% set token = singletag.slug %}
{% set routes = routeString|split('/') %}
{% set resultArray = [] %}
{% for value in routes %}
    {% if value matches '/\\<[\\w]+\\>/' %}
            {% set value = token %} 
    {% endif %}
    {% set resultArray = resultArray|merge([value]) %}
{% endfor %}
{% set result = resultArray|join('/') %}

And there we have it - variable result contains ready to use route url! We can use it inside href attribute of link. For tag with slug 'super-blog-tag', variable result will contain 'tag-list/super-blog-tag'.

Now we just have pass route url to url function - it will prepent it with base url of current site.

{{url(result)}}

Macro to the rescue #

Of course we don't need to paste all this code into template each time we want to use it. When dealing with repetitive fragments of Twig code, its always worth to encapsule it within macro.

{% macro url(routeName, tokens) %}
{% spaceless %}
{% set keyword = 'name' %}
{% set routeString = null %}
{% for route, routeSettings in craft.app.routes.getConfigFileRoutes %}
    {% if routeSettings[keyword] is defined and routeSettings[keyword] == routeName %}
    {% set routeString = route %}
    {% endif %}
{% endfor %}
{% if routeString and tokens is not empty %}
    {% set routes = routeString|split('/') %}
    {% set tokenIndex = 0 %}
    {% set resultArray = [] %}
    {% for value in routes %}
        {% if value matches '/\\<[\\w]+\\>/' %}
            {% if tokens is iterable %}
                {% set value = tokens[tokenIndex] %} 
                {% set tokenIndex = tokenIndex + 1 %}
            {% else %}
                {% set value = tokens %} 
            {% endif %}
        {% endif %}
        {% set resultArray = resultArray|merge([value]) %}
    {% endfor %}
    {% set result = resultArray|join('/') %}
    {{url(result)}}
{% endif %}
{% endspaceless %}
{% endmacro %}

This macro accepts two parameters - routeName and tokens. routeName is string identyfying our route within config/routes.php. tokens can be either string - when your route contains single token, or numeric array, if it contasins multiple tokens.

This is how such macro would be used in practice - assuming that singletag object is avaible:

{% import 'macros' as m %}
<a href="{{m.url('tag', singletag.slug)}}">{{singletag.title}}</a>

Inspiration #

Those of you that worked with Django before, might have noticed this macro's similarity to Django url template tag. This is no coincidence - I wanted to replicate same functionality with Craft CMS.

I hope that some day Craft devs will add such functionality to Craft - and if you also would like that to happen, you can upvote THIS github issue.


TAGS:
#Craft CMS 3 #Twig macro #Outdated articles
Table of contents:
  • What's it all about?
  • Accessing routes from within Twig templates
  • Macro to the rescue
  • Inspiration
Quick links for this article:
URL macro on github gists
Let the expert handle
your Craft CMS project.
70 Basic icons by Xicons.co
piotrpog@protonmail.com
Copyright © 2026 Piotr Pogorzelski
piotrpog@protonmail.com      LinkedIn profile      Github profile