Guide

ElasticPress architecture

Maintainer overview of VIP Search integration, facets middleware, and URL handling.

System pieces

vip-config redirects ──► WordPress /search/{term}
                              │
ElasticPress_Middleware ──► ep_integrate + aggregations
                              │
ElasticPress_Facets_API ──► Interactivity contract
                              │
prc-ep/* blocks ──► ep_filter_* URL + query refresh
Flow

Facet request path

4 relationships
ElasticPress is the sole facets provider.

Provider model

ElasticPress_Middleware is always registered from includes/class-plugin.php. The context provider and REST settings always use ElasticPress (urlKey = ep_filter_).

ElasticPress_Facets_API normalizes aggregations into the Interactivity API contract used by facet blocks.

Query takeover

ElasticPress integrates every main query flagged isPubListingQuery (publications, taxonomy archives, search) plus a dedicated dataset archive opt-in in prc-datasets. Facetable marking uses ep_is_facetable when needed.

Aggregations include:

  • Taxonomy terms (disjunctive for checkbox OR/AND-across)
  • Years (date_terms.year)
  • Time-since ranges (past-month, past-6-months, past-12-months, past-2-years)

Registered facet slugs (from plugin README): category, formats, regions-countries, bylines, research-teams, years, time_since.

URL scheme

All surfaces use ep_filter_* query params. Legacy FacetWP underscore params (_categories, _authors, _formats, _years, _time_since, and related) are 301'd in vip-config/server-redirects.php before WordPress boots. _date_range is stripped without remap.

Frontend HTML /search* integrates via facets middleware. Additional hooks cover REST/feed gaps (ep_integrate, 100-character search term cap, feed posts_per_page cap at 20). Admin DataViews list search sets ep_integrate plus the prc_wp_admin_dataview query flag (Search_Query in prc-wp-admin-dataview). Admin_Dataview_Search indexes draft / pending / private / future (not trash) and expands search fields (title, slug, and chart design_slug). Numeric IDs use post__in, not the ES post_id field. See the plugin README search routing table.

After expanding indexable statuses, reindex VIP Search (wp vip-search index) so drafts and other unpublished posts are searchable.

Origin hardening (search / staff)

Deep unique /search/* renders can saturate PHP-FPM when bots invent junk terms. Guards:

LayerRule
vip-config/redirects.phpNonsense /search/{term}/ (consecutive ++ / spaces, noise-only, no real word) → 301 /
ElasticPress_Middleware::MAX_NAVIGABLE_PAGEFacets-only threshold (100); result pagination still uses MAX_RESULT_WINDOW / per_page
ElasticPress_Facets_APIEmpty facets past page 100 or for nonsense s
PluginDefensive WP short-circuit + 404 if nonsense s reaches WordPress

MAX_RESULT_WINDOW (10000) remains the Elasticsearch result/pager ceiling. Keep vip-config heuristics in sync with is_nonsense_search_term() in includes/utils.php.

MySQL fallback

When ES fails, visibility SQL still applies; facet filters are not re-applied on MySQL. UI renders disabled facet shells (isDisabled).

Cache

Cache keys hash query + selected facets + a manual invalidation stamp (construct_cache_key). Cache groups derive from the request path with pagination stripped (construct_cache_group).

Caches invalidate on content updates, when the manual invalidation date changes, and when facet configuration changes.

Debug

  • PHP: define PRC_ELASTICPRESS_DEBUG to log provider decisions under [PRC Facets - ElasticPress]
  • Client: window.prcFacetsDebug = true

Key files

PathPurpose
includes/class-plugin.phpSearch integration, sanitization, facet bootstrap
includes/class-admin-dataview-search.phpAdmin DataViews search fields and unpublished statuses
includes/providers/Middleware + Facets API
includes/class-rest-api.phpFacet settings REST
vip-config/server-redirects.phpPre-WordPress search + legacy facet redirects
src/Facet blocks

Was this helpful?