13

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:

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
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:

<h1>{{ siteName }}</h1>

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 %}
        <p>{{ block.text }}</p>
    {% 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.