Templating
Flare's content elements render Twig templates. A Flare Engine object is made availble as flare variable in those
templates to interface with the list or reader in the current context.
Use the bundled templates as your starting point. They reflect the current runtime API.
Quick Start
When upgrading to Flare v0.1 – Older Flare documentation referred to Twig helpers such as flare_form(...), flare_make_list(...),
and direct access to flare.entries. These functions and accessors are no longer available.
flareis the engine injected by the content element controllerflare.createViewcreates the runtime view object for the current context{% set flare_view = flare.createView %}- Reader templates work with a
ValidationView - List templates work with an
InteractiveView
Within anInteractiveView:- Create the list view:
{% set flare_list = flare.createView %} - Create the Symfony Form views for filtering:
{% set form = flare_list.form.createView %} - Access entries:
{% for entry in flare_list.entries %}
<h3>{{ entry.headline }}</h3>
{% endfor %} - Display a paginator:
{{ include('@Contao/flare/paginator.html.twig', { paginator: flare_list.paginator }) }}
- Create the list view:
Template Locations
Bundled Templates
The bundled templates live in:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/
The main content element templates are:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/content_element/flare_listview.html.twig
vendor/heimrichhannot/contao-flare-bundle/contao/templates/content_element/flare_reader.html.twig
Related partials live in:
vendor/heimrichhannot/contao-flare-bundle/contao/templates/flare/
Custom Templates
To override or extend the provided templates, create Twig files in a Twig template directory of your Contao
installation. Assuming there is a .twig-root file in contao/templates/, a typical structure looks like this:
contao/templates/content_element/{flare_listview,flare_reader}/my_variant.html.twig
You can then select the variant via the content element's customTpl field.
List View Templating
The default list template creates an interactive view first and then renders the filter form, entries, and paginator from that view.
{% extends "@Contao/content_element/flare_listview.html.twig" %}
{% set flare_list = flare.createView %}
{% block filter %}
{% set form = flare_list.form.createView %}
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">{{ 'submit'|trans({}, 'flare_form') }}</button>
{{ form_end(form) }}
{% endblock %}
{% block list %}
{% for entry in flare_list.entries %}
{% set href = flare_list.to(entry.id) %}
<article>
<h3>
{% if href %}
<a href="{{ href }}">{{ entry.headline ?? entry.title ?? '' }}</a>
{% else %}
{{ entry.headline ?? entry.title ?? '' }}
{% endif %}
</h3>
</article>
{% else %}
<p>No entries found.</p>
{% endfor %}
{% endblock %}
{% block pagination %}
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator
}) }}
{% endblock %}
Available Variables in List Templates
The list content element injects these template variables:
flare: theEnginecontent_model: thetl_contentmodel of the current content elementheadline: the normalized Contao headline data
After creating the view with flare.createView, you typically work with:
flare_list.form: the Symfony form objectflare_list.entries: the current result setflare_list.models: the current result set as Contao modelsflare_list.paginator: the paginatorflare_list.count: the total result countflare_list.to(id): the reader URL for an entry, if configuredflare_list.model(id): theContao\Modelinstance for a specific entry
Entries and Models
In list templates, flare_list.entries yields associative arrays for the current result set.
If you need access to the full model collection directly, use flare_list.models:
{% for model in flare_list.models %}
<h3>{{ model.headline ?? model.title ?? '' }}</h3>
{% endfor %}
If you need models only occasionally, you can still iterate over flare_list.entries and resolve a specific model from
the current entry:
{% for entry in flare_list.entries %}
{% set model = flare_list.model(entry.id) %}
<h3>{{ model.headline ?? entry.headline ?? '' }}</h3>
{% endfor %}
Under the hood, flare_list.model(id) may resolve each model from the cache or from the database individually,
while flare_list.models resolves all models at once. In any case, models are registered from the raw result set (i.e.
flare_list.entries) and cached for later use, eliminating unnecessary database queries.
- Use
flare_list.entrieswhen the raw result data is sufficient. - If you only need models occasionally throughout the loop, using
flare_list.model(entry.id)is perfectly fine. - If you need models throughout the whole loop,
flare_list.modelsis the better choice than resolving each model individually.
Customizing the Filter Form
The filter form is a normal Symfony form. Create the form view from flare_list.form and apply form themes as usual.
{# assuming {% set flare_list = flare.createView %} has been defined #}
{% set form = flare_list.form.createView %}
You can access individual form fields by their field name. That field name is also used for the submitted query
parameter. For example, if a field is named search, you can access it as form.search:
{% set search_field = form.search %}
{{ form_row(search_field) }}
{% block filter %}
{% set flare_list = flare.createView %}
{% set form = flare_list.form.createView %}
{% form_theme form with [
'bootstrap_5_layout.html.twig',
'form/my_symfony_form_theme.html.twig',
] %}
{{ form_start(form) }}
{% set search_field = form.search %}
<div class="my-form-fields">
<div class="my-custom-search-field">
{{ form_row(search_field) }}
</div>
{{ form_rest(form) }}
</div>
{% block submit %}
<button type="submit">Apply filter</button>
{% endblock %}
{% block reset %}
<button type="reset" class="visually-hidden-focusable">Reset filter</button>
{% endblock %}
{{ form_end(form) }}
{% endblock %}
Because form themes are standard Symfony form themes, place them in templates/form/ relative to the project root, not
in the Contao templates directory.
Reader Templating
The reader content element renders a single model. Its default template extends the same base template as the list view, but works with reader-specific variables.
{% extends "@Contao/content_element/flare_reader.html.twig" %}
{% block content %}
<article>
<h1>{{ model.headline ?? model.title ?? '' }}</h1>
{% if model.teaser %}
<div>
{{ model.teaser|raw }}
</div>
{% endif %}
</article>
{% endblock %}
Available Variables in Reader Templates
The reader content element injects these variables:
flare: theEngineflare_reader: the pre-definedValidationViewcreated fromflaremodel: the resolvedContao\Modelfor the current reader itemcontent_model: thetl_contentmodel of the current content elementheadline: the normalized Contao headline datacomments: optional comments data when the comments integration attaches it
The reader template can also use flare_reader.to(id) if you need to generate reader links from within the validation
view, i.e., linking to other entries of the same list.
Within a reader template, creating a separate view with flare.createView is typically not necessary.
Instead of a flare_list variable, you can use flare_reader directly.
In a ValidationView, no Symfony form is available for filtering, meaning you cannot use flare_reader.form or
similar.
Block Structure
These are the main blocks available for extension.
Base Template
@Contao/flare/_flare_base.html.twig defines:
wrapperheadlinecontentfooter
List Template
@Contao/content_element/flare_listview.html.twig adds:
content_startfilterlistpaginationcontent_end
Reader Template
@Contao/content_element/flare_reader.html.twig mainly customizes:
contentfooter
Paginator Templates
Flare ships several paginator templates.
Default paginator
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator
}) }}
The default paginator supports use_default_styles:
{{ include('@Contao/flare/paginator.html.twig', {
paginator: flare_list.paginator,
use_default_styles: true
}) }}
Bootstrap 5 variants
Flare also ships:
@Contao/flare/paginator/bs5.html.twig@Contao/flare/paginator/bs5_extended.html.twig
These are useful if you want predefined Bootstrap-compatible paginator markup.
Modding the Flare Engine
Influencing list filtering or filter form rendering is possible by adding mods to the flare engine before creating
the view.
{% do flare.addMod(mod_type, mod_options) %}
For example, add filters dynamically or change the paginator url query parameter.
{%
set modded_view = flare
.addMod('equation', { ... })
.addMod('query_param', { ... })
.createView()
%}
If you want to create multiple views consecutively with different mods, use flare.clearMods() to clear the current
mod stack and start fresh.
See the Developers / Engine Mods page to learn more about mods and how to create custom ones.
Bundled Mods
Currently, only the following few mods are built-in.
Filter: Simple equation
Useful for showing multiple lists of different archives or categories on the same page. Just use one list view content element and display the different lists with different mods.
- Mod type:
equation - Mod options:
operand1(string): the database column name to filter on,operator(string): the operator, e.g.=,>=,LIKE, etc.,operand2: the second operand, e.g., a string to match, a number to compare, an ID, etc.
Form: Query parameter
To add individual paginators to multiple lists created in one template, use this mod to change the query parameter used for pagination.
- Mod type:
query_param - Mod options:
param(string): the query parameter name.
Examples
{# @var \HeimrichHannot\FlareBundle\Engine\Engine flare #}
{% extends '@Contao/content_element/flare_listview.html.twig' %}
{# @var \HeimrichHannot\FlareBundle\Engine\View\InteractiveView flare_list #}
{% set flare_list = flare.createView %}
{% set form = flare_list.form.createView %}
{% macro render_list(list_view, headline) %}
<article class="flare-listview content-flare-listview block">
<h2>{{ headline }}</h2>
{% for entry in list_view.entries %}
{# Render the entry here #}
{% endfor %}
<footer>
{{ include('@Contao/flare/paginator.html.twig', { paginator: list_view.paginator }) }}
</footer>
</article>
{% endmacro %}
{% block list %}
{% set list_view = flare
.addMod('equation', { operand1: 'medium', operator: '=', operand2: 'video' })
.addMod('query_param', { param: 'video_page' })
.createView()
%}
{{ _self.render_list(list_view, 'Videos') }}
{% set list_view = flare
.clearMods()
.addMod('equation', { operand1: 'medium', operator: '=', operand2: 'podcast' })
.addMod('query_param', { param: 'podcast_page' })
.createView()
%}
{{ _self.render_list(list_view, 'Podcasts') }}
{% endblock %}
Debugging
We are working on improving ways to explore and document the available options per mod.
Providing an empty or malconfigured config dictionary will typically raise an exception informing you on required and available option keys.
{% do flare.addMod('equation', { what: 'ever' }).createView %}
Resulting in an exception like this:
An exception has been thrown during the rendering of a template
("The option "what" does not exist. Defined options are: "name", "operand1", "operand2", "operator".")Twig Helpers
Flare currently registers these Twig functions:
flare_content(model)for rendering the content elements belonging to the model.flare_enclosure(model|entry_row, string field = "enclosure")for retreiving file enclosure data as you would with\Contao\Controller::addEnclosuresToTemplate(...)flare_enclosure_files(model|enclosure_array)(deprecated, will be removed in v0.2): retreives a collection ofContao\FilesModelinstances for the given model or an imediate array of enclosure data.flare_schema_org(?model = null)(uses model from context if not provided): prints the JSON-LD schema markup for the given model in a reader context. The data can be influenced using theReaderSchemaOrgEvent.
Comments Integration
Comments are not universally available. They are attached by Flare's comments integration when the current list and reader setup supports them.
The default reader template renders comments in its footer block if comments data is present:
{% block footer %}
{% if comments|default(false) %}
{{ include('@Contao/flare/comments/basic.html.twig', comments) }}
{% endif %}
{% endblock %}