From b096e21daa6647cd23063c3a4e4280ad81df8f84 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Sep 2011 23:40:44 +0200 Subject: [PATCH] refactored documentation --- doc/filters/capitalize.rst | 11 + doc/filters/date.rst | 34 + doc/filters/default.rst | 18 + doc/filters/escape.rst | 30 + doc/filters/format.rst | 16 + doc/filters/index.rst | 25 + doc/filters/join.rst | 18 + doc/filters/json_encode.rst | 8 + doc/filters/keys.rst | 11 + doc/filters/length.rst | 12 + doc/filters/lower.rst | 10 + doc/filters/merge.rst | 12 + doc/filters/raw.rst | 12 + doc/filters/replace.rst | 14 + doc/filters/reverse.rst | 13 + doc/filters/sort.rst | 17 + doc/filters/striptags.rst | 16 + doc/filters/title.rst | 11 + doc/filters/upper.rst | 10 + doc/filters/url_encode.rst | 8 + doc/functions/attribute.rst | 18 + doc/functions/block.rst | 15 + doc/functions/constant.rst | 8 + doc/functions/cycle.rst | 20 + doc/functions/index.rst | 12 + doc/functions/parent.rst | 20 + doc/functions/range.rst | 38 + doc/index.rst | 4 + doc/tags/autoescape.rst | 43 ++ doc/tags/block.rst | 11 + doc/tags/extends.rst | 188 +++++ doc/tags/filter.rst | 21 + doc/tags/for.rst | 126 ++++ doc/tags/from.rst | 8 + doc/tags/if.rst | 33 + doc/tags/import.rst | 79 +++ doc/tags/include.rst | 83 +++ doc/tags/index.rst | 20 + doc/tags/macro.rst | 91 +++ doc/tags/raw.rst | 16 + doc/tags/set.rst | 32 + doc/tags/spaceless.rst | 14 + doc/tags/use.rst | 123 ++++ doc/templates.rst | 1603 ++++++++----------------------------------- doc/tests/constant.rst | 11 + doc/tests/defined.rst | 17 + doc/tests/divisibleby.rst | 10 + doc/tests/empty.rst | 11 + doc/tests/even.rst | 10 + doc/tests/index.rst | 14 + doc/tests/none.rst | 8 + doc/tests/odd.rst | 10 + doc/tests/sameas.rst | 11 + 53 files changed, 1733 insertions(+), 1301 deletions(-) create mode 100644 doc/filters/capitalize.rst create mode 100644 doc/filters/date.rst create mode 100644 doc/filters/default.rst create mode 100644 doc/filters/escape.rst create mode 100644 doc/filters/format.rst create mode 100644 doc/filters/index.rst create mode 100644 doc/filters/join.rst create mode 100644 doc/filters/json_encode.rst create mode 100644 doc/filters/keys.rst create mode 100644 doc/filters/length.rst create mode 100644 doc/filters/lower.rst create mode 100644 doc/filters/merge.rst create mode 100644 doc/filters/raw.rst create mode 100644 doc/filters/replace.rst create mode 100644 doc/filters/reverse.rst create mode 100644 doc/filters/sort.rst create mode 100644 doc/filters/striptags.rst create mode 100644 doc/filters/title.rst create mode 100644 doc/filters/upper.rst create mode 100644 doc/filters/url_encode.rst create mode 100644 doc/functions/attribute.rst create mode 100644 doc/functions/block.rst create mode 100644 doc/functions/constant.rst create mode 100644 doc/functions/cycle.rst create mode 100644 doc/functions/index.rst create mode 100644 doc/functions/parent.rst create mode 100644 doc/functions/range.rst create mode 100644 doc/tags/autoescape.rst create mode 100644 doc/tags/block.rst create mode 100644 doc/tags/extends.rst create mode 100644 doc/tags/filter.rst create mode 100644 doc/tags/for.rst create mode 100644 doc/tags/from.rst create mode 100644 doc/tags/if.rst create mode 100644 doc/tags/import.rst create mode 100644 doc/tags/include.rst create mode 100644 doc/tags/index.rst create mode 100644 doc/tags/macro.rst create mode 100644 doc/tags/raw.rst create mode 100644 doc/tags/set.rst create mode 100644 doc/tags/spaceless.rst create mode 100644 doc/tags/use.rst create mode 100644 doc/tests/constant.rst create mode 100644 doc/tests/defined.rst create mode 100644 doc/tests/divisibleby.rst create mode 100644 doc/tests/empty.rst create mode 100644 doc/tests/even.rst create mode 100644 doc/tests/index.rst create mode 100644 doc/tests/none.rst create mode 100644 doc/tests/odd.rst create mode 100644 doc/tests/sameas.rst diff --git a/doc/filters/capitalize.rst b/doc/filters/capitalize.rst new file mode 100644 index 0000000..10546a1 --- /dev/null +++ b/doc/filters/capitalize.rst @@ -0,0 +1,11 @@ +``capitalize`` +============== + +The ``capitalize`` filter capitalizes a value. The first character will be +uppercase, all others lowercase: + +.. code-block:: jinja + + {{ 'my first car'|capitalize }} + + {# outputs 'My first car' #} diff --git a/doc/filters/date.rst b/doc/filters/date.rst new file mode 100644 index 0000000..32032ac --- /dev/null +++ b/doc/filters/date.rst @@ -0,0 +1,34 @@ +``date`` +======== + +.. versionadded:: 1.1 + The timezone support has been added in Twig 1.1. + +The ``date`` filter formats a date to a given format: + +.. code-block:: jinja + + {{ post.published_at|date("m/d/Y") }} + +The ``date`` filter accepts any date format supported by `date`_ and +`DateTime`_ instances. For instance, to display the current date, filter the +word "now": + +.. code-block:: jinja + + {{ "now"|date("m/d/Y") }} + +To escape words and characters in the date format use ``\\`` in front of each character: + +.. code-block:: jinja + + {{ post.published_at|date("F jS \\a\\t g:ia") }} + +You can also specify a timezone: + +.. code-block:: jinja + + {{ post.published_at|date("m/d/Y", "Europe/Paris") }} + +.. _`date`: http://www.php.net/date +.. _`DateTime`: http://www.php.net/manual/en/datetime.construct.php diff --git a/doc/filters/default.rst b/doc/filters/default.rst new file mode 100644 index 0000000..3fc0845 --- /dev/null +++ b/doc/filters/default.rst @@ -0,0 +1,18 @@ +``default`` +=========== + +The ``default`` filter returns the passed default value if the value is +undefined or empty, otherwise the value of the variable: + +.. code-block:: jinja + + {{ var|default('var is not defined') }} + + {{ var.foo|default('foo item on var is not defined') }} + + {{ ''|default('passed var is empty') }} + +.. note:: + + Read the documentation for the :doc:`defined<../tests/defined>` and + :doc:`empty<../tests/empty>` tests to learn more about their semantics. diff --git a/doc/filters/escape.rst b/doc/filters/escape.rst new file mode 100644 index 0000000..dd927b4 --- /dev/null +++ b/doc/filters/escape.rst @@ -0,0 +1,30 @@ +``escape`` +========== + +The ``escape`` filter converts the characters ``&``, ``<``, ``>``, ``'``, and +``"`` in strings to HTML-safe sequences. Use this if you need to display text +that might contain such characters in HTML: + +.. code-block:: jinja + + {{ user.username|escape }} + +For convenience, the ``e`` filter is defined as an alias: + +.. code-block:: jinja + + {{ user.username|e }} + +The ``escape`` filter can also be used in another context than HTML; for +instance, to escape variables included in a JavaScript: + +.. code-block:: jinja + + {{ user.username|escape('js') }} + {{ user.username|e('js') }} + +.. note:: + + Internally, ``escape`` uses the PHP native `htmlspecialchars`_ function. + +.. _`htmlspecialchars`: http://php.net/htmlspecialchars diff --git a/doc/filters/format.rst b/doc/filters/format.rst new file mode 100644 index 0000000..fd5b18d --- /dev/null +++ b/doc/filters/format.rst @@ -0,0 +1,16 @@ +``format`` +========== + +The ``format`` filter formats a given string by replacing the placeholders +(placeholders follows the `printf`_ notation): + +.. code-block:: jinja + + {{ "I like %s and %s."|format(foo, "bar") }} + + {# returns I like foo and bar + if the foo parameter equals to the foo string. #} + +.. _`printf`: http://www.php.net/printf + +.. seealso:: :doc:`replace` diff --git a/doc/filters/index.rst b/doc/filters/index.rst new file mode 100644 index 0000000..48dfbf6 --- /dev/null +++ b/doc/filters/index.rst @@ -0,0 +1,25 @@ +Filters +======= + +.. toctree:: + :maxdepth: 1 + + date + format + replace + url_encode + json_encode + title + capitalize + upper + lower + striptags + join + reverse + length + sort + default + keys + escape + raw + merge diff --git a/doc/filters/join.rst b/doc/filters/join.rst new file mode 100644 index 0000000..eec2045 --- /dev/null +++ b/doc/filters/join.rst @@ -0,0 +1,18 @@ +``join`` +======== + +The ``join`` filter returns a string which is the concatenation of the items +of a sequence: + +.. code-block:: jinja + + {{ [1, 2, 3]|join }} + {# returns 123 #} + +The separator between elements is an empty string per default, but you can +define it with the optional first parameter: + +.. code-block:: jinja + + {{ [1, 2, 3]|join('|') }} + {# returns 1|2|3 #} diff --git a/doc/filters/json_encode.rst b/doc/filters/json_encode.rst new file mode 100644 index 0000000..24b479f --- /dev/null +++ b/doc/filters/json_encode.rst @@ -0,0 +1,8 @@ +``json_encode`` +=============== + +The ``json_encode`` filter returns the JSON representation of a string: + +.. code-block:: jinja + + {{ data|json_encode() }} diff --git a/doc/filters/keys.rst b/doc/filters/keys.rst new file mode 100644 index 0000000..e4f090c --- /dev/null +++ b/doc/filters/keys.rst @@ -0,0 +1,11 @@ +``keys`` +======== + +The ``keys`` filter returns the keys of an array. It is useful when you want to +iterate over the keys of an array: + +.. code-block:: jinja + + {% for key in array|keys %} + ... + {% endfor %} diff --git a/doc/filters/length.rst b/doc/filters/length.rst new file mode 100644 index 0000000..f79b9bd --- /dev/null +++ b/doc/filters/length.rst @@ -0,0 +1,12 @@ +``length`` +========== + +The ``length`` filters returns the number of items of a sequence or mapping, or +the length of a string: + +.. code-block:: jinja + + {% if users|length > 10 %} + ... + {% endif %} + diff --git a/doc/filters/lower.rst b/doc/filters/lower.rst new file mode 100644 index 0000000..ef9faa9 --- /dev/null +++ b/doc/filters/lower.rst @@ -0,0 +1,10 @@ +``lower`` +========= + +The ``lower`` filter converts a value to lowercase: + +.. code-block:: jinja + + {{ 'WELCOME'|lower }} + + {# outputs 'welcome' #} diff --git a/doc/filters/merge.rst b/doc/filters/merge.rst new file mode 100644 index 0000000..dfcb2f1 --- /dev/null +++ b/doc/filters/merge.rst @@ -0,0 +1,12 @@ +``merge`` +========= + +The ``merge`` filter merges an array or a hash with the given value: + +.. code-block:: jinja + + {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %} + + {% set items = items|merge({ 'peugeot': 'car' }) %} + + {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #} diff --git a/doc/filters/raw.rst b/doc/filters/raw.rst new file mode 100644 index 0000000..434dd24 --- /dev/null +++ b/doc/filters/raw.rst @@ -0,0 +1,12 @@ +``raw`` +======= + +The ``raw`` filter marks the value as being "safe", which means that in an +environment with automatic escaping enabled this variable will not be escaped +if ``raw`` is the last filter applied to it: + +.. code-block:: jinja + + {% autoescape true %} + {{ var|raw }} {# var won't be escaped #} + {% endautoescape %} diff --git a/doc/filters/replace.rst b/doc/filters/replace.rst new file mode 100644 index 0000000..cc603fa --- /dev/null +++ b/doc/filters/replace.rst @@ -0,0 +1,14 @@ +``replace`` +=========== + +The ``replace`` filter formats a given string by replacing the placeholders +(placeholders are free-form): + +.. code-block:: jinja + + {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }} + + {# returns I like foo and bar + if the foo parameter equals to the foo string. #} + +.. seealso:: :doc:`format` diff --git a/doc/filters/reverse.rst b/doc/filters/reverse.rst new file mode 100644 index 0000000..82bb7fb --- /dev/null +++ b/doc/filters/reverse.rst @@ -0,0 +1,13 @@ +``reverse`` +=========== + +The ``reverse`` filter reverses an array (or an object if it implements the +`Iterator`_ interface): + +.. code-block:: jinja + + {% for use in users|reverse %} + ... + {% endfor %} + +.. _`Iterator`: http://fr.php.net/manual/en/class.iterator.php diff --git a/doc/filters/sort.rst b/doc/filters/sort.rst new file mode 100644 index 0000000..0e330d2 --- /dev/null +++ b/doc/filters/sort.rst @@ -0,0 +1,17 @@ +``sort`` +======== + +The ``sort`` filter sorts an array: + +.. code-block:: jinja + + {% for use in users|sort %} + ... + {% endfor %} + +.. note:: + + Internally, Twig uses the PHP `asort`_ function to maintain index + association. + +.. _`asort`: http://php.net/asort diff --git a/doc/filters/striptags.rst b/doc/filters/striptags.rst new file mode 100644 index 0000000..7a3d9dd --- /dev/null +++ b/doc/filters/striptags.rst @@ -0,0 +1,16 @@ +``striptags`` +============= + +The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace +by one space: + +.. code-block:: jinja + + {% some_html|striptags %} + +.. note:: + + Internally, Twig uses the PHP `strip_tags`_ function to maintain index + association. + +.. _`strip_tags`: http://php.net/strip_tags diff --git a/doc/filters/title.rst b/doc/filters/title.rst new file mode 100644 index 0000000..c5a318e --- /dev/null +++ b/doc/filters/title.rst @@ -0,0 +1,11 @@ +``title`` +========= + +The ``title`` filter returns a titlecased version of the value. Words will +start with uppercase letters, all remaining characters are lowercase: + +.. code-block:: jinja + + {{ 'my first car'|title }} + + {# outputs 'My First Car' #} diff --git a/doc/filters/upper.rst b/doc/filters/upper.rst new file mode 100644 index 0000000..561cebe --- /dev/null +++ b/doc/filters/upper.rst @@ -0,0 +1,10 @@ +``upper`` +========= + +The ``upper`` filter converts a value to uppercase: + +.. code-block:: jinja + + {{ 'welcome'|upper }} + + {# outputs 'WELCOME' #} diff --git a/doc/filters/url_encode.rst b/doc/filters/url_encode.rst new file mode 100644 index 0000000..17204dc --- /dev/null +++ b/doc/filters/url_encode.rst @@ -0,0 +1,8 @@ +``url_encode`` +============== + +The ``url_encode`` filter URL encodes a given string: + +.. code-block:: jinja + + {{ data|url_encode() }} diff --git a/doc/functions/attribute.rst b/doc/functions/attribute.rst new file mode 100644 index 0000000..3051bda --- /dev/null +++ b/doc/functions/attribute.rst @@ -0,0 +1,18 @@ +``attribute`` +============= + +.. versionadded:: 1.2 + The ``attribute`` function was added in Twig 1.2. + +``attribute`` can be used to access a "dynamic" attribute of a variable: + +.. code-block:: jinja + + {{ attribute(object, method) }} + {{ attribute(object, method, arguments) }} + {{ attribute(array, item) }} + +.. note:: + + The resolution algorithm is the same as the one used for the ``.`` + notation, except that the item can be any valid expression. diff --git a/doc/functions/block.rst b/doc/functions/block.rst new file mode 100644 index 0000000..fd571ef --- /dev/null +++ b/doc/functions/block.rst @@ -0,0 +1,15 @@ +``block`` +========= + +When a template uses inheritance and if you want to print a block multiple +times, use the ``block`` function: + +.. code-block:: jinja + + {% block title %}{% endblock %} + +

{{ block('title') }}

+ + {% block body %}{% endblock %} + +.. seealso:: :doc:`extends<../tags/extends>`, :doc:`parent<../functions/parent>` diff --git a/doc/functions/constant.rst b/doc/functions/constant.rst new file mode 100644 index 0000000..68ab2cf --- /dev/null +++ b/doc/functions/constant.rst @@ -0,0 +1,8 @@ +``constant`` +============ + +``constant`` returns the constant value for a given string: + +.. code-block:: jinja + + {{ some_date|date(constant('DATE_W3C')) }} diff --git a/doc/functions/cycle.rst b/doc/functions/cycle.rst new file mode 100644 index 0000000..fe11d68 --- /dev/null +++ b/doc/functions/cycle.rst @@ -0,0 +1,20 @@ +``cycle`` +========= + +The ``cycle`` function cycles on an array of values: + +.. code-block:: jinja + + {% for i in 0..10 %} + {{ cycle(['odd', 'even'], i) }} + {% endfor %} + +The array can contain any number of values: + +.. code-block:: jinja + + {% set fruits = ['apple', 'orange', 'citrus'] %} + + {% for i in 0..10 %} + {{ cycle(fruits, i) }} + {% endfor %} diff --git a/doc/functions/index.rst b/doc/functions/index.rst new file mode 100644 index 0000000..d3a5feb --- /dev/null +++ b/doc/functions/index.rst @@ -0,0 +1,12 @@ +Functions +========= + +.. toctree:: + :maxdepth: 1 + + range + cycle + constant + attribute + block + parent diff --git a/doc/functions/parent.rst b/doc/functions/parent.rst new file mode 100644 index 0000000..f5bd200 --- /dev/null +++ b/doc/functions/parent.rst @@ -0,0 +1,20 @@ +``parent`` +========== + +When a template uses inheritance, it's possible to render the contents of the +parent block when overriding a block by using the ``parent`` function: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% block sidebar %} +

Table Of Contents

+ ... + {{ parent() }} + {% endblock %} + +The ``parent()`` call will return the content of the ``sidebar`` block as +defined in the ``base.html`` template. + +.. seealso:: :doc:`extends<../tags/extends>`, :doc:`block<../functions/block>`, :doc:`block<../tags/block>` diff --git a/doc/functions/range.rst b/doc/functions/range.rst new file mode 100644 index 0000000..c9bdd96 --- /dev/null +++ b/doc/functions/range.rst @@ -0,0 +1,38 @@ +``range`` +========= + +Returns a list containing an arithmetic progression of integers: + +.. code-block:: jinja + + {% for i in range(0, 3) %} + {{ i }}, + {% endfor %} + + {# returns 0, 1, 2, 3 #} + +When step is given (as the third parameter), it specifies the increment (or +decrement): + +.. code-block:: jinja + + {% for i in range(0, 6, 2) %} + {{ i }}, + {% endfor %} + + {# returns 0, 2, 4, 6 #} + +The Twig built-in ``..`` operator is just syntactic sugar for the ``range`` +function (with a step of 1): + +.. code-block:: jinja + + {% for i in 0..3 %} + {{ i }}, + {% endfor %} + +.. tip:: + + The ``range`` function works as the native PHP `range`_ function. + +.. _`range`: http://php.net/range diff --git a/doc/index.rst b/doc/index.rst index 73edce0..4d6c17b 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -11,3 +11,7 @@ Twig extensions hacking recipes + tags/index + filters/index + functions/index + tests/index diff --git a/doc/tags/autoescape.rst b/doc/tags/autoescape.rst new file mode 100644 index 0000000..89c0420 --- /dev/null +++ b/doc/tags/autoescape.rst @@ -0,0 +1,43 @@ +``autoescape`` +============== + +Whether automatic escaping is enabled or not, you can mark a section of a +template to be escaped or not by using the ``autoescape`` tag: + +.. code-block:: jinja + + {% autoescape true %} + Everything will be automatically escaped in this block + {% endautoescape %} + + {% autoescape false %} + Everything will be outputed as is in this block + {% endautoescape %} + + {% autoescape true js %} + Everything will be automatically escaped in this block + using the js escaping strategy + {% endautoescape %} + +When automatic escaping is enabled everything is escaped by default except for +values explicitly marked as safe. Those can be marked in the template by using +the :doc:`raw<../filters/raw>` filter: + +.. code-block:: jinja + + {% autoescape true %} + {{ safe_value|raw }} + {% endautoescape %} + +Functions returning template data (like :doc:`macros` and +:doc:`parent<../functions/parent>`) always return safe markup. + +.. note:: + + Twig is smart enough to not escape an already escaped value by the + :doc:`escape<../filters/escape>` filter. + +.. note:: + + The chapter :doc:`Twig for Developers<../api>` gives more information + about when and how automatic escaping is applied. diff --git a/doc/tags/block.rst b/doc/tags/block.rst new file mode 100644 index 0000000..b02d89a --- /dev/null +++ b/doc/tags/block.rst @@ -0,0 +1,11 @@ +``block`` +========= + +Blocks are used for inheritance and act as placeholders and replacements at +the same time. They are documented in detail in the documentation for the +:doc:`extends<../tags/extends>` tag. + +Block names should consist of alphanumeric characters, and underscores. Dashes +are not permitted. + +.. seealso:: :doc:`block<../functions/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>`, :doc:`use<../tags/extends>` diff --git a/doc/tags/extends.rst b/doc/tags/extends.rst new file mode 100644 index 0000000..0865bf8 --- /dev/null +++ b/doc/tags/extends.rst @@ -0,0 +1,188 @@ +``extends`` +=========== + +The ``extends`` tag can be used to extend a template from another one. + +.. note:: + + Like PHP, Twig does not support multiple inheritance. So you can only have + one extends tag called per rendering. However, Twig supports horizontal + :doc:`reuse`. + +Let's define a base template, ``base.html``, which defines a simple HTML +skeleton document: + +.. code-block:: html+jinja + + + + + {% block head %} + + {% block title %}{% endblock %} - My Webpage + {% endblock %} + + +
{% block content %}{% endblock %}
+ + + + +In this example, the :doc:`{% block %}` tags define four blocks +that child templates can fill in. All the ``block`` tag does is to tell the +template engine that a child template may override those portions of the +template. + +Child Template +-------------- + +A child template might look like this: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% block title %}Index{% endblock %} + {% block head %} + {{ parent() }} + + {% endblock %} + {% block content %} +

Index

+

+ Welcome on my awesome homepage. +

+ {% endblock %} + +The ``{% extends %}`` tag is the key here. It tells the template engine that +this template "extends" another template. When the template system evaluates +this template, first it locates the parent. The extends tag should be the +first tag in the template. + +Note that since the child template doesn't define the ``footer`` block, the +value from the parent template is used instead. + +You can't define multiple ``{% block %}`` tags with the same name in the same +template. This limitation exists because a block tag works in "both" +directions. That is, a block tag doesn't just provide a hole to fill - it also +defines the content that fills the hole in the *parent*. If there were two +similarly-named ``{% block %}`` tags in a template, that template's parent +wouldn't know which one of the blocks' content to use. + +If you want to print a block multiple times you can however use the +``block`` function: + +.. code-block:: jinja + + {% block title %}{% endblock %} +

{{ block('title') }}

+ {% block body %}{% endblock %} + +Parent Blocks +------------- + +It's possible to render the contents of the parent block by using the +:doc:`parent<../functions/parent>` function. This gives back the results of +the parent block: + +.. code-block:: jinja + + {% block sidebar %} +

Table Of Contents

+ ... + {{ parent() }} + {% endblock %} + +Named Block End-Tags +-------------------- + +Twig allows you to put the name of the block after the end tag for better +readability: + +.. code-block:: jinja + + {% block sidebar %} + {% block inner_sidebar %} + ... + {% endblock inner_sidebar %} + {% endblock sidebar %} + +Of course, the name after the ``endblock`` word must match the block name. + +Block Nesting and Scope +----------------------- + +Blocks can be nested for more complex layouts. Per default, blocks have access +to variables from outer scopes: + +.. code-block:: jinja + + {% for item in seq %} +
  • {% block loop_item %}{{ item }}{% endblock %}
  • + {% endfor %} + +Block Shortcuts +--------------- + +For blocks with few content, it's possible to use a shortcut syntax. The +following constructs do the same: + +.. code-block:: jinja + + {% block title %} + {{ page_title|title }} + {% endblock %} + +.. code-block:: jinja + + {% block title page_title|title %} + +Dynamic Inheritance +------------------- + +Twig supports dynamic inheritance by using a variable as the base template: + +.. code-block:: jinja + + {% extends some_var %} + +If the variable evaluates to a ``Twig_Template`` object, Twig will use it as +the parent template:: + + // {% extends layout %} + + $layout = $twig->loadTemplate('some_layout_template.twig'); + + $twig->display('template.twig', array('layout' => $layout)); + +.. versionadded:: 1.2 + The possibility to pass an array of templates has been added in Twig 1.2. + +You can also provide a list of templates that are checked for existence. The +first template that exists will be used as a parent: + +.. code-block:: jinja + + {% extends ['layout.html', 'base_layout.html'] %} + +Conditional Inheritance +----------------------- + +As the template name for the parent can be any valid Twig expression, it's +possible to make the inheritance mechanism conditional: + +.. code-block:: jinja + + {% extends standalone ? "minimum.html" : "base.html" %} + +In this example, the template will extend the "minimum.html" layout template +if the ``standalone`` variable evaluates to ``true``, and "base.html" +otherwise. + +.. seealso:: :doc:`block<../functions/block>`, :doc:`block<../tags/block>`, :doc:`parent<../functions/parent>`, :doc:`use<../tags/use>` diff --git a/doc/tags/filter.rst b/doc/tags/filter.rst new file mode 100644 index 0000000..82ca5c6 --- /dev/null +++ b/doc/tags/filter.rst @@ -0,0 +1,21 @@ +``filter`` +========== + +Filter sections allow you to apply regular Twig filters on a block of template +data. Just wrap the code in the special ``filter`` section: + +.. code-block:: jinja + + {% filter upper %} + This text becomes uppercase + {% endfilter %} + +You can also chain filters: + +.. code-block:: jinja + + {% filter lower|escape %} + SOME TEXT + {% endfilter %} + + {# outputs "<strong>some text</strong>" #} diff --git a/doc/tags/for.rst b/doc/tags/for.rst new file mode 100644 index 0000000..bbd5caf --- /dev/null +++ b/doc/tags/for.rst @@ -0,0 +1,126 @@ +``for`` +======= + +Loop over each item in a sequence. For example, to display a list of users +provided in a variable called ``users``: + +.. code-block:: jinja + +

    Members

    +
      + {% for user in users %} +
    • {{ user.username|e }}
    • + {% endfor %} +
    + +.. note:: + + A sequence can be either an array or an object implementing the + ``Traversable`` interface. + +If you do need to iterate over a sequence of numbers, you can use the ``..`` +operator: + +.. code-block:: jinja + + {% for i in 0..10 %} + * {{ i }} + {% endfor %} + +The above snippet of code would print all numbers from 0 to 10. + +It can be also useful with letters: + +.. code-block:: jinja + + {% for letter in 'a'..'z' %} + * {{ letter }} + {% endfor %} + +The ``..`` operator can take any expression at both sides: + +.. code-block:: jinja + + {% for letter in 'a'|upper..'z'|upper %} + * {{ letter }} + {% endfor %} + +.. tip: + + If you need a step different from 1, you can use the ``range`` function + instead. + +Inside of a ``for`` loop block you can access some special variables: + +===================== ============================================================= +Variable Description +===================== ============================================================= +``loop.index`` The current iteration of the loop. (1 indexed) +``loop.index0`` The current iteration of the loop. (0 indexed) +``loop.revindex`` The number of iterations from the end of the loop (1 indexed) +``loop.revindex0`` The number of iterations from the end of the loop (0 indexed) +``loop.first`` True if first iteration +``loop.last`` True if last iteration +``loop.length`` The number of items in the sequence +``loop.parent`` The parent context +===================== ============================================================= + +.. note:: + + The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and + ``loop.last`` variables are only available for PHP arrays, or objects that + implement the ``Countable`` interface. + +.. versionadded:: 1.2 + The ``if`` modifier support has been added in Twig 1.2. + +Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You +can however filter the sequence during iteration which allows you to skip +items. The following example skips all the users which are not active: + +.. code-block:: jinja + +
      + {% for user in users if user.active %} +
    • {{ user.username|e }}
    • + {% endfor %} +
    + +The advantage is that the special loop variable will count correctly thus not +counting the users not iterated over. + +If no iteration took place because the sequence was empty, you can render a +replacement block by using ``else``: + +.. code-block:: jinja + +
      + {% for user in users %} +
    • {{ user.username|e }}
    • + {% else %} +
    • no user found
    • + {% endfor %} +
    + +By default, a loop iterates over the values of the sequence. You can iterate +on keys by using the ``keys`` filter: + +.. code-block:: jinja + +

    Members

    +
      + {% for key in users|keys %} +
    • {{ key }}
    • + {% endfor %} +
    + +You can also access both keys and values: + +.. code-block:: jinja + +

    Members

    +
      + {% for key, user in users %} +
    • {{ key }}: {{ user.username|e }}
    • + {% endfor %} +
    diff --git a/doc/tags/from.rst b/doc/tags/from.rst new file mode 100644 index 0000000..5337a23 --- /dev/null +++ b/doc/tags/from.rst @@ -0,0 +1,8 @@ +``from`` +======== + +The ``from`` tags import :doc:`macro<../tags/macro>` names into the current +namespace. The tag is documented in detail in the documentation for the +:doc:`import<../tags/import>` tag. + +.. seealso:: :doc:`macro<../tags/macro>`, :doc:`import<../tags/import>` diff --git a/doc/tags/if.rst b/doc/tags/if.rst new file mode 100644 index 0000000..9540fa5 --- /dev/null +++ b/doc/tags/if.rst @@ -0,0 +1,33 @@ +``if`` +====== + +The ``if`` statement in Twig is comparable with the if statements of PHP. In +the simplest form you can use it to test if a variable is not empty: + +.. code-block:: jinja + + {% if users %} +
      + {% for user in users %} +
    • {{ user.username|e }}
    • + {% endfor %} +
    + {% endif %} + +.. note:: + + If you want to test if the variable is defined, use ``if users is + defined`` instead. + +For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use +more complex ``expressions`` there too: + +.. code-block:: jinja + + {% if kenny.sick %} + Kenny is sick. + {% elseif kenny.dead %} + You killed Kenny! You bastard!!! + {% else %} + Kenny looks okay --- so far + {% endif %} diff --git a/doc/tags/import.rst b/doc/tags/import.rst new file mode 100644 index 0000000..e967dd4 --- /dev/null +++ b/doc/tags/import.rst @@ -0,0 +1,79 @@ +``import`` +========== + +Twig supports putting often used code into :doc:`macros<../tags/macro>`. These +macros can go into different templates and get imported from there. + +There are two ways to import templates. You can import the complete template +into a variable or request specific macros from it. + +Imagine we have a helper module that renders forms (called ``forms.html``): + +.. code-block:: jinja + + {% macro input(name, value, type, size) %} + + {% endmacro %} + + {% macro textarea(name, value, rows) %} + + {% endmacro %} + +The easiest and most flexible is importing the whole module into a variable. +That way you can access the attributes: + +.. code-block:: jinja + + {% import 'forms.html' as forms %} + +
    +
    Username
    +
    {{ forms.input('username') }}
    +
    Password
    +
    {{ forms.input('password', none, 'password') }}
    +
    +

    {{ forms.textarea('comment') }}

    + +Alternatively you can import names from the template into the current +namespace: + +.. code-block:: jinja + + {% from 'forms.html' import input as input_field, textarea %} + +
    +
    Username
    +
    {{ input_field('username') }}
    +
    Password
    +
    {{ input_field('password', type='password') }}
    +
    +

    {{ textarea('comment') }}

    + +Importing is not needed if the macros and the template are defined in the same +file; use the special ``_self`` variable instead: + +.. code-block:: jinja + + {# index.html template #} + + {% macro textarea(name, value, rows) %} + + {% endmacro %} + +

    {{ _self.textarea('comment') }}

    + +But you can still create an alias by importing from the ``_self`` variable: + +.. code-block:: jinja + + {# index.html template #} + + {% macro textarea(name, value, rows) %} + + {% endmacro %} + + {% import _self as forms %} + +

    {{ forms.textarea('comment') }}

    + +.. seealso:: :doc:`macro<../tags/macro>`, :doc:`from<../tags/from>` diff --git a/doc/tags/include.rst b/doc/tags/include.rst new file mode 100644 index 0000000..1d1c06f --- /dev/null +++ b/doc/tags/include.rst @@ -0,0 +1,83 @@ +``include`` +=========== + +The ``include`` statement includes a template and return the rendered content +of that file into the current namespace: + +.. code-block:: jinja + + {% include 'header.html' %} + Body + {% include 'footer.html' %} + +Included templates have access to the variables of the active context. + +You can add additional variables by passing them after the ``with`` keyword: + +.. code-block:: jinja + + {# the foo template will have access to the variables from the current context and the foo one #} + {% include 'foo' with {'foo': 'bar'} %} + + {% set vars = {'foo': 'bar'} %} + {% include 'foo' with vars %} + +You can disable access to the context by appending the ``only`` keyword: + +.. code-block:: jinja + + {# only the foo variable will be accessible #} + {% include 'foo' with {'foo': 'bar'} only %} + +.. code-block:: jinja + + {# no variable will be accessible #} + {% include 'foo' only %} + +.. tip:: + + When including a template created by an end user, you should consider + sandboxing it. More information in the :doc:`Twig for Developers<../api>` + chapter. + +The template name can be any valid Twig expression: + +.. code-block:: jinja + + {% include some_var %} + {% include ajax ? 'ajax.html' : 'not_ajax.html' %} + +And if the expression evaluates to a ``Twig_Template`` object, Twig will use it +directly:: + + // {% include template %} + + $template = $twig->loadTemplate('some_template.twig'); + + $twig->loadTemplate('template.twig')->display(array('template' => $template)); + +.. versionadded:: 1.2 + The ``ignore missing`` feature has been added in Twig 1.2. + +You can mark an include with ``ignore missing`` in which case Twig will ignore +the statement if the template to be ignored does not exist. It has to be +placed just after the template name. Here some valid examples: + +.. code-block:: jinja + + {% include "sidebar.html" ignore missing %} + {% include "sidebar.html" ignore missing with {'foo': 'bar} %} + {% include "sidebar.html" ignore missing only %} + +.. versionadded:: 1.2 + The possibility to pass an array of templates has been added in Twig 1.2. + +You can also provide a list of templates that are checked for existence before +inclusion. The first template that exists will be included: + +.. code-block:: jinja + + {% include ['page_detailed.html', 'page.html'] %} + +If ``ignore missing`` is given, it will fall back to rendering nothing if none +of the templates exist, otherwise it will throw an exception. diff --git a/doc/tags/index.rst b/doc/tags/index.rst new file mode 100644 index 0000000..df14182 --- /dev/null +++ b/doc/tags/index.rst @@ -0,0 +1,20 @@ +Tags +==== + +.. toctree:: + :maxdepth: 1 + + for + if + macro + filter + set + extends + block + include + import + from + use + spaceless + autoescape + raw diff --git a/doc/tags/macro.rst b/doc/tags/macro.rst new file mode 100644 index 0000000..01bf625 --- /dev/null +++ b/doc/tags/macro.rst @@ -0,0 +1,91 @@ +``macro`` +========= + +Macros are comparable with functions in regular programming languages. They +are useful to put often used HTML idioms into reusable elements to not repeat +yourself. + +Here is a small example of a macro that renders a form element: + +.. code-block:: jinja + + {% macro input(name, value, type, size) %} + + {% endmacro %} + +Macros differs from native PHP functions in a few ways: + +* Default argument values are defined by using the ``default`` filter in the + macro body; + +* Arguments of a macro are always optional. + +But as PHP functions, macros don't have access to the current template +variables. + +.. tip:: + + You can pass the whole context as an argument by using the special + ``_context`` variable. + +Macros can be defined in any template, and need to be "imported" before being +used (see the documentation for the :doc:`import<../tags/import>` tag for more +information): + +.. code-block:: jinja + + {% import "forms.html" as forms %} + +The above ``import`` call imports the "forms.html" file (which can contain only +macros, or a template and some macros), and import the functions as items of +the ``forms`` variable. + +The macro can then be called at will: + +.. code-block:: jinja + +

    {{ forms.input('username') }}

    +

    {{ forms.input('password', none, 'password') }}

    + +If macros are defined and used in the same template, you can use the +special ``_self`` variable, without importing them: + +.. code-block:: jinja + +

    {{ _self.input('username') }}

    + +When you want to use a macro in another one from the same file, use the ``_self`` +variable: + +.. code-block:: jinja + + {% macro input(name, value, type, size) %} + + {% endmacro %} + + {% macro wrapped_input(name, value, type, size) %} +
    + {{ _self.input(name, value, type, size) }} +
    + {% endmacro %} + +When the macro is defined in another file, you need to import it: + +.. code-block:: jinja + + {# forms.html #} + + {% macro input(name, value, type, size) %} + + {% endmacro %} + + {# shortcuts.html #} + + {% macro wrapped_input(name, value, type, size) %} + {% import "forms.html" as forms %} +
    + {{ forms.input(name, value, type, size) }} +
    + {% endmacro %} + +.. seealso:: :doc:`from<../tags/from>`, :doc:`import<../tags/import>` diff --git a/doc/tags/raw.rst b/doc/tags/raw.rst new file mode 100644 index 0000000..4136c70 --- /dev/null +++ b/doc/tags/raw.rst @@ -0,0 +1,16 @@ +``raw`` +======= + +The ``raw`` tag marks sections as being raw text that should not be parsed. +For example to put Twig syntax as example into a template you can use this +snippet: + +.. code-block:: jinja + + {% raw %} +
      + {% for item in seq %} +
    • {{ item }}
    • + {% endfor %} +
    + {% endraw %} diff --git a/doc/tags/set.rst b/doc/tags/set.rst new file mode 100644 index 0000000..15090e7 --- /dev/null +++ b/doc/tags/set.rst @@ -0,0 +1,32 @@ +``set`` +======= + +Inside code blocks you can also assign values to variables. Assignments use +the ``set`` tag and can have multiple targets: + +.. code-block:: jinja + + {% set foo = 'foo' %} + + {% set foo = [1, 2] %} + + {% set foo = {'foo': 'bar'} %} + + {% set foo = 'foo' ~ 'bar' %} + + {% set foo, bar = 'foo', 'bar' %} + +The ``set`` tag can also be used to 'capture' chunks of text: + +.. code-block:: jinja + + {% set foo %} + + {% endset %} + +.. caution:: + + If you enable automatic output escaping, Twig will only consider the + content to be safe when capturing chunks of text. diff --git a/doc/tags/spaceless.rst b/doc/tags/spaceless.rst new file mode 100644 index 0000000..9a7c9bf --- /dev/null +++ b/doc/tags/spaceless.rst @@ -0,0 +1,14 @@ +``spaceless`` +============= + +Use the ``spaceless`` tag to remove whitespace *between HTML tags*: + +.. code-block:: jinja + + {% spaceless %} +
    + foo +
    + {% endspaceless %} + + {# output will be
    foo
    #} diff --git a/doc/tags/use.rst b/doc/tags/use.rst new file mode 100644 index 0000000..085f916 --- /dev/null +++ b/doc/tags/use.rst @@ -0,0 +1,123 @@ +``use`` +======= + +.. versionadded:: 1.1 + Horizontal reuse was added in Twig 1.1. + +.. note:: + + Horizontal reuse is an advanced Twig feature that is hardly ever needed in + regular templates. It is mainly used by projects that need to make + template blocks reusable without using inheritance. + +Template inheritance is one of the most powerful Twig's feature but it is +limited to single inheritance; a template can only extend one other template. +This limitation makes template inheritance simple to understand and easy to +debug: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% block title %}{% endblock %} + {% block content %}{% endblock %} + +Horizontal reuse is a way to achieve the same goal as multiple inheritance, +but without the associated complexity: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% use "blocks.html" %} + + {% block title %}{% endblock %} + {% block content %}{% endblock %} + +The ``use`` statement tells Twig to import the blocks defined in +```blocks.html`` into the current template (it's like macros, but for blocks): + +.. code-block:: jinja + + # blocks.html + {% block sidebar %}{% endblock %} + +In this example, the ``use`` statement imports the ``sidebar`` block into the +main template. The code is mostly equivalent to the following one (the +imported blocks are not outputted automatically): + +.. code-block:: jinja + + {% extends "base.html" %} + + {% block sidebar %}{% endblock %} + {% block title %}{% endblock %} + {% block content %}{% endblock %} + +.. note:: + + The ``use`` tag only imports a template if it does not extend another + template, if it does not define macros, and if the body is empty. But it + can *use* other templates. + +.. note:: + + Because ``use`` statements are resolved independently of the context + passed to the template, the template reference cannot be an expression. + +The main template can also override any imported block. If the template +already defines the ``sidebar`` block, then the one defined in ``blocks.html`` +is ignored. To avoid name conflicts, you can rename imported blocks: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% use "blocks.html" with sidebar as base_sidebar %} + + {% block sidebar %}{% endblock %} + {% block title %}{% endblock %} + {% block content %}{% endblock %} + +.. versionadded:: 1.3 + The ``parent()`` support was added in Twig 1.3. + +The ``parent()`` function automatically determines the correct inheritance +tree, so it can be used when overriding a block defined in an imported +template: + +.. code-block:: jinja + + {% extends "base.html" %} + + {% use "blocks.html" %} + + {% block sidebar %} + {{ parent() }} + {% endblock %} + + {% block title %}{% endblock %} + {% block content %}{% endblock %} + +In this example, ``parent()`` will correctly call the ``sidebar`` block from +the ``blocks.html`` template. + +.. tip:: + + In Twig 1.2, renaming allows you to simulate inheritance by calling the + "parent" block: + + .. code-block:: jinja + + {% extends "base.html" %} + + {% use "blocks.html" with sidebar as parent_sidebar %} + + {% block sidebar %} + {{ block('parent_sidebar') }} + {% endblock %} + +.. note:: + + You can use as many ``use`` statements as you want in any given template. + If two imported templates define the same block, the latest one wins. diff --git a/doc/templates.rst b/doc/templates.rst index f8a2b50..f8386ec 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -12,29 +12,29 @@ XML, CSV, LaTeX, etc.). It doesn't have a specific extension, ``.html`` or ``.xml`` are just fine. A template contains **variables** or **expressions**, which get replaced with -values when the template is evaluated, and tags, which control the logic of -the template. +values when the template is evaluated, and **tags**, which control the logic +of the template. Below is a minimal template that illustrates a few basics. We will cover the -details later in that document: - -.. code-block:: jinja - - - - - My Webpage - - - - -

    My Webpage

    - {{ a_variable }} - +details later on: + +.. code-block:: html+jinja + + + + + My Webpage + + + + +

    My Webpage

    + {{ a_variable }} + There are two kinds of delimiters: ``{% ... %}`` and ``{{ ... }}``. The first @@ -59,12 +59,12 @@ Variables The application passes variables to the templates you can mess around in the template. Variables may have attributes or elements on them you can access -too. How a variable looks like, heavily depends on the application providing +too. How a variable looks like heavily depends on the application providing those. -You can use a dot (``.``) to access attributes of a variable, alternative the -so-called "subscript" syntax (``[]``) can be used. The following lines do the -same: +You can use a dot (``.``) to access attributes of a variable (methods or +properties of a PHP object, or items of a PHP array), or the so-called +"subscript" syntax (``[]``): .. code-block:: jinja @@ -77,46 +77,52 @@ same: variable but the print statement. If you access variables inside tags don't put the braces around. -If a variable or attribute does not exist you will get back a ``null`` value -(which can be tested with the ``none`` expression). +If a variable or attribute does not exist you will get back a ``null`` value. .. sidebar:: Implementation - For convenience sake ``foo.bar`` does the following things on the PHP - layer: - - * check if ``foo`` is an array and ``bar`` a valid element; - * if not, and if ``foo`` is an object, check that ``bar`` is a valid property; - * if not, and if ``foo`` is an object, check that ``bar`` is a valid method - (even if ``bar`` is the constructor - use ``__construct()`` instead); - * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method; - * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method; - * if not, return a ``null`` value. - - ``foo['bar']`` on the other hand works mostly the same with the a small - difference in the order: + For convenience sake ``foo.bar`` does the following things on the PHP + layer: - * check if ``foo`` is an array and ``bar`` a valid element; - * if not, return a ``null`` value. + * check if ``foo`` is an array and ``bar`` a valid element; + * if not, and if ``foo`` is an object, check that ``bar`` is a valid property; + * if not, and if ``foo`` is an object, check that ``bar`` is a valid method + (even if ``bar`` is the constructor - use ``__construct()`` instead); + * if not, and if ``foo`` is an object, check that ``getBar`` is a valid method; + * if not, and if ``foo`` is an object, check that ``isBar`` is a valid method; + * if not, return a ``null`` value. - Using the alternative syntax is also useful to dynamically get attributes - from arrays: + ``foo['bar']`` on the other hand only works with PHP arrays: - .. code-block:: jinja - - foo[bar] + * check if ``foo`` is an array and ``bar`` a valid element; + * if not, return a ``null`` value. .. note:: If you want to get a dynamic attribute on a variable, use the - ``attribute`` function instead. + :doc:`attribute` function instead. + +Global Variables +~~~~~~~~~~~~~~~~ -Twig always references the following variables: +The following variables are always available in templates: * ``_self``: references the current template; * ``_context``: references the current context; * ``_charset``: references the current charset. +Setting Variables +~~~~~~~~~~~~~~~~~ + +You can assign values to variables inside code blocks. Assignments use the +:doc:`set` tag: + +.. code-block:: jinja + + {% set foo = 'foo' %} + {% set foo = [1, 2] %} + {% set foo = {'foo': 'bar'} %} + Filters ------- @@ -125,103 +131,131 @@ variable by a pipe symbol (``|``) and may have optional arguments in parentheses. Multiple filters can be chained. The output of one filter is applied to the next. -``{{ name|striptags|title }}`` for example will remove all HTML tags from the -``name`` and title-cases it. Filters that accept arguments have parentheses -around the arguments, like a function call. This example will join a list by -commas: ``{{ list|join(', ') }}``. +The following example removes all HTML tags from the ``name`` and title-cases +it: -The built-in filters section below describes all the built-in filters. +.. code-block:: jinja -Comments --------- + {{ name|striptags|title }} -To comment-out part of a line in a template, use the comment syntax ``{# ... -#}``. This is useful to comment out parts of the template for debugging or to -add information for other template designers or yourself: +Filters that accept arguments have parentheses around the arguments. This +example will join a list by commas: .. code-block:: jinja - {# note: disabled template because we no longer use this - {% for user in users %} - ... - {% endfor %} - #} + {{ list|join(', ') }} -Whitespace Control ------------------- +To apply a filter on a section of code, wrap it with the +:doc:`filter` tag: -.. versionadded:: 1.1 - Tag level whitespace control was added in Twig 1.1. +.. code-block:: jinja -The first newline after a template tag is removed automatically (like in PHP.) -Whitespace is not further modified by the template engine, so each whitespace -(spaces, tabs, newlines etc.) is returned unchanged. + {% filter upper %} + This text becomes uppercase + {% endfilter %} + +Go to the :doc:`filters` page to learn more about the built-in +filters. -Use the ``spaceless`` tag to remove whitespace between HTML tags: +Functions +--------- + +Functions can be called to generate content. Functions are called by their +name followed by parentheses (``()``) and may have arguments. + +For instance, the ``range`` function returns a list containing an arithmetic +progression of integers: .. code-block:: jinja - {% spaceless %} -
    - foo -
    - {% endspaceless %} + {% for i in range(0, 3) %} + {{ i }}, + {% endfor %} - {# output will be
    foo
    #} +Go to the :doc:`functions` page to learn more about the +built-in functions. -In addition to the spaceless tag you can also control whitespace on a per tag -level. By using the whitespace control modifier on your tags you can trim -leading and or trailing whitespace from any tag type: +Control Structure +----------------- -.. code-block:: jinja +A control structure refers to all those things that control the flow of a +program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as +well as things like blocks. Control structures appear inside ``{% ... %}`` +blocks. - {% set value = 'no spaces' %} - {#- No leading/trailing whitespace -#} - {%- if true -%} - {{- value -}} - {%- endif -%} +For example, to display a list of users provided in a variable called +``users``, use the :doc:`for` tag: - {# output 'no spaces' #} +.. code-block:: jinja -The above sample shows the default whitespace control modifier, and how you can -use it to remove whitespace around tags. Trimming space will consume all whitespace -for that side of the tag. It is possible to use whitespace trimming on one side -of a tag: +

    Members

    +
      + {% for user in users %} +
    • {{ user.username|e }}
    • + {% endfor %} +
    + +The :doc:`if` tag can be used to test an expression: .. code-block:: jinja - {% set value = 'no spaces' %} -
  • {{- value }}
  • + {% if users|length > 0 %} +
      + {% for user in users %} +
    • {{ user.username|e }}
    • + {% endfor %} +
    + {% endif %} - {# outputs '
  • no spaces
  • ' #} +Go to the :doc:`tags` page to learn more about the built-in tags. -Escaping +Comments -------- -It is sometimes desirable or even necessary to have Twig ignore parts it would -otherwise handle as variables or blocks. For example if the default syntax is -used and you want to use ``{{`` as raw string in the template and not start a -variable you have to use a trick. +To comment-out part of a line in a template, use the comment syntax ``{# ... +#}``. This is useful for debugging or to add information for other template +designers or yourself: -The easiest way is to output the variable delimiter (``{{``) by using a variable -expression: +.. code-block:: jinja + + {# note: disabled template because we no longer use this + {% for user in users %} + ... + {% endfor %} + #} + +Including other Templates +------------------------- + +The :doc:`include` tag is useful to include a template and +return the rendered content of that template into the current one: .. code-block:: jinja - {{ '{{' }} + {% include 'sidebar.html' %} + +Per default included templates are passed the current context. + +The context that is passed to the included template includes variables defined +in the template: + +.. code-block:: jinja + + {% for box in boxes %} + {% include "render_box.html" %} + {% endfor %} + +The included template ``render_box.html`` is able to access ``box``. -For bigger sections it makes sense to mark a block ``raw``. For example to put -Twig syntax as example into a template you can use this snippet: +The filename of the template depends on the template loader. For instance, the +``Twig_Loader_Filesystem`` allows you to access other templates by giving the +filename. You can access templates in subdirectories with a slash: .. code-block:: jinja - {% raw %} -
      - {% for item in seq %} -
    • {{ item }}
    • - {% endfor %} -
    - {% endraw %} + {% include "sections/articles/sidebar.html" %} + +This behavior depends on the application embedding Twig. Template Inheritance -------------------- @@ -234,39 +268,33 @@ override. Sounds complicated but is very basic. It's easiest to understand it by starting with an example. -Base Template -~~~~~~~~~~~~~ - -This template, which we'll call ``base.html``, defines a simple HTML skeleton -document that you might use for a simple two-column page. It's the job of -"child" templates to fill the empty blocks with content: - -.. code-block:: jinja - - - - - {% block head %} - - {% block title %}{% endblock %} - My Webpage - {% endblock %} - - -
    {% block content %}{% endblock %}
    - - +Let's define a base template, ``base.html``, which defines a simple HTML +skeleton document that you might use for a simple two-column page: + +.. code-block:: html+jinja + + + + + {% block head %} + + {% block title %}{% endblock %} - My Webpage + {% endblock %} + + +
    {% block content %}{% endblock %}
    + + -In this example, the ``{% block %}`` tags define four blocks that child -templates can fill in. All the ``block`` tag does is to tell the template -engine that a child template may override those portions of the template. - -Child Template -~~~~~~~~~~~~~~ +In this example, the :doc:`{% block %}` tags define four blocks +that child templates can fill in. All the ``block`` tag does is to tell the +template engine that a child template may override those portions of the +template. A child template might look like this: @@ -276,170 +304,43 @@ A child template might look like this: {% block title %}Index{% endblock %} {% block head %} - {{ parent() }} - + {{ parent() }} + {% endblock %} {% block content %} -

    Index

    -

    - Welcome on my awesome homepage. -

    +

    Index

    +

    + Welcome on my awesome homepage. +

    {% endblock %} -The ``{% extends %}`` tag is the key here. It tells the template engine that -this template "extends" another template. When the template system evaluates -this template, first it locates the parent. The extends tag should be the -first tag in the template. - -The filename of the template depends on the template loader. For example the -``Twig_Loader_Filesystem`` allows you to access other templates by giving the -filename. You can access templates in subdirectories with a slash: - -.. code-block:: jinja - - {% extends "layout/default.html" %} - -But this behavior can depend on the application embedding Twig. Note that -since the child template doesn't define the ``footer`` block, the value from -the parent template is used instead. - -You can't define multiple ``{% block %}`` tags with the same name in the same -template. This limitation exists because a block tag works in "both" -directions. That is, a block tag doesn't just provide a hole to fill - it also -defines the content that fills the hole in the *parent*. If there were two -similarly-named ``{% block %}`` tags in a template, that template's parent -wouldn't know which one of the blocks' content to use. Block names should -consist of alphanumeric characters, and underscores. Dashes are not permitted. - -If you want to print a block multiple times you can however use the -``block`` function: - -.. code-block:: jinja - - {% block title %}{% endblock %} -

    {{ block('title') }}

    - {% block body %}{% endblock %} - -Like PHP, Twig does not support multiple inheritance. So you can only have one -extends tag called per rendering. - -Parent Blocks -~~~~~~~~~~~~~ - -It's possible to render the contents of the parent block by using the ``parent`` -function. This gives back the results of the parent block: - -.. code-block:: jinja - - {% block sidebar %} -

    Table Of Contents

    - ... - {{ parent() }} - {% endblock %} +The :doc:`{% extends %}` tag is the key here. It tells the +template engine that this template "extends" another template. When the +template system evaluates this template, first it locates the parent. The +extends tag should be the first tag in the template. -Named Block End-Tags -~~~~~~~~~~~~~~~~~~~~ +Note that since the child template doesn't define the ``footer`` block, the +value from the parent template is used instead. -Twig allows you to put the name of the block after the end tag for better -readability: +It's possible to render the contents of the parent block by using the +:doc:`parent` function. This gives back the results of the +parent block: .. code-block:: jinja {% block sidebar %} - {% block inner_sidebar %} - ... - {% endblock inner_sidebar %} - {% endblock sidebar %} - -However the name after the ``endblock`` word must match the block name. - -Block Nesting and Scope -~~~~~~~~~~~~~~~~~~~~~~~ - -Blocks can be nested for more complex layouts. Per default, blocks have access -to variables from outer scopes: - -.. code-block:: jinja - - {% for item in seq %} -
  • {% block loop_item %}{{ item }}{% endblock %}
  • - {% endfor %} - -Block Shortcuts -~~~~~~~~~~~~~~~ - -For blocks with few content, it's possible to have a shortcut syntax. The -following constructs do the same: - -.. code-block:: jinja - - {% block title %} - {{ page_title|title }} +

    Table Of Contents

    + ... + {{ parent() }} {% endblock %} -.. code-block:: jinja - - {% block title page_title|title %} - -Dynamic Inheritance -~~~~~~~~~~~~~~~~~~~ - -Twig supports dynamic inheritance by using a variable as the base template: - -.. code-block:: jinja - - {% extends some_var %} - -If the variable evaluates to a ``Twig_Template`` object, Twig will use it as -the parent template:: - - // {% extends layout %} - - $layout = $twig->loadTemplate('some_layout_template.twig'); - - $twig->display('template.twig', array('layout' => $layout)); - -.. versionadded:: 1.2 - The possibility to pass an array of templates has been added in Twig 1.2. - -You can also provide a list of templates that are checked for existence. The -first template that exists will be used as a parent: - -.. code-block:: jinja - - {% extends ['layout.html', 'base_layout.html'] %} - -Conditional Inheritance -~~~~~~~~~~~~~~~~~~~~~~~ - -As a matter of fact, the template name can be any valid expression. So, it's -also possible to make the inheritance mechanism conditional: - -.. code-block:: jinja - - {% extends standalone ? "minimum.html" : "base.html" %} - -In this example, the template will extend the "minimum.html" layout template -if the ``standalone`` variable evaluates to ``true``, and "base.html" -otherwise. - -Import Context Behavior ------------------------ - -Per default included templates are passed the current context. - -The context that is passed to the included template includes variables defined -in the template: - -.. code-block:: jinja - - {% for box in boxes %} - {% include "render_box.html" %} - {% endfor %} +.. tip:: -The included template ``render_box.html`` is able to access ``box``. + The documentation page for the :doc:`extends` tag describes + more advanced features like block nesting, scope, dynamic inheritance, and + conditional inheritance. HTML Escaping ------------- @@ -461,558 +362,109 @@ Working with Manual Escaping If manual escaping is enabled it's **your** responsibility to escape variables if needed. What to escape? If you have a variable that *may* include any of -the following chars (``>``, ``<``, ``&``, or ``"``) you **have to** escape it unless -the variable contains well-formed and trusted HTML. Escaping works by piping -the variable through the ``|e`` filter: ``{{ user.username|e }}``. +the following chars (``>``, ``<``, ``&``, or ``"``) you **have to** escape it +unless the variable contains well-formed and trusted HTML. Escaping works by +piping the variable through the :doc:`escape` or ``e`` filter: + +.. code-block:: jinja + + {{ user.username|e }} + {{ user.username|e('js') }} Working with Automatic Escaping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whether automatic escaping is enabled or not, you can mark a section of a -template to be escaped or not by using the ``autoescape`` tag: +template to be escaped or not by using the :doc:`autoescape` +tag: .. code-block:: jinja {% autoescape true %} - Everything will be automatically escaped in this block + Everything will be automatically escaped in this block {% endautoescape %} - {% autoescape false %} - Everything will be outputed as is in this block - {% endautoescape %} - - {% autoescape true js %} - Everything will be automatically escaped in this block - using the js escaping strategy - {% endautoescape %} - -When automatic escaping is enabled everything is escaped by default except for -values explicitly marked as safe. Those can be marked in the template by using -the ``|raw`` filter. - -Functions returning template data (like macros and ``parent``) always return -safe markup. +Escaping +-------- -.. note:: +It is sometimes desirable or even necessary to have Twig ignore parts it would +otherwise handle as variables or blocks. For example if the default syntax is +used and you want to use ``{{`` as raw string in the template and not start a +variable you have to use a trick. - Twig is smart enough to not escape an already escaped value by the - ``escape`` filter. +The easiest way is to output the variable delimiter (``{{``) by using a variable +expression: -.. note:: +.. code-block:: jinja - The chapter for developers give more information about when and how - automatic escaping is applied. + {{ '{{' }} -List of Control Structures --------------------------- +For bigger sections it makes sense to mark a block :doc:`raw`. -A control structure refers to all those things that control the flow of a -program - conditionals (i.e. ``if``/``elseif``/``else``), ``for``-loops, as well as -things like blocks. Control structures appear inside ``{% ... %}`` blocks. +Macros +------ -For -~~~ +Macros are comparable with functions in regular programming languages. They +are useful to put often used HTML idioms into reusable elements to not repeat +yourself. -Loop over each item in a sequence. For example, to display a list of users -provided in a variable called ``users``: +A macro is defined via the :doc:`macro` tag. Here is a small +example of a macro that renders a form element: .. code-block:: jinja -

    Members

    -
      - {% for user in users %} -
    • {{ user.username|e }}
    • - {% endfor %} -
    - -.. note:: - - A sequence can be either an array or an object implementing the - ``Traversable`` interface. + {% macro input(name, value, type, size) %} + + {% endmacro %} -If you do need to iterate over a sequence of numbers, you can use the ``..`` -operator: +Macros can be defined in any template, and need to be "imported" before being +used via the :doc:`import` tag: .. code-block:: jinja - {% for i in 0..10 %} - * {{ i }} - {% endfor %} - -The above snippet of code would print all numbers from 0 to 10. - -It can be also useful with letters: - -.. code-block:: jinja + {% import "forms.html" as forms %} - {% for letter in 'a'..'z' %} - * {{ letter }} - {% endfor %} +

    {{ forms.input('username') }}

    -The ``..`` operator can take any expression at both sides: +Alternatively you can import names from the template into the current +namespace via the :doc:`from` tag: .. code-block:: jinja - {% for letter in 'a'|upper..'z'|upper %} - * {{ letter }} - {% endfor %} - -.. tip: + {% from 'forms.html' import input as input_field, textarea %} - If you need a step different from 1, you can use the ``range`` function - instead. +
    +
    Username
    +
    {{ input_field('username') }}
    +
    Password
    +
    {{ input_field('password', type='password') }}
    +
    +

    {{ textarea('comment') }}

    -Inside of a ``for`` loop block you can access some special variables: +Expressions +----------- -===================== ============================================================= -Variable Description -===================== ============================================================= -``loop.index`` The current iteration of the loop. (1 indexed) -``loop.index0`` The current iteration of the loop. (0 indexed) -``loop.revindex`` The number of iterations from the end of the loop (1 indexed) -``loop.revindex0`` The number of iterations from the end of the loop (0 indexed) -``loop.first`` True if first iteration -``loop.last`` True if last iteration -``loop.length`` The number of items in the sequence -``loop.parent`` The parent context -===================== ============================================================= +Twig allows expressions everywhere. These work very similar to regular PHP and +even if you're not working with PHP you should feel comfortable with it. .. note:: - The ``loop.length``, ``loop.revindex``, ``loop.revindex0``, and - ``loop.last`` variables are only available for PHP arrays, or objects that - implement the ``Countable`` interface. + The operator precedence is as follows, with the lowest-precedence + operators listed first: ``or``, ``and``, ``==``, ``!=``, ``<``, ``>``, + ``>=``, ``<=``, ``in``, ``+``, ``-``, ``~``, ``*``, ``/``, ``%``, ``//``, + ``is``, ``..``, and ``**``. -.. versionadded:: 1.2 - The ``if`` modifier support has been added in Twig 1.2. +Literals +~~~~~~~~ -Unlike in PHP, it's not possible to ``break`` or ``continue`` in a loop. You -can however filter the sequence during iteration which allows you to skip -items. The following example skips all the users which are not active: +The simplest form of expressions are literals. Literals are representations +for PHP types such as strings, numbers, and arrays. The following literals +exist: -.. code-block:: jinja - -
      - {% for user in users if user.active %} -
    • {{ user.username|e }}
    • - {% endfor %} -
    - -The advantage is that the special loop variable will count correctly thus not -counting the users not iterated over. - -If no iteration took place because the sequence was empty, you can render a -replacement block by using ``else``: - -.. code-block:: jinja - -
      - {% for user in users %} -
    • {{ user.username|e }}
    • - {% else %} -
    • no user found
    • - {% endfor %} -
    - -By default, a loop iterates over the values of the sequence. You can iterate -on keys by using the ``keys`` filter: - -.. code-block:: jinja - -

    Members

    -
      - {% for key in users|keys %} -
    • {{ key }}
    • - {% endfor %} -
    - -You can also access both keys and values: - -.. code-block:: jinja - -

    Members

    -
      - {% for key, user in users %} -
    • {{ key }}: {{ user.username|e }}
    • - {% endfor %} -
    - -If -~~ - -The ``if`` statement in Twig is comparable with the if statements of PHP. In -the simplest form you can use it to test if a variable is not empty: - -.. code-block:: jinja - - {% if users %} -
      - {% for user in users %} -
    • {{ user.username|e }}
    • - {% endfor %} -
    - {% endif %} - -.. note:: - - If you want to test if the variable is defined, use ``if users is - defined`` instead. - -For multiple branches ``elseif`` and ``else`` can be used like in PHP. You can use -more complex ``expressions`` there too: - -.. code-block:: jinja - - {% if kenny.sick %} - Kenny is sick. - {% elseif kenny.dead %} - You killed Kenny! You bastard!!! - {% else %} - Kenny looks okay --- so far - {% endif %} - -Macros -~~~~~~ - -Macros are comparable with functions in regular programming languages. They -are useful to put often used HTML idioms into reusable elements to not repeat -yourself. - -Here is a small example of a macro that renders a form element: - -.. code-block:: jinja - - {% macro input(name, value, type, size) %} - - {% endmacro %} - -Macros differs from native PHP functions in a few ways: - -* Default argument values are defined by using the ``default`` filter in the - macro body; - -* Arguments of a macro are always optional. - -But as PHP functions, macros don't have access to the current template -variables. - -.. tip:: - - You can pass the whole context as an argument by using the special - ``_context`` variable. - -Macros can be defined in any template, and need to be "imported" before being -used (see the Import section for more information): - -.. code-block:: jinja - - {% import "forms.html" as forms %} - -The above ``import`` call imports the "forms.html" file (which can contain only -macros, or a template and some macros), and import the functions as items of -the ``forms`` variable. - -The macro can then be called at will: - -.. code-block:: jinja - -

    {{ forms.input('username') }}

    -

    {{ forms.input('password', none, 'password') }}

    - -If macros are defined and used in the same template, you can use the -special ``_self`` variable, without importing them: - -.. code-block:: jinja - -

    {{ _self.input('username') }}

    - -When you want to use a macro in another one from the same file, use the ``_self`` -variable: - -.. code-block:: jinja - - {% macro input(name, value, type, size) %} - - {% endmacro %} - - {% macro wrapped_input(name, value, type, size) %} -
    - {{ _self.input(name, value, type, size) }} -
    - {% endmacro %} - -When the macro is defined in another file, you need to import it: - -.. code-block:: jinja - - {# forms.html #} - - {% macro input(name, value, type, size) %} - - {% endmacro %} - - {# shortcuts.html #} - - {% macro wrapped_input(name, value, type, size) %} - {% import "forms.html" as forms %} -
    - {{ forms.input(name, value, type, size) }} -
    - {% endmacro %} - -Filters -~~~~~~~ - -Filter sections allow you to apply regular Twig filters on a block of template -data. Just wrap the code in the special ``filter`` section: - -.. code-block:: jinja - - {% filter upper %} - This text becomes uppercase - {% endfilter %} - -You can also chain filters: - -.. code-block:: jinja - - {% filter lower|escape %} - SOME TEXT - {% endfilter %} - -It should return ``<strong>some text</strong>``. - -Assignments -~~~~~~~~~~~ - -Inside code blocks you can also assign values to variables. Assignments use -the ``set`` tag and can have multiple targets: - -.. code-block:: jinja - - {% set foo = 'foo' %} - - {% set foo = [1, 2] %} - - {% set foo = {'foo': 'bar'} %} - - {% set foo = 'foo' ~ 'bar' %} - - {% set foo, bar = 'foo', 'bar' %} - -The ``set`` tag can also be used to 'capture' chunks of text: - -.. code-block:: jinja - - {% set foo %} - - {% endset %} - -.. caution:: - - If you enable automatic output escaping, Twig will only consider the - content to be safe when capturing chunks of text. - -Extends -~~~~~~~ - -The ``extends`` tag can be used to extend a template from another one. You can -have multiple of them in a file but only one of them may be executed at the -time. There is no support for multiple inheritance. See the section about -Template inheritance above for more information. - -Block -~~~~~ - -Blocks are used for inheritance and act as placeholders and replacements at -the same time. They are documented in detail as part of the section about -Template inheritance above. - -Include -~~~~~~~ - -The ``include`` statement is useful to include a template and return the -rendered content of that file into the current namespace: - -.. code-block:: jinja - - {% include 'header.html' %} - Body - {% include 'footer.html' %} - -Included templates have access to the variables of the active context. - -You can add additional variables by passing them after the ``with`` keyword: - -.. code-block:: jinja - - {# the foo template will have access to the variables from the current context and the foo one #} - {% include 'foo' with {'foo': 'bar'} %} - - {% set vars = {'foo': 'bar'} %} - {% include 'foo' with vars %} - -You can disable access to the context by appending the ``only`` keyword: - -.. code-block:: jinja - - {# only the foo variable will be accessible #} - {% include 'foo' with {'foo': 'bar'} only %} - -.. code-block:: jinja - - {# no variable will be accessible #} - {% include 'foo' only %} - -.. tip:: - - When including a template created by an end user, you should consider - sandboxing it. More information in the "Twig for Developers" chapter. - -The template name can be any valid Twig expression: - -.. code-block:: jinja - - {% include some_var %} - {% include ajax ? 'ajax.html' : 'not_ajax.html' %} - -And if the expression evaluates to a ``Twig_Template`` object, Twig will use it -directly:: - - // {% include template %} - - $template = $twig->loadTemplate('some_template.twig'); - - $twig->loadTemplate('template.twig')->display(array('template' => $template)); - -.. versionadded:: 1.2 - The ``ignore missing`` feature has been added in Twig 1.2. - -You can mark an include with ``ignore missing`` in which case Twig will ignore -the statement if the template to be ignored does not exist. It has to be -placed just after the template name. Here some valid examples: - -.. code-block:: jinja - - {% include "sidebar.html" ignore missing %} - {% include "sidebar.html" ignore missing with {'foo': 'bar} %} - {% include "sidebar.html" ignore missing only %} - -.. versionadded:: 1.2 - The possibility to pass an array of templates has been added in Twig 1.2. - -You can also provide a list of templates that are checked for existence before -inclusion. The first template that exists will be included: - -.. code-block:: jinja - - {% include ['page_detailed.html', 'page.html'] %} - -If ``ignore missing`` is given, it will fall back to rendering nothing if none -of the templates exist, otherwise it will throw an exception. - -Import -~~~~~~ - -Twig supports putting often used code into macros. These macros can go into -different templates and get imported from there. - -There are two ways to import templates. You can import the complete template -into a variable or request specific macros from it. - -Imagine we have a helper module that renders forms (called ``forms.html``): - -.. code-block:: jinja - - {% macro input(name, value, type, size) %} - - {% endmacro %} - - {% macro textarea(name, value, rows) %} - - {% endmacro %} - -The easiest and most flexible is importing the whole module into a variable. -That way you can access the attributes: - -.. code-block:: jinja - - {% import 'forms.html' as forms %} - -
    -
    Username
    -
    {{ forms.input('username') }}
    -
    Password
    -
    {{ forms.input('password', none, 'password') }}
    -
    -

    {{ forms.textarea('comment') }}

    - -Alternatively you can import names from the template into the current -namespace: - -.. code-block:: jinja - - {% from 'forms.html' import input as input_field, textarea %} - -
    -
    Username
    -
    {{ input_field('username') }}
    -
    Password
    -
    {{ input_field('password', type='password') }}
    -
    -

    {{ textarea('comment') }}

    - -Importing is not needed if the macros and the template are defined in the same -file; use the special ``_self`` variable instead: - -.. code-block:: jinja - - {# index.html template #} - - {% macro textarea(name, value, rows) %} - - {% endmacro %} - -

    {{ _self.textarea('comment') }}

    - -But you can still create an alias by importing from the ``_self`` variable: - -.. code-block:: jinja - - {# index.html template #} - - {% macro textarea(name, value, rows) %} - - {% endmacro %} - - {% import _self as forms %} - -

    {{ forms.textarea('comment') }}

    - -Expressions ------------ - -Twig allows basic expressions everywhere. These work very similar to regular -PHP and even if you're not working with PHP you should feel comfortable with -it. - -The operator precedence is as follows, with the lowest-precedence operators -listed first: ``or``, ``and``, ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``+``, ``-``, -``~``, ``*``, ``/``, ``%``, ``//``, ``is``, ``..``, and ``**``. - -Literals -~~~~~~~~ - -The simplest form of expressions are literals. Literals are representations -for PHP types such as strings, numbers, and arrays. The following literals -exist: - -* ``"Hello World"``: Everything between two double or single quotes is a - string. They are useful whenever you need a string in the template (for - example as arguments to function calls, filters or just to extend or - include a template). +* ``"Hello World"``: Everything between two double or single quotes is a + string. They are useful whenever you need a string in the template (for + example as arguments to function calls, filters or just to extend or + include a template). * ``42`` / ``42.23``: Integers and floating point numbers are created by just writing the number down. If a dot is present the number is a float, @@ -1067,8 +519,7 @@ but exists for completeness' sake. The following operators are supported: Logic ~~~~~ -For ``if`` statements, ``for`` filtering or ``if`` expressions it can be useful to -combine multiple expressions: +You can combine multiple expressions with the following operators: * ``and``: Returns true if the left and the right operands are both true. @@ -1113,8 +564,8 @@ To perform a negative test, use the ``not in`` operator: {# is equivalent to #} {% if not (1 in [1, 2, 3]) %} -Tests -~~~~~ +Test Operator +~~~~~~~~~~~~~ The ``is`` operator performs tests. Tests can be used to test a variable against a common expression. The right operand is name of the test: @@ -1140,16 +591,18 @@ Tests can be negated by using the ``not in`` operator: {# is equivalent to #} {% if not (loop.index is divisibleby(3)) %} -The built-in tests section below describes all the built-in tests. +Go to the :doc:`tests` page to learn more about the built-in +tests. Other Operators ~~~~~~~~~~~~~~~ The following operators are very useful but don't fit into any of the other -two categories: +categories: * ``..``: Creates a sequence based on the operand before and after the - operator (see the ``for`` tag for some usage examples). + operator (this is just syntactic sugar for the :doc:`range` + function). * ``|``: Applies a filter. @@ -1159,521 +612,69 @@ two categories: * ``.``, ``[]``: Gets an attribute of an object. -* ``?:``: Twig supports the PHP ternary operator: +* ``?:``: The PHP ternary operator: ``{{ foo ? 'yes' : 'no' }}`` - .. code-block:: jinja - - {{ foo ? 'yes' : 'no' }} - -List of built-in Filters ------------------------- - -``date`` -~~~~~~~~ +Whitespace Control +------------------ .. versionadded:: 1.1 - The timezone support has been added in Twig 1.1. + Tag level whitespace control was added in Twig 1.1. + +The first newline after a template tag is removed automatically (like in PHP.) +Whitespace is not further modified by the template engine, so each whitespace +(spaces, tabs, newlines etc.) is returned unchanged. -The ``date`` filter is able to format a date to a given format: +Use the ``spaceless`` tag to remove whitespace *between HTML tags*: .. code-block:: jinja - {{ post.published_at|date("m/d/Y") }} - -The ``date`` filter accepts any date format supported by `DateTime`_ and -``DateTime`` instances. For instance, to display the current date, filter the -word "now": - -.. code-block:: jinja - - {{ "now"|date("m/d/Y") }} - -To escape words and characters in the date format use ``\\`` in front of each character: - -.. code-block:: jinja - - {{ post.published_at|date("F jS \\a\\t g:ia") }} - -You can also specify a timezone: - - {{ post.published_at|date("m/d/Y", "Europe/Paris") }} - -``format`` -~~~~~~~~~~ - -The ``format`` filter formats a given string by replacing the placeholders -(placeholders follows the ``printf`` notation): - -.. code-block:: jinja - - {{ "I like %s and %s."|format(foo, "bar") }} - - {# returns I like foo and bar. (if the foo parameter equals to the foo string) #} - -``replace`` -~~~~~~~~~~~ - -The ``replace`` filter formats a given string by replacing the placeholders -(placeholders are free-form): - -.. code-block:: jinja - - {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }} - - {# returns I like foo and bar. (if the foo parameter equals to the foo string) #} - -``url_encode`` -~~~~~~~~~~~~~~ - -The ``url_encode`` filter URL encodes a given string. - -``json_encode`` -~~~~~~~~~~~~~~~ - -The ``json_encode`` filter returns the JSON representation of a string. - -``title`` -~~~~~~~~~ - -The ``title`` filter returns a titlecased version of the value. I.e. words will -start with uppercase letters, all remaining characters are lowercase. - -``capitalize`` -~~~~~~~~~~~~~~ - -The ``capitalize`` filter capitalizes a value. The first character will be -uppercase, all others lowercase. - -``upper`` -~~~~~~~~~ - -The ``upper`` filter converts a value to uppercase. - -``lower`` -~~~~~~~~~ - -The ``lower`` filter converts a value to lowercase. - -``striptags`` -~~~~~~~~~~~~~ - -The ``striptags`` filter strips SGML/XML tags and replace adjacent whitespace by -one space. - -``join`` -~~~~~~~~ - -The ``join`` filter returns a string which is the concatenation of the strings -in the sequence. The separator between elements is an empty string per -default, you can define it with the optional parameter: - -.. code-block:: jinja - - {{ [1, 2, 3]|join('|') }} - {# returns 1|2|3 #} - - {{ [1, 2, 3]|join }} - {# returns 123 #} - -``reverse`` -~~~~~~~~~~~ - -The ``reverse`` filter reverses an array or an object if it implements the -``Iterator`` interface. - -``length`` -~~~~~~~~~~ - -The ``length`` filters returns the number of items of a sequence or mapping, or -the length of a string. - -``sort`` -~~~~~~~~ - -The ``sort`` filter sorts an array. - -``default`` -~~~~~~~~~~~ - -The ``default`` filter returns the passed default value if the value is -undefined or empty, otherwise the value of the variable: - -.. code-block:: jinja - - {{ var|default('var is not defined') }} - - {{ var.foo|default('foo item on var is not defined') }} - - {{ ''|default('passed var is empty') }} - -.. note:: - - Read the documentation for the ``defined`` and ``empty`` tests below to - learn more about their semantics. - -``keys`` -~~~~~~~~ - -The ``keys`` filter returns the keys of an array. It is useful when you want to -iterate over the keys of an array: - -.. code-block:: jinja - - {% for key in array|keys %} - ... - {% endfor %} - -``escape``, ``e`` -~~~~~~~~~~~~~~~~~ - -The ``escape`` filter converts the characters ``&``, ``<``, ``>``, ``'``, and ``"`` in -strings to HTML-safe sequences. Use this if you need to display text that -might contain such characters in HTML. - -.. note:: - - Internally, ``escape`` uses the PHP ``htmlspecialchars`` function. - -``raw`` -~~~~~~~ - -The ``raw`` filter marks the value as safe which means that in an environment -with automatic escaping enabled this variable will not be escaped if ``raw`` is -the last filter applied to it. - -.. code-block:: jinja - - {% autoescape true %} - {{ var|raw }} {# var won't be escaped #} - {% endautoescape %} - -``merge`` -~~~~~~~~~ - -The ``merge`` filter merges an array or a hash with the value: - -.. code-block:: jinja - - {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %} - - {% set items = items|merge({ 'peugeot': 'car' }) %} - - {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #} - -List of built-in Tests ----------------------- - -``divisibleby`` -~~~~~~~~~~~~~~~ - -``divisibleby`` checks if a variable is divisible by a number: - -.. code-block:: jinja - - {% if loop.index is divisibleby(3) %} - -``none`` -~~~~~~~~ - -``none`` returns ``true`` if the variable is ``none``: - -.. code-block:: jinja - - {{ var is none }} - -``even`` -~~~~~~~~ - -``even`` returns ``true`` if the given number is even: - -.. code-block:: jinja - - {{ var is even }} - -``odd`` -~~~~~~~ - -``odd`` returns ``true`` if the given number is odd: - -.. code-block:: jinja - - {{ var is odd }} - -``sameas`` -~~~~~~~~~~ - -``sameas`` checks if a variable points to the same memory address than another -variable: - -.. code-block:: jinja - - {% if foo.attribute is sameas(false) %} - the foo attribute really is the ``false`` PHP value - {% endif %} - -``constant`` -~~~~~~~~~~~~ - -``constant`` checks if a variable has the exact same value as a constant. You -can use either global constants or class constants: - -.. code-block:: jinja - - {% if post.status is constant('Post::PUBLISHED') %} - the status attribute is exactly the same as Post::PUBLISHED - {% endif %} - -``defined`` -~~~~~~~~~~~ - -``defined`` checks if a variable is defined in the current context. This is very -useful if you use the ``strict_variables`` option: - -.. code-block:: jinja - - {# defined works with variable names #} - {% if foo is defined %} - ... - {% endif %} - - {# and attributes on variables names #} - {% if foo.bar is defined %} - ... - {% endif %} - -``empty`` -~~~~~~~~~ - -``empty`` checks if a variable is empty: - -.. code-block:: jinja - - {# evaluates to true if the foo variable is null, false, or the empty string #} - {% if foo is empty %} - ... - {% endif %} - -List of Global Functions ------------------------- - -The following functions are available in the global scope by default: - -``range`` -~~~~~~~~~ - -Returns a list containing an arithmetic progression of integers. When step is -given, it specifies the increment (or decrement): - -.. code-block:: jinja - - {% for i in range(0, 3) %} - {{ i }}, - {% endfor %} - - {# returns 0, 1, 2, 3 #} - - {% for i in range(0, 6, 2) %} - {{ i }}, - {% endfor %} - - {# returns 0, 2, 4, 6 #} - -.. tip:: - - The ``range`` function works as the native PHP ``range`` function. - -The ``..`` operator is a syntactic sugar for the ``range`` function (with a -step of 1): - -.. code-block:: jinja - - {% for i in 0..10 %} - {{ i }}, - {% endfor %} - -``cycle`` -~~~~~~~~~ - -The ``cycle`` function can be used to cycle on an array of values: - -.. code-block:: jinja - - {% for i in 0..10 %} - {{ cycle(['odd', 'even'], i) }} - {% endfor %} - -The array can contain any number of values: - -.. code-block:: jinja - - {% set fruits = ['apple', 'orange', 'citrus'] %} - - {% for i in 0..10 %} - {{ cycle(fruits, i) }} - {% endfor %} + {% spaceless %} +
    + foo +
    + {% endspaceless %} -``constant`` -~~~~~~~~~~~~ + {# output will be
    foo
    #} -``constant`` returns the constant value for a given string: +In addition to the spaceless tag you can also control whitespace on a per tag +level. By using the whitespace control modifier on your tags, you can trim +leading and or trailing whitespace: .. code-block:: jinja - {{ some_date|date(constant('DATE_W3C')) }} - -``attribute`` -~~~~~~~~~~~~~ + {% set value = 'no spaces' %} + {#- No leading/trailing whitespace -#} + {%- if true -%} + {{- value -}} + {%- endif -%} -.. versionadded:: 1.2 - The ``attribute`` function was added in Twig 1.2. + {# output 'no spaces' #} -``attribute`` can be used to access a "dynamic" attribute of a variable: +The above sample shows the default whitespace control modifier, and how you can +use it to remove whitespace around tags. Trimming space will consume all whitespace +for that side of the tag. It is possible to use whitespace trimming on one side +of a tag: .. code-block:: jinja - {{ attribute(object, method) }} - {{ attribute(object, method, arguments) }} - {{ attribute(array, item) }} - -.. note:: + {% set value = 'no spaces' %} +
  • {{- value }}
  • - The resolution algorithm is the same as the one used for the ``.`` - notation, except that the item can be any valid expression. + {# outputs '
  • no spaces
  • ' #} Extensions ---------- -Twig can be easily extended. If you are looking for new tags or filters, have -a look at the Twig official extension repository: -http://github.com/fabpot/Twig-extensions. - -Horizontal Reuse ----------------- - -.. versionadded:: 1.1 - Horizontal reuse was added in Twig 1.1. - -.. note:: - - Horizontal reuse is an advanced Twig feature that is hardly ever needed in - regular templates. It is mainly used by projects that need to make - template blocks reusable without using inheritance. - -Template inheritance is one of the most powerful Twig's feature but it is -limited to single inheritance; a template can only extend one other template. -This limitation makes template inheritance simple to understand and easy to -debug: - -.. code-block:: jinja - - {% extends "base.html" %} - - {% block title %}{% endblock %} - {% block content %}{% endblock %} - -Horizontal reuse is a way to achieve the same goal as multiple inheritance, -but without the associated complexity: +Twig can be easily extended. -.. code-block:: jinja - - {% extends "base.html" %} - - {% use "blocks.html" %} - - {% block title %}{% endblock %} - {% block content %}{% endblock %} - -The ``use`` statement tells Twig to import the blocks defined in -```blocks.html`` into the current template (it's like macros, but for blocks): - -.. code-block:: jinja - - # blocks.html - {% block sidebar %}{% endblock %} - -In this example, the ``use`` statement imports the ``sidebar`` block into the -main template. The code is mostly equivalent to the following one (the -imported blocks are not outputted automatically): - -.. code-block:: jinja - - {% extends "base.html" %} - - {% block sidebar %}{% endblock %} - {% block title %}{% endblock %} - {% block content %}{% endblock %} - -.. note:: - - The ``use`` tag only imports a template if it does not extend another - template, if it does not define macros, and if the body is empty. But it - can *use* other templates. - -.. note:: - - Because ``use`` statements are resolved independently of the context - passed to the template, the template reference cannot be an expression. - -The main template can also override any imported block. If the template -already defines the ``sidebar`` block, then the one defined in ``blocks.html`` -is ignored. To avoid name conflicts, you can rename imported blocks: - -.. code-block:: jinja - - {% extends "base.html" %} - - {% use "blocks.html" with sidebar as base_sidebar %} - - {% block sidebar %}{% endblock %} - {% block title %}{% endblock %} - {% block content %}{% endblock %} - -.. versionadded:: 1.3 - The ``parent()`` support was added in Twig 1.3. - -The ``parent()`` function automatically determines the correct inheritance -tree, so it can be used when overriding a block defined in an imported -template: - -.. code-block:: jinja - - {% extends "base.html" %} - - {% use "blocks.html" %} - - {% block sidebar %} - {{ parent() }} - {% endblock %} - - {% block title %}{% endblock %} - {% block content %}{% endblock %} - -In this example, ``parent()`` will correctly call the ``sidebar`` block from -the ``blocks.html`` template. - -.. tip:: - - In Twig 1.2, renaming allows you to simulate inheritance by calling the - "parent" block: - - .. code-block:: jinja - - {% extends "base.html" %} - - {% use "blocks.html" with sidebar as parent_sidebar %} - - {% block sidebar %} - {{ block('parent_sidebar') }} - {% endblock %} - -.. note:: +If you are looking for new tags, filters, or functions, have a look at the Twig official +`extension repository`_. - You can use as many ``use`` statements as you want in any given template. - If two imported templates define the same block, the latest one wins. +If you want to create your own, read :doc:`extensions`. .. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle .. _`Jinja syntax plugin`: http://jinja.pocoo.org/2/documentation/integration .. _`Twig syntax plugin`: https://github.com/blogsh/Twig-netbeans .. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin .. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language -.. _`DateTime`: http://www.php.net/manual/en/datetime.construct.php +.. _`extension repository`: http://github.com/fabpot/Twig-extensions diff --git a/doc/tests/constant.rst b/doc/tests/constant.rst new file mode 100644 index 0000000..7970933 --- /dev/null +++ b/doc/tests/constant.rst @@ -0,0 +1,11 @@ +``constant`` +============ + +``constant`` checks if a variable has the exact same value as a constant. You +can use either global constants or class constants: + +.. code-block:: jinja + + {% if post.status is constant('Post::PUBLISHED') %} + the status attribute is exactly the same as Post::PUBLISHED + {% endif %} diff --git a/doc/tests/defined.rst b/doc/tests/defined.rst new file mode 100644 index 0000000..9e8e228 --- /dev/null +++ b/doc/tests/defined.rst @@ -0,0 +1,17 @@ +``defined`` +=========== + +``defined`` checks if a variable is defined in the current context. This is very +useful if you use the ``strict_variables`` option: + +.. code-block:: jinja + + {# defined works with variable names #} + {% if foo is defined %} + ... + {% endif %} + + {# and attributes on variables names #} + {% if foo.bar is defined %} + ... + {% endif %} diff --git a/doc/tests/divisibleby.rst b/doc/tests/divisibleby.rst new file mode 100644 index 0000000..9b0b964 --- /dev/null +++ b/doc/tests/divisibleby.rst @@ -0,0 +1,10 @@ +``divisibleby`` +=============== + +``divisibleby`` checks if a variable is divisible by a number: + +.. code-block:: jinja + + {% if loop.index is divisibleby(3) %} + ... + {% endif %} diff --git a/doc/tests/empty.rst b/doc/tests/empty.rst new file mode 100644 index 0000000..0d1eb32 --- /dev/null +++ b/doc/tests/empty.rst @@ -0,0 +1,11 @@ +``empty`` +========= + +``empty`` checks if a variable is empty: + +.. code-block:: jinja + + {# evaluates to true if the foo variable is null, false, or the empty string #} + {% if foo is empty %} + ... + {% endif %} diff --git a/doc/tests/even.rst b/doc/tests/even.rst new file mode 100644 index 0000000..6ab5cc3 --- /dev/null +++ b/doc/tests/even.rst @@ -0,0 +1,10 @@ +``even`` +======== + +``even`` returns ``true`` if the given number is even: + +.. code-block:: jinja + + {{ var is even }} + +.. seealso:: :doc:`odd<../tests/odd>` diff --git a/doc/tests/index.rst b/doc/tests/index.rst new file mode 100644 index 0000000..69d4be7 --- /dev/null +++ b/doc/tests/index.rst @@ -0,0 +1,14 @@ +Tests +===== + +.. toctree:: + :maxdepth: 1 + + divisibleby + none + even + odd + sameas + constant + defined + empty diff --git a/doc/tests/none.rst b/doc/tests/none.rst new file mode 100644 index 0000000..8b59dd1 --- /dev/null +++ b/doc/tests/none.rst @@ -0,0 +1,8 @@ +``none`` +======== + +``none`` returns ``true`` if the variable is ``none``: + +.. code-block:: jinja + + {{ var is none }} diff --git a/doc/tests/odd.rst b/doc/tests/odd.rst new file mode 100644 index 0000000..9eece77 --- /dev/null +++ b/doc/tests/odd.rst @@ -0,0 +1,10 @@ +``odd`` +======= + +``odd`` returns ``true`` if the given number is odd: + +.. code-block:: jinja + + {{ var is odd }} + +.. seealso:: :doc:`even<../tests/even>` diff --git a/doc/tests/sameas.rst b/doc/tests/sameas.rst new file mode 100644 index 0000000..efb15c3 --- /dev/null +++ b/doc/tests/sameas.rst @@ -0,0 +1,11 @@ +``sameas`` +========== + +``sameas`` checks if a variable points to the same memory address than another +variable: + +.. code-block:: jinja + + {% if foo.attribute is sameas(false) %} + the foo attribute really is the ``false`` PHP value + {% endif %} -- 1.7.2.5