dynamic_facet_cascade
A Drupal module that places a configurable block of cascading AJAX dropdowns in front of a search results page built with Views on top of a Search API index. Users make sequential selections (e.g. Make → Model → Version) and are redirected to that Views page pre-filtered with the chosen facet values appended to the URL.
Overview
Problem: Search API + Facets provides powerful filtering, but users face an overwhelming wall of checkboxes or dropdowns with hundreds of options. There is no native way to scope the selection progressively (e.g. "first pick a brand, then only see models for that brand").
Solution: This module adds a pre-filter block that sits above the search view. Each dropdown only reveals options relevant to the parent selection, creating a guided search funnel. On submit, the block builds a Facets-compatible URL and redirects to the view.
The module is heavily tied to Views: the redirect target must be a Views page display whose base table is a Search API index, and the facets it pre-fills must use that display as their facet source (search_api:views_page__{view}__{display}). The preset admin form only offers views that satisfy this, and the optional content-based cascade mode queries the same index the view is built on.
Example flow: [Make: Toyota] → [Model: Corolla] → [Version: LE] → [Search] — the Model dropdown only shows Toyota models, the Version dropdown only Corolla versions.
Requirements
- Drupal 10 or 11
- Search API with a configured index
- Views (Drupal core): the search results page must be a Views page display whose base table is a Search API index — the preset form only lists such views
- Facets with facet entities attached to that Views display (facet source
search_api:views_page__…) - Taxonomy vocabularies with entity reference fields linking parent → child levels
Installation
composer require drupal/dynamic_facet_cascade
drush en dynamic_facet_cascade
drush cr
Configuration
All preset management lives at Admin → Configuration → Search and Metadata → Dynamic Facet Cascade (/admin/config/search/dynamic-facet-cascade).
Step 1 — Create the Facets
The preset form can only offer facets that already exist for your search view. Before creating a preset, create one facet per dropdown you plan to expose — one for each cascade level (e.g. Make, Model, Version) and one for each dominant dimension (e.g. Year, Type):
- Go to Admin → Configuration → Search and Metadata → Facets (
/admin/config/search/facets) and click Add facet. - Facet source: select the page display of your Search API view (e.g.
search_api:views_page__car_search__page_1). The facet must be attached to the view's display — facets created for other sources will not appear in the preset form. - Field: pick the indexed taxonomy term field for that dropdown.
- Save, and repeat for every level and dominant dimension.
Empty Facet dropdowns on the preset page? This step is what's missing — the module lists only facets whose source matches the selected view.
Step 2 — Create a Preset
- Click Add Preset.
- Enter a Label (human-readable) and Machine name (used as the block ID).
- Search View Path: the path of the Search API view page that displays results.
- Facet Value Type: how the selected term is encoded in the redirect URL:
tid— numeric term ID (?f[]=brand:42). Most performant; safe for all term names.name— raw term label (?f[]=brand:Toyota). Requires Facets configured to accept names.slug— CSS-cleaned lowercase label (?f[]=brand:toyota). Human-friendly URLs.
- Cascade on existing content only: see Cascade Modes below.
Step 3 — Cascade Levels
Define the ordered chain. Each level maps to one Facets entity configured for the chosen view.
- Facet
- Select from Facets entities attached to the chosen view. The module derives the vocabulary, URL alias, and inter-level reference field automatically.
- Label
- Label shown on the dropdown in the block (e.g. "Make", "Model", "Version").
Click Add Level / Remove Level to adjust the chain. A minimum of two levels is recommended.
Order matters. Level 1 filters Level 2, Level 2 filters Level 3, etc. Arrange from broadest to most specific.
Step 4 — Tabs
Tabs allow multiple named search variations in one block. Each tab adds an independent dominant dimension — a dropdown that is orthogonal to the cascade chain (e.g. Year or Era).
- Tab Label
- Text shown on the tab button (e.g. "By Year").
- Dominant Dimension
- A Facets entity whose selected value is included in the redirect URL alongside the cascade values.
- Exposed Dropdowns & Weights
- Check/uncheck which dropdowns appear on this tab. Weight controls left-to-right order.
A single-tab preset renders no tab buttons — just the dropdowns.
Step 5 — Place the Block
- Go to Structure → Block Layout.
- Find Dynamic Facet Cascade: [Preset Label] in the block list.
- Place it in a region above your search view.
- No special block settings needed — all configuration lives in the preset.
Cascade Modes
Taxonomy-based (default)
Options come directly from the taxonomy database. A selected Make shows all Models that reference that Make via field_brand, regardless of whether any nodes exist for those models. Fast and consistent — ideal for curated catalogs.
Content-based (cascade_existing_only)
Each dropdown is additionally filtered against the live Search API index. A Model only appears if at least one indexed, published node references it. Slower (runs a Search API query per page load) but always accurate for sparse or frequently changing catalogs.
Choose content-based mode when your taxonomy is comprehensive but only a fraction of terms have actual listings — otherwise users see options that lead to empty results.
URL Format
On submit, the block builds a ?f[]=alias:value query string and redirects to the configured view path:
/search?f[]=year:2023&f[]=brand:toyota&f[]=model:corolla&f[]=version:le
The alias for each parameter comes from the Facets entity's URL alias setting. The value format depends on the preset's Facet Value Type.
On page load, the block reads any existing f[] parameters from the URL and pre-populates the dropdowns, so users can refine an existing search without losing context.
Tabs & the Dominant Dimension
The dominant dimension is an independent facet that defines a tab's theme. It is not part of the cascade chain — it filters results directly without cascading down. Common uses:
- Year — "By Year" tab where year filters results but doesn't change which brands/models appear
- Era — "By Era" tab grouping results by decade or period
- Type — "By Type" tab where selecting a category pre-scopes the cascade
When cascade_existing_only is on, the dominant also participates: selecting a dominant value additionally filters cascade options to only those with indexed content matching that dominant term.
Dominant Term Pre-Selection
Each tab's dominant can be pre-configured to represent a specific term.
Visible pre-selection: the dominant dropdown renders with a configured term already selected. The user can change it. Useful as a smart default (e.g. default year = current year).
Hidden injection: the dominant dropdown is not rendered at all. The locked term is silently included in the redirect URL on every submit. Useful for segment-specific blocks:
- A "SUVs" block where
car_type = SUVis always applied, invisible to the user - A "Classics" block where
era = 1960sis always injected
Configure via the Limit to a specific term option on each tab in the preset form.
Developer Notes
All configuration lives in a single config entity (dynamic_facet_cascade_preset); one preset = one block variant, exposed via a block deriver. Each cascade level corresponds to a taxonomy vocabulary whose terms reference the parent level via an entity_reference field — the reference field between adjacent levels is auto-discovered at runtime by inspecting field definitions.
Nothing about a level's vocabulary, reference field, or URL alias is stored in the preset: all of it is derived at runtime from the configured Facets entity (field identifier → vocabulary → reference field, plus the facet's URL alias). Renaming a field or vocabulary only requires updating the Facets entity — the preset auto-adapts. See the README and WALKTHROUGH in the repository for the full developer reference.