Twig Recipes

This page contains an assortment of problems and their respective solutions related to Twig templating.

  1. List the last 5 recent blog posts
  2. List the blog posts for the year
  3. Displaying a translated month
  4. Displaying page content without summary
  5. Hiding the email to spam bots
  6. Picking a random item from a translated array

List the last 5 recent blog posts

Problem:

You want to display the last 5 blog posts in a sidebar of your site so a reader can see recent blog activity.

Solution:

Simply find the /blog page, obtain it's children, order them by date in a descending order, and then get the first 5 to display in a list:

<ul>
{% for post in page.find('/blog').children.order('date', 'desc').slice(0, 5) %}
    <li class="recent-posts">
        <strong><a href="{{ post.url }}">{{ post.title }}</a></strong>
    </li>
{% endfor %}
</ul>

when using within pages make sure you add following configuration to the page header:

twig_first: true
process:
    twig: true

List the blog posts for the year

Problem:

You want to display all the blog posts that have occurred in this calendar year.

Solution:

Simply find the /blog page, obtain it's children, filter by appropriate dateRange(), and order them by date in a descending order:

<ul>
{% set this_year = "now"|date('Y') %}
{% for post in page.find('/blog').children.dateRange('01/01/' ~ this_year, '12/31/' ~ this_year).order('date', 'desc') %}
    <li class="recent-posts">
        <strong><a href="{{ post.url }}">{{ post.title }}</a></strong>
    </li>
{% endfor %}
</ul>

Displaying a translated month

Problem:

In some page templates, the Twig date filter is used, and it does not handle locales / multilanguage. So even if your page is in a language different than english, it could show the month in english, if the template chooses to show the month name.

Solution:

There are two solutions to this problem.

First approach

The first involves the use of the Twig intl extension.

Install https://github.com/Perlkonig/grav-plugin-twig-extensions. Make sure you have the PHP intl extension installed.

In your twig template, instead of for example (like in the Antimatter theme) {{ page.date|date("M") }} to {{ page.date|localizeddate('long', 'none', 'it', 'Europe/Rome', 'MMM') }} (add your language and timezone here)

Second approach

Let's assume you have some language translations setup in your user/languages/ folder called en.yaml that contains the entry:

MONTHS_OF_THE_YEAR: [January, February, March, April, May, June, July, August, September, October, November, December]

And in fr.yaml:

MONTHS_OF_THE_YEAR: [Janvier, Février, Mars, Avril, Mai, Juin, Juillet, Août, Septembre, Octobre, Novembre, Décembre]

Then you have your Twig:

<li>
    <a href='{{ post.url }}'><aside class="dates">{{ 'MONTHS_OF_THE_YEAR'|ta(post.date|date('n') - 1) }} {{ post.date|date('d') }}</aside></a>
    <a href='{{ post.url }}'>{{ post.title }}</a>
</li>

This makes use of the Grav custom Twig filter |ta that stands for Translate Array. In the English version, the output might be something like:

An Example Post  July 2015

And the French:

Un exemple d’article Juillet 2015

Displaying page content without summary

Problem:

You want to display the content of a page without the summary at top.

Solution:

Use the slice filter to remove the summary from the page content:

{% set content = page.content|slice(page.summary|length) %}
{{ content }}

Hiding the email to spam bots

Problem:

You want to hide the email from spam bots

Solution:

Enable Twig processing in the page header:

process:
    twig: true

Then use the safe_email Twig filter:

<a href="mailto:{{'your.email@server.com'|safe_email}}">
  Email me
</a>

Picking a random item from a translated array

Problem:

You want to pick a random item from an array translated in a particular language. For this to work, it's assumed you have your multi-language site setup and configured as outlined in the documentation.

Solution:

Let's also assume you have some language translations setup in your user/languages/ folder called en.yaml that contains the entry:

FRUITS: [Banana, Cherry, Lemon, Lime, Strawberry, Raspberry]

And in fr.yaml:

FRUITS: [Banana, Cerise, Citron, Citron Vert, Fraise, Framboise]

Then you have your Twig:

{% set langobj  = grav['language'] %}
{% set curlang  = langobj.getLanguage() %}
{% set fruits   = langobj.getTranslation(curlang,'FRUITS',true) %}
<span data-ticker="{{ fruits|join(',') }}">{{ random(fruits) }}</span>