<blockquote>
  <p><em>To encourage input, this is a community wiki post. Any user with at least 100 reputation points may contribute.</em> </p>
</blockquote>

<h1>Functions, filters, objects, macros and statements – when to use which</h1>

<p>A <strong>function</strong> is one of the simplest constructs in Twig – it takes one or more inputs and returns a single output:</p>

<pre><code>{{ round(42.9) }} will output 43
</code></pre>

<p>These are best used for simple, commonly used operations that generate or transform data, such as a Lorem-Ipsum generator: <code>{{ loremIpsum(50) }}</code>. But note that functions are often better grouped into an object to prevent name collisions (see below).</p>

<p>A <strong>filter</strong> is almost identical to a function, except that it offers a different syntax, which can be more readable when chaining several filters together (they read in progressive order):</p>

<pre><code>{{ 1000000 | number }} will output 1,000,000
{{ 1000000 | number(false) }} will output 1000000
{{ 'ABC' | lower | replace('c', 'd') }} will output abd
</code></pre>

<p>It also provides an easy way to wrap around a larger block of text:</p>

<pre><code>{% filter upper %}
    This text becomes uppercase
{% endfilter %}
</code></pre>

<p>Note that you can also do this with a function, but it requires an additional line:</p>

<pre><code>{% set myText %}
    A quick brown fox
{% endset %}
{{ filterCurseWords(myText) }}
</code></pre>

<p>Use a filter when:</p>

<ul>
<li>It might be necessary to place it in a chain along with other filters</li>
<li>It might be necessary to place around larger blocks of text/content</li>
</ul>

<p>A <strong>global variable</strong> is one accessible to all templates in your project automatically:</p>

<pre><code>&lt;h1&gt;{{ siteName }}&lt;/h1&gt;
</code></pre>

<p>A <strong>global object</strong> is also accessible to all templates in your project, but can contain variables, functions or both:</p>

<pre><code>{{ currentUser.friendlyName }}
{{ currentUser.can('accessCp') }}
</code></pre>

<p>Objects provide a good way to neatly group variables and functions and prevent collisions.</p>

<p>A Twig <strong>statement</strong> (sometimes called a "logic tag") is used to designate the flow of logic and may only execute the content inside based on certain circumstances.</p>

<pre><code>{% cache %}
    {% for block in entry.myMatrixField %}
        &lt;p&gt;{{ block.text }}&lt;/p&gt;
    {% endfor %}
{% endcache %}
</code></pre>

<p>Note that caching would not work as a filter, because the content inside a filter is always executed <em>prior</em> to being passed into the filter. By implementing the cache tag as a <em>statement</em>, it is able to only execute the content inside when appropriate.</p>

<p>Finally, it's worth mentioning <strong>macros</strong>. They assist with reusing snippets of content or HTML in multiple places. Mijingo has written a <a href="https://mijingo.com/blog/using-macros-in-twig-and-craft" rel="noreferrer">great tutorial</a> that explains macros in Craft.</p>

<pre><code>{% import "forms.html" as forms %}
{{ forms.input('username') }}
</code></pre>

<p>Note, however, that the functionality of macros can sometimes be replicated via a simple include, with less code and more clarity:</p>

<pre><code>{% include 'mySnippet' with { enabled: true } %}
</code></pre>

<hr>

<h1>Creating a custom Twig filter</h1>

<pre><code>{{ myVariable | myFilter }}
</code></pre>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Accessing a plugin's variables and functions</h1>

<pre><code>{{ craft.myPlugin.myVariable }}
{{ craft.myPlugin.myFunction() }}
</code></pre>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Creating a custom global function</h1>

<pre><code>{{ customFunction() }}
</code></pre>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Creating a custom global object</h1>

<pre><code>{{ browser.version }}
{{ browser.isMobile() }}
</code></pre>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Creating a custom statement (logic tag)</h1>

<pre><code>{% devOnly %}
    ...output some debugging info here...
{% endDevOnly %}
</code></pre>

<p>Refer to <a href="http://twig.sensiolabs.org/doc/2.x/advanced.html#tags" rel="noreferrer">http://twig.sensiolabs.org/doc/2.x/advanced.html#tags</a></p>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<p>Be aware that sometimes the functionality can be achieved by creating a filter instead of a statement:</p>

<pre><code>{% filter uppercase %}
    A quick brown fox
{% endfilter %}
</code></pre>

<p>However the benefit of a statement is that the code inside is not run unless the statement permits it, whereas in a filter the code is always run, and then later sent to the filter.</p>

<hr>

<h1>Creating a custom operator</h1>

<pre><code>{{ ! true }}
</code></pre>

<p>Refer to <a href="http://twig.sensiolabs.org/doc/2.x/advanced.html#operators" rel="noreferrer">http://twig.sensiolabs.org/doc/2.x/advanced.html#operators</a></p>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Calling a plugin service class from Twig</h1>

<p>Under normal circumstances, Twig templates only have access to a plugins <em>Variable Classes</em> and not their <em>Service Classes</em>. But using a simple PHP trick, you can pass all calls on transparently:</p>

<p><em>Twig > Variable Class > Service Class</em></p>

<pre><code>// craft/plugins/YourPlugin/variables/YourPluginVariable.php
class YourPluginVariable
{
    /** 
     * If function is not found in this class, go find it in service class
     */
    function __call($method, $arguments) {
        return call_user_func_array(array(craft()-&gt;YourPlugin_YourService, $method), $arguments);
    }   
}
</code></pre>

<p>Be sure to rename <code>YourPlugin</code> and <code>YourService</code> to reflect the names of your plugin and service class.</p>

<hr>

<h1>Making custom database calls from Twig</h1>

<pre><code>{{ craft.myPlugin.fetchUserCount() }}
</code></pre>

<p>Firstly this requires a custom plugin. </p>

<p>In Craft, database calls need to be made via a service class, however because you can only access <em>variable classes</em> from Twig, you need to pass one to the other. (See the point above for a clean way to transparently pass calls from a variable class to a service class.)</p>

<p>Twig > Variable Class > Service Class > Database Query</p>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Post-processing HTML after Twig has finished rendering</h1>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

<hr>

<h1>Changing Twig settings</h1>

<p><em>More content to come here. Feel free to contribute some instructions if you're able.</em></p>

CC BY-SA 3.0
2017-01-11T01:11:10.207Z
2018-02-22T14:20:34.040Z
2018-02-22T14:20:34.040Z
Simon East
<p>So Craft's implementation of Twig is already very powerful and suitable to most common tasks. The Craft Docs already provide a great intro into using Twig and the handy extensions provided by Craft:</p>

<ul>
<li><a href="https://craftcms.com/docs/templating-overview" rel="noreferrer">Craft Templating Overview</a></li>
<li><a href="https://craftcms.com/docs/twig-primer" rel="noreferrer">Craft Twig Primer</a></li>
<li><a href="https://craftcms.com/docs/templating" rel="noreferrer">Craft Full Templating Reference</a></li>
</ul>

<p><strong>But what about when you need to go further and build in some sweet custom functionality?</strong></p>

<p>This question serves to be a starting point that summarises all the different ways to extend Twig with custom functionality, including:</p>

<ul>
<li>Filters, functions, objects, macros and statements – when to use which</li>
<li>Creating a custom Twig filter</li>
<li>Accessing variables and functions in a plugin</li>
<li>Creating a custom global function</li>
<li>Creating a custom global object</li>
<li>Creating a custom statement (or "logic tag")</li>
<li>Creating a custom operator</li>
<li>Calling a plugin service class from Twig </li>
<li>Making custom database calls from Twig</li>
<li>Post-processing HTML after Twig has finished rendering</li>
<li>Changing Twig settings</li>
</ul>

<plugin-development><templating><twigextension>
The Definitive Guide to Extending Twig in Craft CMS
# The Definitive Guide to Extending Twig in Craft CMS

(Asked by: username_0 on 2017-01-11)

So Craft's implementation of Twig is already very powerful and suitable to most common tasks. The Craft Docs already provide a great intro into using Twig and the handy extensions provided by Craft:

* [Craft Templating Overview](https://craftcms.com/docs/templating-overview)
* [Craft Twig Primer](https://craftcms.com/docs/twig-primer)
* [Craft Full Templating Reference](https://craftcms.com/docs/templating)

**But what about when you need to go further and build in some sweet custom functionality?**

This question serves to be a starting point that summarises all the different ways to extend Twig with custom functionality, including:

* Filters, functions, objects, macros and statements – when to use which
* Creating a custom Twig filter
* Accessing variables and functions in a plugin
* Creating a custom global function
* Creating a custom global object
* Creating a custom statement (or "logic tag")
* Creating a custom operator
* Calling a plugin service class from Twig
* Making custom database calls from Twig
* Post-processing HTML after Twig has finished rendering
* Changing Twig settings

**Tags:** plugin-development, templating, twigextension


---

## 1 answers

### Answer by username_0 on 2017-01-11. Score: 14

To encourage input, this is a community wiki post. Any user with at least 100 reputation points may contribute. 

Functions, filters, objects, macros and statements – when to use which
A function is one of the simplest constructs in Twig – it takes one or more inputs and returns a single output:
{{ round(42.9) }} will output 43

These are best used for simple, commonly used operations that generate or transform data, such as a Lorem-Ipsum generator: {{ loremIpsum(50) }}. But note that functions are often better grouped into an object to prevent name collisions (see below).
A filter is almost identical to a function, except that it offers a different syntax, which can be more readable when chaining several filters together (they read in progressive order):
{{ 1000000 | number }} will output 1,000,000
{{ 1000000 | number(false) }} will output 1000000
{{ 'ABC' | lower | replace('c', 'd') }} will output abd

It also provides an easy way to wrap around a larger block of text:
{% filter upper %}
    This text becomes uppercase
{% endfilter %}

Note that you can also do this with a function, but it requires an additional line:
{% set myText %}
    A quick brown fox
{% endset %}
{{ filterCurseWords(myText) }}

Use a filter when:

It might be necessary to place it in a chain along with other filters
It might be necessary to place around larger blocks of text/content

A global variable is one accessible to all templates in your project automatically:
{{ siteName }}

A global object is also accessible to all templates in your project, but can contain variables, functions or both:
{{ currentUser.friendlyName }}
{{ currentUser.can('accessCp') }}

Objects provide a good way to neatly group variables and functions and prevent collisions.
A Twig statement (sometimes called a "logic tag") is used to designate the flow of logic and may only execute the content inside based on certain circumstances.
{% cache %}
    {% for block in entry.myMatrixField %}
        {{ block.text }}
    {% endfor %}
{% endcache %}

Note that caching would not work as a filter, because the content inside a filter is always executed prior to being passed into the filter. By implementing the cache tag as a statement, it is able to only execute the content inside when appropriate.
Finally, it's worth mentioning macros. They assist with reusing snippets of content or HTML in multiple places. Mijingo has written a great tutorial that explains macros in Craft.
{% import "forms.html" as forms %}
{{ forms.input('username') }}

Note, however, that the functionality of macros can sometimes be replicated via a simple include, with less code and more clarity:
{% include 'mySnippet' with { enabled: true } %}


Creating a custom Twig filter
{{ myVariable | myFilter }}

More content to come here. Feel free to contribute some instructions if you're able.

Accessing a plugin's variables and functions
{{ craft.myPlugin.myVariable }}
{{ craft.myPlugin.myFunction() }}

More content to come here. Feel free to contribute some instructions if you're able.

Creating a custom global function
{{ customFunction() }}

More content to come here. Feel free to contribute some instructions if you're able.

Creating a custom global object
{{ browser.version }}
{{ browser.isMobile() }}

More content to come here. Feel free to contribute some instructions if you're able.

Creating a custom statement (logic tag)
{% devOnly %}
    ...output some debugging info here...
{% endDevOnly %}

Refer to http://twig.sensiolabs.org/doc/2.x/advanced.html#tags
More content to come here. Feel free to contribute some instructions if you're able.
Be aware that sometimes the functionality can be achieved by creating a filter instead of a statement:
{% filter uppercase %}
    A quick brown fox
{% endfilter %}

However the benefit of a statement is that the code inside is not run unless the statement permits it, whereas in a filter the code is always run, and then later sent to the filter.

Creating a custom operator
{{ ! true }}

Refer to http://twig.sensiolabs.org/doc/2.x/advanced.html#operators
More content to come here. Feel free to contribute some instructions if you're able.

Calling a plugin service class from Twig
Under normal circumstances, Twig templates only have access to a plugins Variable Classes and not their Service Classes. But using a simple PHP trick, you can pass all calls on transparently:
Twig > Variable Class > Service Class
// craft/plugins/YourPlugin/variables/YourPluginVariable.php
class YourPluginVariable
{
    /** 
     * If function is not found in this class, go find it in service class
     */
    function __call($method, $arguments) {
        return call_user_func_array(array(craft()->YourPlugin_YourService, $method), $arguments);
    }   
}

Be sure to rename YourPlugin and YourService to reflect the names of your plugin and service class.

Making custom database calls from Twig
{{ craft.myPlugin.fetchUserCount() }}

Firstly this requires a custom plugin. 
In Craft, database calls need to be made via a service class, however because you can only access variable classes from Twig, you need to pass one to the other. (See the point above for a clean way to transparently pass calls from a variable class to a service class.)
Twig > Variable Class > Service Class > Database Query
More content to come here. Feel free to contribute some instructions if you're able.

Post-processing HTML after Twig has finished rendering
More content to come here. Feel free to contribute some instructions if you're able.

Changing Twig settings
More content to come here. Feel free to contribute some instructions if you're able.


---

