Skip to content
mFilter
mFilter
Faceted filtering for MODX 3 with SEO URL support
  1. Extras
  2. mFilter
  3. Snippets
  4. mFilterForm

mFilterForm

Snippet for rendering the filter form.

Parameters

Main

ParameterDefaultDescription
resourceIdcurrent resourceResource ID for filter configuration
filtersShow only these filters (comma-separated)
excludeExclude these filters (comma-separated)

Templates

ParameterDefaultDescription
tplmfilter.filterFilter block template
tplOuter@INLINEOuter form template
tplItemFilter item template (checkbox/radio)
tplSliderRange slider template
tplColorColor filter template
tplBooleanBoolean toggle template

Value display

ParameterDefaultDescription
showCountstrueShow result counts
hideZerotrueHide values with zero count
hideEmptyfalseHide empty filters (no values)
sortByCountfalseSort values by count (DESC)

Form

ParameterDefaultDescription
formIdForm HTML id
formClassForm CSS class
actionUrlcurrent URLForm action URL
methodPOSTForm method (GET, POST)

AJAX

ParameterDefaultDescription
ajaxtrueEnable AJAX filtering
ajaxModeformMode: form (on button) or instant (on change)

Output

ParameterDefaultDescription
outputSeparator\nSeparator between filter blocks
toPlaceholderfalseOutput to placeholder
placeholderPrefixmfilter.Placeholder prefix

Examples

Basic call

fenom
{'!mFilterForm' | snippet}

Only specific filters

fenom
{'!mFilterForm' | snippet: [
    'filters' => 'vendor,color,price'
]}

Exclude filters

fenom
{'!mFilterForm' | snippet: [
    'exclude' => 'size,weight'
]}

Instant filtering

fenom
{'!mFilterForm' | snippet: [
    'ajaxMode' => 'instant'
]}

Sort values by popularity

fenom
{'!mFilterForm' | snippet: [
    'sortByCount' => 1,
    'hideZero' => 1
]}

Custom form wrapper

fenom
{'!mFilterForm' | snippet: [
    'tplOuter' => '@INLINE <form id="catalog-filter" class="filter-sidebar" data-mfilter>{$output}</form>'
]}

Output to placeholder

fenom
{'!mFilterForm' | snippet: [
    'toPlaceholder' => 'sidebar.filters'
]}

{* Use elsewhere *}
<aside>
    {$_modx->getPlaceholder('sidebar.filters')}
</aside>

Form for another resource

fenom
{* Filter form for category ID=5 *}
{'!mFilterForm' | snippet: [
    'resourceId' => 5
]}

Templates

Default structure

html
<form data-mfilter data-mfilter-results=".mfilter-results">
    <!-- Filter "Brand" -->
    <div class="mfilter-filter" data-filter="vendor">
        <div class="mfilter-filter-title">Brand</div>
        <div class="mfilter-filter-content">
            <label class="mfilter-item">
                <input type="checkbox" name="vendor[]" value="apple">
                <span class="mfilter-label">Apple</span>
                <span class="mfilter-count">15</span>
            </label>
            <!-- ... -->
        </div>
    </div>

    <!-- Filter "Price" (range) -->
    <div class="mfilter-filter mfilter-range" data-filter="price">
        <div class="mfilter-filter-title">Price</div>
        <div class="mfilter-filter-content">
            <input type="number" name="price|min" data-range="min" min="0" max="100000">
            <input type="number" name="price|max" data-range="max" min="0" max="100000">
            <div data-mfilter-slider></div>
        </div>
    </div>

    <button type="submit">Apply</button>
    <button type="reset" class="mfilter-reset">Reset</button>
</form>

Custom filter template

fenom
{'!mFilterForm' | snippet: [
    'tpl' => '@FILE chunks/filter.custom.tpl'
]}

chunks/filter.custom.tpl:

html
<div class="filter-block filter-{$key}" data-filter="{$key}">
    <h4 class="filter-title">{$label}</h4>

    {if $type == 'number'}
        <div class="filter-range">
            <input type="number" name="{$key}|min" value="{$min}" min="{$filterMin}" max="{$filterMax}">
            <span>—</span>
            <input type="number" name="{$key}|max" value="{$max}" min="{$filterMin}" max="{$filterMax}">
        </div>
    {else}
        <ul class="filter-values">
            {foreach $values as $item}
                <li class="filter-value {$item.active ? 'active' : ''}">
                    <label>
                        <input type="checkbox" name="{$key}[]" value="{$item.value}" {$item.active ? 'checked' : ''}>
                        {$item.label}
                        {if $showCounts}
                            <span class="count">({$item.count})</span>
                        {/if}
                    </label>
                </li>
            {/foreach}
        </ul>
    {/if}
</div>

Placeholders in filter template

PlaceholderDescription
{$key}Filter key (vendor, color, price)
{$label}Filter label
{$type}Type (default, number, boolean, vendors, colors)
{$source}Source (option, tv, field, resource)
{$values}Values array
{$min}, {$max}Current range values
{$filterMin}, {$filterMax}Range bounds
{$active}Whether any value is selected

Placeholders in value item

PlaceholderDescription
{$item.value}Value
{$item.label}Display label
{$item.count}Result count
{$item.active}Whether value is selected
{$item.slug}SEO slug for value
{$item.hex}HEX color (for colors type)

Data attributes

The form uses data attributes for JavaScript:

AttributeDescription
data-mfiltermFilter form marker
data-mfilter-resultsResults block selector
data-mfilter-ajaxEnable AJAX (true/false)
data-mfilter-modeMode: form or instant
data-mfilter-auto-submitAuto-submit on change
data-mfilter-hashConfig hash for AJAX
data-filterFilter key (on block)
data-rangeRange field type (min/max)
data-mfilter-sliderMarker for noUiSlider

CSS classes

ClassDescription
.mfilter-formFilter form
.mfilter-filterSingle filter block
.mfilter-filter-titleFilter title
.mfilter-filter-contentFilter content
.mfilter-itemFilter item (label)
.mfilter-labelItem text
.mfilter-countResult count
.mfilter-rangeRange block
.mfilter-resetReset button
.mfilter-loadingLoading state
.mfilter-disabledDisabled item

Filters outside the form

You can place individual filters outside the main form and control them via JS API:

fenom
{* Main form without brand filter *}
{'!mFilterForm' | snippet: [
    'exclude' => 'vendor',
    'formId' => 'main-filter'
]}

{* Separate brand filter in header *}
<select id="header-brand">
    <option value="">All brands</option>
    <option value="apple">Apple</option>
    <option value="samsung">Samsung</option>
</select>

<script>
document.getElementById('header-brand').addEventListener('change', (e) => {
    const filter = mfilterGet('main-filter');
    if (e.target.value) {
        filter.setFilter('vendor', e.target.value);
    } else {
        filter.removeFilter('vendor');
    }
    filter.submit();
});
</script>

See: External filters