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

mFilterForm ​

Snippet for rendering the filter form.

Parameters ​

Main ​

ParameterDefaultDescription
resourceIdcurrent resourceResource ID for filter configuration
filters—Show only these filters (comma-separated)
exclude—Exclude these filters (comma-separated)

Templates ​

ParameterDefaultDescription
tplmfilter.filterFilter block template
tplOuter@INLINEOuter form template
tplItem—Filter item template (checkbox/radio)
tplSlider—Range slider template
tplColor—Color filter template
tplBoolean—Boolean 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
formId—Form HTML id
formClass—Form 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