Skip to content

Product Filter

Filter form

twig
{# minimal usage #}
<i:filter-form name="default">
    {% for attribute in attributes %}
        <i:filter-attribute attribute="attribute">
            <a data-role="show-more">{% trans 'template.filter.more' %} (%n)</a>
        </i:filter-attribute>
    {% endfor %}
    <div data-role="reset">
        {% trans 'template.filter.active' %}
        <a data-role="reset">{% trans 'template.filter.reset' %}</a>
    </div>
    <button type="submit">{% trans 'template.filter.submit-button' %}</button>
</i:filter-form>

Attributes of filter-form

AttributeRequiredDefaultDescription
nameyes---name
auto-scrolltrue---automatically scroll to results (true/false)

Filter attribute

twig
<i:filter-form name="default">
    {% for attribute in attributes %}
        <i:filter-attribute attribute="attribute" choice-wrap="div">
            <a data-role="show-more">{% trans 'template.filter.more' %} (%n)</a>
            <a data-role="show-less">{% trans 'template.filter.less' %}</a>
        </i:filter-attribute>
    {% endfor %}
    <button type="submit">{% trans 'template.filter.submit-button' %}</button>
</i:filter-form>

The "show-more"/"show-less" link is only displayed when needed. The optional %n placeholder is replaced with the number of hidden values. Expand/collapse functionality is handled globally and the expanded state is saved to LocalStorage.

Attributes of filter-attribute

AttributeRequiredDefaultDescription
attributeyes---Twig object
choice-wrapnospanwrapper tag
checkbox-classno---CSS classes for the checkbox input
img-formatno30x30image size (same as in i:img)
img-sizesno---responsive sizes for the image (same as in i:img)

Filter values

Renders active filter values with the ability to remove individual values or reset the entire filter.

twig
<i:filter-values name="default">
    {% for value in values %}
        <a href="{{value.url}}">{{value.name}}</a>
    {% endfor%}
    <a href="{{resetUrl}}">{% trans 'template.filter.reset' %}</a>
</i:filter-values>

Attributes of filter-values

AttributeRequiredDescription
nameyesobject name

Filter placeholder

twig
<i:filter-placeholder name="default" config="default" />

Attributes of filter-placeholder

AttributeRequiredDescription
nameyesobject name
configyesfilter group code
hide-emptynodo not render the form if there are no filters to display
always-collapsednocollapse all filters regardless of the admin panel settings

Filter placeholder values

The i:filter-placeholder-values block must not be wrapped in a condition checking for an active filter! If the filter is not active, it will render as an empty div. If it were hidden by a parent condition, it could not appear dynamically during filtering.

twig
<i:filter-placeholder-values name="default" config="default" />

Attributes of filter-placeholder-values

AttributeRequiredDescription
nameyesobject name
configyesfilter group code

Price Slider (legacy filters)

Price slider for the filter. Uses jQuery UI Slider (must be enabled in plugins). No JavaScript initialization is needed -- inserting the tag into the template sets everything up automatically. Elements marked with the from and to roles are used to display the current price.

twig
{# minimal usage #}
<i:price-slider>
    <div data-role="slider"></div>
    <span data-role="from"></span> - <span data-role="to"></span>
</i:price-slider>

{# visible input #}
<i:price-slider>
    <div data-role="slider"></div>
    <input data-role="from"></input> - <input data-role="to"></input>
</i:price-slider>

{# custom classes (any) #}
<i:price-slider>
    <div data-role="slider"  class="slider-range" ></div>
    <div class="range">
        <em>{%trans%}od {%endtrans%} <span class="range-from" data-role="from"></span>  do <span class="range-to" data-role="to"></span></em>
    </div>
</i:price-slider>

To customize the slider behavior, use standard jQuery UI events (documentation). First add a custom class to the slider, then modify its behavior in external JavaScript:

javascript
$(document).on('slide', '.slider-range', function(event, ui) {
    alert(ui.value);
});

Slider properties can be changed the same way:

javascript
$('.slider-range').slider('option', 'animate', 'fast');

Complete Filter Template

A production _filter.tpl combining the filter form with active filter values. This example is simplified from the buran template. The filter form includes a mobile-specific header (close button + title), a scrollable body with attribute sections, and submit/reset buttons at the bottom:

twig
{# _filter.tpl #}
<i:filter-form name="default" class="filter" auto-scroll="false">
    <div class="filter__in">
        {# Mobile-only header with close button #}
        <p class="filter__header hide-for-medium">
            <a class="toggle-filter" role="button" aria-label="{% trans 'template.close' %}">
                <svg class="icon"><use xlink:href="{{ images('symbol-defs.svg#bi-cross') }}"></use></svg>
            </a>
            <strong>{% trans 'template.filter.headline' %}</strong>
        </p>

        {# Scrollable filter body with attribute sections #}
        <div class="filter__body scrollbox">
            {% for attribute in attributes %}
                <div class="filter-section filter-section--{{ attribute.id }}">
                    <i:filter-attribute attribute="attribute" checkbox-class="spec-check">
                        {# "Show more" link -- only displayed when values are hidden #}
                        {# %n is replaced with the count of hidden values #}
                        <a data-role="show-more" class="filter-more">template.filter.more (%n)</a>
                    </i:filter-attribute>
                </div>
            {% endfor %}
        </div>

        {# Submit and reset buttons #}
        <div class="filter-buttons">
            <button type="submit" class="button">
                {% trans 'template.filter.submit-button' %}
            </button>
            {# data-role="reset" wrapper is only visible when a filter is active #}
            <div data-role="reset">
                <a data-role="reset">{% trans 'template.filter.reset-button' %}</a>
            </div>
        </div>
    </div>
</i:filter-form>

{# Active filter values -- displays selected filters with individual remove links #}
{# Each value.url removes that single filter value; resetUrl clears all filters #}
<i:filter-values name="default" class="filter-active">
    <div class="filter-active__in">
        <a href="{{ resetUrl }}" class="reset-filter">
            <svg class="icon"><use xlink:href="{{ images('symbol-defs.svg#bi-cross') }}"></use></svg>
            {% trans 'template.filter.reset-button' %}
        </a>
        {% for value in values %}
            <a href="{{ value.url }}" class="filter-active__value">
                <svg class="icon"><use xlink:href="{{ images('symbol-defs.svg#bi-cross') }}"></use></svg>
                {{ value.name }}
            </a>
        {% endfor %}
    </div>
</i:filter-values>

The data-role="reset" wrapper is only visible when a filter is active. The data-role="show-more" / data-role="show-less" links toggle automatically; their expanded/collapsed state persists in LocalStorage. On mobile, the filter typically opens as a slide-in panel triggered by a toggle-filter button in the listing page.

Integration with Listing

The filter connects to a product listing through i:filter-placeholder and i:filter-placeholder-values placed inside i:list-container. Here is the buran vypis.tpl (category listing page) simplified to show how all components wire together -- the filter form, sort dropdown, active filter pills, product grid, and multiple pagination slots:

twig
{# vypis.tpl (category listing page) #}
<h1>{{ this.nazev }}</h1>

<i:list-container type="product" class="main-listing">

    {# Mobile filter toggle button (opens the filter as a slide-in panel) #}
    <div class="hide-for-medium">
        <a class="toggle-filter" role="button" aria-label="{% trans 'template.filter' %}">
            <svg class="icon"><use xlink:href="{{ images('symbol-defs.svg#bi-filter') }}"></use></svg>
            <span>{% trans 'template.filter.all-filters' %}</span>
        </a>
    </div>

    {# Filter form placeholder -- renders _filter.tpl content here #}
    <i:filter-placeholder name="default" config="default" always-collapsed />

    {# Sort dropdown (defined in _listing.tpl as i:list-pagination name="sort") #}
    <div data-role="pagination" data-name="sort"></div>

    {# Result count (defined in _listing.tpl as i:list-pagination name="numbers") #}
    <div data-role="pagination" data-name="numbers"></div>

    {# Grid style toggle (defined in _listing.tpl as i:list-pagination name="grid") #}
    <div data-role="pagination" data-name="grid"></div>

    <hr />

    {# Active filter pills with remove links -- must NOT be wrapped in a conditional! #}
    <i:filter-placeholder-values name="default" config="default" />

    {# Empty state message #}
    <div data-role="empty"></div>

    {# Product grid #}
    <div data-role="list" class="listing"></div>

    {# Bottom pagination area with multiple named sections #}
    <div class="pagination">
        <div data-role="pagination" data-name="scroll"></div>
        <div data-role="pagination" data-name="pages"></div>
        <div data-role="pagination" data-name="add"></div>
        <div data-role="pagination" data-name="numbers"></div>
    </div>

</i:list-container>

Key points:

  • i:filter-placeholder renders the filter form (defined in _filter.tpl) inside the listing container. The config attribute refers to the filter group code configured in the admin panel.
  • i:filter-placeholder-values renders the active filter selections with remove links (defined by i:filter-values in _filter.tpl). It must not be wrapped in a conditional -- it renders as an empty div when no filter is active and appears dynamically during AJAX filtering.
  • The name attribute on both placeholders must match the name used in i:filter-form and i:filter-values in _filter.tpl.
  • The always-collapsed attribute on i:filter-placeholder collapses all filter groups regardless of the admin panel settings.
  • Multiple data-role="pagination" elements with different data-name values can coexist in the same container. Each renders the corresponding i:list-pagination definition from _listing.tpl. The same data-name can appear multiple times (e.g. numbers at the top and bottom).
  • On mobile, the .toggle-filter button opens the filter panel (styled as a slide-in overlay). The close button inside the filter form (see Complete Filter Template) dismisses it.

For more about the listing components (list-item definitions, pagination variants, source patterns) used alongside filters.

Available CSS classes

Flags

  • filter-flag-in-stock - in stock
  • filter-flag-new - new arrival
  • filter-flag-promo - promotion
  • filter-flag-discount - discounted