Djia Filters
AJAX filter system for any Bricks Query Loop. 15 filter elements, 9 filter types, pre-built index, shared cache and URL sync — for any CPT or WooCommerce archive.
Djia Filters adds a complete AJAX filtering system to Bricks Builder. Drag filter elements onto your page, connect them to a Query Loop and every interaction refreshes results without a page reload — URL synced, indexed and cached.
The Filter Container element is the parent wrapper for all filter elements. It connects to your Query Loop via a CSS selector.
Add a Filter Container
Drag the Filter Container element anywhere on your page — above, beside or below your listing.
Set the target selector
In the Filter Container controls, set Target Selector to the CSS class or ID of your Bricks Query Loop wrapper — e.g. .my-listing. Add a custom class to your Query Loop section first if needed.
Add filter elements inside
Place any of the 15 filter elements inside the Filter Container. Configure each one — choose the taxonomy, meta key or WooCommerce attribute.
Build the index (recommended)
For best performance run the index builder once. Go to Djia Bricks → Index → Rebuild or use WP-CLI. The index updates automatically on post save.
All 15 filter elements are available in the Bricks element panel under the Djia Filters category.
| Element | Description | Filter Types |
|---|---|---|
| Checkboxes | Multi-select filter with result counts per term | Taxonomy, Meta |
| Radio | Single-select filter for taxonomy and meta facets | Taxonomy, Meta |
| Select | Dropdown with optional multi-select mode | Taxonomy, WooCommerce |
| Color Swatch | Visual color circles per term — circle or square shape | Taxonomy, Woo attribute |
| Image Swatch | Image per term for fabric, texture or pattern filtering | Taxonomy, Woo attribute |
| Range Slider | Single dual-handle slider for numeric or price range | Meta, Woo price |
| Min / Max Input | Two number inputs for precise range entry | Meta, Woo price |
| Toggle Button | Button group for single or multi-select | Taxonomy, Meta |
| Search | Keyword search on post title and content | Keyword |
| Sort / Order | Order-by dropdown — date, title, price, custom meta | Sort |
| Active Tags | Displays active filters with individual clear buttons | All |
| Reset / Clear All | Clears all active filters in the container | All |
| Apply Button | Manual mode — results refresh only on click | Manual mode |
| Offcanvas Panel | Mobile slide-out filter drawer | Container |
| Filter Group | Collapsible wrapper for grouping related filters | Container |
These elements display and paginate the filtered results. Place them next to your Query Loop — they update together with the filters, without a page reload.
| Element | Description | Notes |
|---|---|---|
| Results Count | Shows the number of matching results — e.g. “128 products found” | Custom label & “no results” text |
| Pagination | Numbered page links for the filtered result set | Syncs with the URL (?paged=2) |
| Load More | Appends the next page of results on click | Alternative to numbered pagination |
| Per Page | Dropdown to let visitors choose results per page | e.g. 12 / 24 / 48 |
| Type | Source | Notes |
|---|---|---|
| Taxonomy | Any registered taxonomy | AND/OR relation, hide empty, count display |
| Post Meta | Any post meta key | String, numeric or date comparison. ACF, Meta Box, Pods compatible |
| Woo Attribute | WooCommerce attribute (pa_color…) | Variation-aware stock counting |
| Woo Price | _price meta | Auto min/max boundary detection from indexed data |
| Woo Stock | stock_status | In stock, out of stock, on backorder |
| Woo Rating | _wc_average_rating | Minimum star rating filter |
| Keyword | Post title + content | Configurable debounce delay |
| Sort | WP_Query orderby | Relevance, date, title, price, or any meta_value |
| Conditional | Other filter state | Show/hide filter elements based on active filter values |
Djia Filters supports parent → child relationships, so a second filter narrows to only the options that exist under the current selection — e.g. Brand → Model or Region → City. Selecting a parent implies all of its descendants, and the full path is written to the URL.
Use a hierarchical taxonomy
Point the filter at a taxonomy that has parent/child terms (e.g. a brand taxonomy where “Giulia” is a child of “Alfa Romeo”).
Enable Hierarchy mode
In the filter element controls set Display to Hierarchy (dependent dropdowns). Child options load only after a parent is chosen.
Choose depth behaviour
Selecting a parent matches the parent and every descendant. Counts are calculated from the index for the deepest selected term, so they stay accurate at every level.
| Setting | Description |
|---|---|
| Relation | Parent implies descendants (default) or exact-term-only |
| Full-path URL | Writes the whole path to the URL, e.g. ?brand=alfa-romeo,giulia |
| Depth labels | Optional label per level (Brand, Model, Trim…) |
get_term_children(). If counts look wrong after adding terms, rebuild the index (wp djia index rebuild).Djia Filters uses a pre-built flat index table to eliminate live taxonomy JOIN queries at filter time. The index auto-updates when posts are saved, updated or deleted.
- Built once — stored in a dedicated
djia_filter_indextable - Incremental updates — only changed posts are re-indexed on save
- Supports all public post types and all registered taxonomies + meta keys
- WP-CLI command for manual rebuilds and status checks
- Every unique filter state (URL params) is cached as a transient or object cache entry
- Shared anonymous cache — all visitors share the same cached response
- Configurable TTL from 5 minutes to permanent
- Uses the WordPress object cache when a persistent backend (Redis/Memcached) is available; otherwise falls back to transients
- AJAX requests bypass full-page cache (WP Rocket, LiteSpeed, Cloudflare)
Warming pre-generates cached responses for popular filter combinations so the very first visitor also gets an instant, cache-served result — not just repeat visitors. This is what makes filtering feel instant on large catalogs.
- Real visitor filter combinations are recorded as “recipes”, ranked by popularity
- A background worker replays due recipes and stores their responses in cache
- Optionally, common combinations can be generated automatically up to a configurable cap
- Stale entries are re-queued and regenerated on the next run — the cache stays warm without manual work
wp djia preload run via server cron (every 15–60 min) on stores with heavy traffic. Combine it with an object cache (Redis) so warmed entries survive and serve in near-0ms.Djia Filters integrates directly with WooCommerce product archives and custom product loops built with the Bricks Query Loop element.
On smaller screens, filters can move into a slide-out drawer instead of taking up the top of the page. The Offcanvas Panel keeps the full filter set one tap away without pushing the listing down.
Add an Offcanvas Panel
Drop the Offcanvas Panel element on the page and place your filter elements inside it (it acts as a Filter Container too).
Set a trigger & breakpoint
Choose the “Filters” button that opens the drawer, and the breakpoint below which the drawer replaces the inline filters.
Add an Apply button
On mobile, enable manual mode with an Apply button showing a live result count (“Show 128 results”), so results refresh once instead of on every tap.
Active Tags element inside the drawer so users can see and remove selections before applying.Djia Filters works with the major translation plugins. The index and cache are stored per language, so filtering, counts and URLs all stay correct in each language.
| Plugin | Support |
|---|---|
| WPML | Per-language index, translated facet labels, language-aware URLs |
| Polylang | Per-language index & cache buckets |
| TranslatePress | Active language detected on every AJAX request |
| Weglot | Language resolved from URL / cookie |
| Setting | Default | Description |
|---|---|---|
| cache_ttl | 3600 | Seconds before a cache entry expires |
| cache_driver | transients | transients or object-cache |
| ajax_debounce | 300 | Milliseconds to wait after last interaction before firing AJAX |
| url_mode | pushState | pushState or replaceState for URL sync |
| index_batch | 200 | Posts per batch when rebuilding the index |
| count_display | true | Show result counts next to filter terms |
Extend and customise filtering behaviour from PHP or JavaScript.
| Hook | Purpose |
|---|---|
| djia/filter/query_args | Modify the final query arguments before results are fetched |
| djia/filter/facet_options | Alter the options (and counts) shown for a facet |
| djia/filter/cache_ttl | Override cache lifetime per request |
| djia/filter/indexable_meta | Add or remove meta keys included in the index |
djia:filter:beforeRefresh— fires before an AJAX request is sentdjia:filter:refresh— fires after new results are rendereddjia:filter:change— fires when any filter value changes
| Problem | Cause & Fix |
|---|---|
| Filters don’t update the listing | The Target Selector doesn’t match your Query Loop wrapper. Add a custom class to the loop and set the same selector on the Filter Container. |
| Result counts are wrong | Index is out of date. Run wp djia index rebuild or Djia Bricks → Index → Rebuild. |
| Price min/max is off | Boundaries are read from the index. Rebuild after bulk price changes or importing products. |
| Old results keep showing | Cache TTL too long, or a full-page cache is caching the AJAX response. Flush with wp djia cache flush and exclude the AJAX endpoint in your page-cache plugin. |
| Nothing filters on a custom post type | The CPT must be public and indexed. Rebuild with --post-type=your_cpt. |
| Woo price/stock filter missing | WooCommerce must be active — those facet types depend on it. |