Twig Tags
Grav also provides a variety of custom Twig Tags that extend the already very capable Twig templating capabilities with some new tags that we've found useful.
markdown
The Markdown tag provides a powerful new way to embed markdown in Twig template. You could use a variable and render that variable with the |markdown filter, but the {% markdown %} syntax makes creating blocks of markdown text even simpler.
1{% markdown %}
2This is **bold** and this _underlined_
3
41. This is a bullet list
52. This is another item in that same list
6{% endmarkdown %}
1<p>This is <strong>bold</strong> and this <em>underlined</em></p>
2<ol>
3<li>This is a bullet list</li>
4<li>This is another item in that same list</li>
5</ol>
script
The Script tag is really a convenience tag that keeps your Twig more readable compared to the usual {% do assets...%} approach. It's purely an alternative way of writing things.
Script File
{% script 'theme://js/something.js' at 'bottom' priority: 20 with { defer: true, async: true } %}
<script src="/user/themes/mytheme/js/something.js" defer async></script>
Grav 1.7.28 adds also support for modules:
{% script module 'theme://js/module.mjs' %}
<script type="module" src="/user/themes/mytheme/js/module.mjs"></script>
Inline Script
{% script at 'bottom' priority: 20 %}
alert('Warning!');
{% endscript %}
<script>
alert('Warning!');
</script>
style
CSS File
{% style 'theme://css/foo.css' priority: 20 %}
<link rel="stylesheet" href="/user/themes/mytheme/css/foo.css">
Inline CSS
{% style priority: 20 with { media: 'screen' } %}
a { color: red; }
{% endstyle %}
<style media="screen">
a { color: red; }
</style>
link
{% link icon 'theme://images/favicon.png' priority: 20 with { type: 'image/png' } %}
{% link modulepreload 'plugin://grav-plugin/build/js/vendor.js' %}
<link rel="icon" href="/user/themes/mytheme/images/favicon.png" type="image/png">
<link rel="modulepreload" href="/user/plugins/grav-plugin/build/js/vendor.js">
switch
In most programming language, using a switch statement is a common way to make a bunch of if else statements cleaner and more readabile. Also they may prove to be marginally faster. We just provide a simple way of creating these as they were missing in the base Twig functionality.
1{% switch type %}
2 {% case 'foo' %}
3 {{ my_data.foo }}
4 {% case 'bar' %}
5 {{ my_data.bar }}
6 {% default %}
7 {{ my_data.default }}
8{% endswitch %}
(outputs the value of my_data.foo, my_data.bar, or my_data.default based on type)
deferred
With traditional blocks, once the block has been rendered, it cannot be manipulated. Take the example of a {% block scripts %} that might hold some entries for JavaScript includes. If you have a child Twig template, and you extend a base template where this block is defined, you can extend the block, and add your own custom JavaScript entries. However, partial twig templates that are included from this page, cannot reach or interact with the block.
The deferred attribute on the block which is powered by the Deferred Extension, means that you can define this block in any Twig template, but its rendering is deferred, so that it renders after everything else. This means that you can add JavaScript references via the {% do assets.addJs() %} call from anywhere in your page, and because the rendering is deferred, the output will contain all the assets that Grav knows about, no matter when you added them.
{% block myblock deferred %}
This will be rendered after everything else.
{% endblock %}
This will be rendered after everything else.
It is also possible to merge the content of the parent block with the deferred block using {{ parent() }}. This can be especially useful for themes if additional css or javascript files are added.
{% block stylesheets %}
<!-- Additional css library -->
{% do assets.addCss('theme://libraries/leaflet/dist/leaflet.css') %}
{{ parent() }}
{% endblock %}
<link rel="stylesheet" href="/user/themes/mytheme/libraries/leaflet/dist/leaflet.css">
<!-- parent stylesheets content -->
throw
There are certain situations where you need to manually throw an exception, so we have a tag for that too.
{% throw 404 'Not Found' %}
(throws HTTP 404 Not Found exception)
try & catch
Also it's useful to have more powerful PHP-style error handling in your Twig templates so we have a new try/catch tag.
{% try %}
<li>{{ user.get('name') }}</li>
{% catch %}
User Error: {{ e.message }}
{% endcatch %}
<li>John Doe</li>
(or if error: User Error: User not found)
render
Flex Objects are slowly making their way into more and more elements of Grav. These are self-aware objects that have an associated Twig template structure, so they know how to render themselves. In order to use these, we have implemented a new render tag that takes an optional layout which in turn controls which of the template layouts the object should be rendered with.
{% render collection layout: 'list' %}
{% render object layout: 'default' with { variable: 'value' } %}
<!-- renders collection using list.html.twig template -->
<!-- renders object using default.html.twig template with variable -->
cache
Sometimes you may need to cache parts of the page, which take a lot of time to render. You can do this with cache tag.
{% cache 600 %}
{{ some_complex_work() }}
{% endcache %}
(cached output of some_complex_work() for 600 seconds)
In the example 600 is an optional lifetime in seconds. If the parameter isn't passed, default cache lifetime will be used.