# Facet Recipes

> Practical facet setups backed by the codebase E2E scenarios.

<!-- Sources: src/Testing/E2E/Facets/FacetsScenarioProvider.php; tests/e2e/components/facets/multi-facet-combinations.spec.ts; tests/e2e/components/facets/taxonomy-query.spec.ts; tests/e2e/components/facets/meta-query-variants.spec.ts; tests/e2e/components/facets/date-query.spec.ts; tests/e2e/components/facets/wp-query-args.spec.ts; tests/e2e/components/facets/map-facet.spec.ts; tests/e2e/components/facets/nested-loop-context.spec.ts -->

# Facet Recipes

These recipes use real scenarios from the test suite. They describe authoring intent and the important prop choices rather than copying fixture-only helper code.

## CPT and Taxonomy Filter

Use this when a result loop lists a custom post type and users need to filter by a custom taxonomy.

Example data:

```text
Post type: facettestcpt
Taxonomy: facet_color
Terms: red, blue, green
Target ID: catalog-results
```

Authoring setup:

1. Add a `Facet Target` with `target = catalog-results`.
2. Place the WP Query loop in the target loop slot. The loop should include the desired post type.
3. Add a `Select Facet`, `Radio List Facet`, or `Checkbox List Facet` with the same `target`.
4. Set `argument_mode = tax`.
5. Set `taxonomy = facet_color`.
6. Set `tax_field = slug` when option values are slugs like `red`.
7. Add options with values matching the selected field.

The taxonomy E2E suite verifies `slug`, `term_id`, `name`, and `term_taxonomy_id`.

## Multiple Facets to One Target

Use this when users need to narrow the same result grid with several independent controls.

Example:

```text
Target ID: multi-combo-target
Facet 1: Select post_type = post
Facet 2: Select category_name = facets-e2e-news
Facet 3: Select tag = facets-e2e-beta
Facet 4: Radio meta facet_priority = high
```

Each facet uses the same `target`. The backend combines the active clauses, and the result is the intersection. The E2E suite verifies two-way, three-way, and four-way intersections, fallback on zero results, recovery after clearing one facet, and pagination reset after changing a facet.

## Meta Filter

Use meta mode when the filtered value lives in post meta.

Example data:

```text
Meta key: facet_price
Values: 10, 25, 50, 75, 100
```

Authoring setup:

```text
argument_mode = meta
meta_key = facet_price
meta_compare = BETWEEN
meta_type = numeric
option value = 25,75
```

The meta query E2E suite verifies exact matches, numeric ranges, char values, bool values, `LIKE`, `NOT LIKE`, `IN`, `NOT IN`, `BETWEEN`, and `NOT BETWEEN`.

## Date Range Filter

Use date mode when authored options represent date ranges.

```text
argument_mode = date
column = post_date
option value = 2024-01-01,2024-12-31
```

The first date is the start date and the second date is the end date. Supported columns are `post_date`, `post_modified`, `post_date_gmt`, and `post_modified_gmt`.

## ACF Relationship Filter

Use ACF relationship mode when the posts being filtered store related post IDs in a relationship field.

```text
Filtered posts: Projects
Related posts: People
Relationship field on Projects: project_people
Facet option value: numeric Person post ID
```

Authoring setup:

```text
argument_mode = acf_relationship
acf_relationship_argument.meta_key = project_people
option value = 123
```

The directional rule is important: the relationship field must be stored on the posts being filtered. The facet does not reverse-resolve a relationship stored only on the related posts.

Comma-separated option values are supported for matching any of several related IDs:

```text
option value = 123,456
```

## Mapped Bundle Option

Use mapped bundle when one option should apply several query clauses.

Example option:

```text
Label: News + High priority
category mapping: category_name = facets-e2e-news
priority mapping: facet_priority = high
```

Parent facet:

```text
target_multiple_query_arguments = true
query_argument_mappings:
- mapping_key = category, argument_mode = default, facet_key = category_name
- mapping_key = priority, argument_mode = meta, meta_key = facet_priority, meta_compare = =, meta_type = char
```

Option:

```text
used_with_multiple_arguments = true
query_value_mappings:
- mapping_key = category, value = facets-e2e-news
- mapping_key = priority, value = high
```

The runtime expands the selected option into both clauses.

## Search Across Multiple Arguments

Use Search Facet multi-argument mode when one input should search more than one field.

```text
target_multiple_query_arguments = true
query_argument_relation = OR
query_argument_mappings:
- mapping_key = native-search, argument_mode = default, facet_key = search
- mapping_key = priority, argument_mode = meta, meta_key = facet_priority, meta_compare = LIKE, meta_type = char
```

Typing one value creates a `query_bundle` and applies the typed value to each mapped row. Search mappings normalize common text fields to partial aliases, so `title` behaves like `title_like`.

## Map and POIs

Use Map Facet when the target loop renders listings with coordinates.

Authoring setup:

1. Add `Map Facet` with `target = map-results`.
2. Configure `lat_meta_key` and `lng_meta_key`.
3. Add `Facet Target` with the same `target` and `used_with_map = true`.
4. Inside the target loop, add `Map POI`.
5. Set POI `value`, `lat`, and `lng` from the current loop item.

The map runtime reads initial POIs from the DOM and sends `geo_bbox` values as the map moves.

## Nested Loop Target

If the target is inside an outer Etch loop, keep the target template inside the original render context. The current implementation stores resolved outer-loop params before AJAX refresh, and the `nested_loop_context` E2E scenario verifies that searching for `Alice` still returns `Alice Alpha` and `Alice Beta` from the correct outer-loop rows.
