=== Scry Search: Meilisearch for WordPress === Contributors: jtgraham38 Tags: meilisearch, search, developer, hooks, extendable Requires at least: 5.2 Tested up to: 7.1 Stable tag: 1.5.2 Requires PHP: 8.1 License: GPLv3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html Meilisearch for WordPress: keyword + built-in semantic/hybrid search. Drop-in WP_Query, ~45 PHP hooks, no theme changes. == Get Managed Hosting from ScryWP == Don't want to operate Meilisearch yourself? [ScryWP Search](https://scrywp.com) runs the engine for you — kept patched, monitored, and maintained — so search isn't another server to babysit. Self-hosting and local dev stay fully supported; see **Managed hosting (ScryWP)** below. == Description == Scry Search wires Meilisearch into WordPress the way you'd want it on a client project: fast keyword search, optional AI/semantic (hybrid) search, and a big extension surface — without ripping out your theme. **Docs (start here):** [DOCS.md on GitHub](https://github.com/jtgraham38/ScryWP-Search/blob/main/DOCS.md) — every filter/action, args, return values, when it fires, plus the `window.scrySearch` JS API. Same file ships in the plugin zip. You get over **40 PHP hooks** (`scry_ms_*`) covering indexing, documents, index settings, federated search, autosuggest, analytics, logs, and the front-end runtime. Call sites are marked in source. If you can install a plugin and paste API keys, you can run it without writing code. If you ship WordPress for a living, you can bend it without forking. = No theme changes. Not glued to a results UI. = This is the important bit: * We do **not** replace your search results template. `search.php` (or whatever your theme / builder uses) still renders the results. * We do **not** require a shortcode, block, or widget. Autosuggest and highlighting are optional and off unless you turn them on. * Existing search forms keep working. Gutenberg Search block, classic `searchform.php`, Elementor/Divi/Beaver search widgets — they still POST to WordPress; we intercept the query. Admin-side tuning is a different story: ranking, searchable/filterable fields, synonyms, typo tolerance, hybrid embedders, federated weights, etc. are all in wp-admin (see below). You’re not stuck editing Meilisearch JSON by hand — you’re just not locked into a plugin-owned results page. Under the hood we hook `posts_pre_query`, run the search in Meilisearch, and hand WordPress normal `WP_Post` objects. Same loop, same template tags, same pagination assumptions your theme already has. Need native WP search for one query? `scry_ms_should_search`. = Built-in semantic / hybrid search = Keyword search is the baseline. Hybrid search is built into the core plugin (not a separate SKU): Meilisearch blends full-text ranking with vector similarity so "fuzzy intent" queries still hit the right posts/products. Per index, under **Index Settings → Configure Index → Hybrid Search**: * Add embedders (OpenAI, Hugging Face, Ollama, user-provided vectors, other Meilisearch-supported sources) * Pick which embedder to use and the semantic vs keyword ratio * Enable hybrid per post type — products can differ from posts Same `WP_Query` path as keyword search. No second endpoint, no alternate results page. Reindex after embedder changes so vectors exist. Analytics can record hybrid usage in `search_metadata`. = What you configure in wp-admin = Most of Meilisearch’s knobs are in WordPress — you don’t need to curl the instance for day-to-day tuning. **Connection** — URL, admin key, optional search-only key, connection test. **Index Settings** (tabbed dialog per post type): * Searchable fields — titles, content, excerpts, taxonomies, author, custom meta (ACF, Meta Box, etc.); drag to set relevancy order * Filterable fields — post type/status/author, `post_date_unix`, taxonomy IDs (`taxonomies..id`), and more for facets / advanced filters * Ranking rules — reorder words / typo / proximity / attribute / sort / exactness; add custom `attribute:asc` / `attribute:desc` * Synonyms, stop words, dictionary — nicknames, brand aliases, noise terms, multi-word tokens * Typo tolerance — enable/disable, min word sizes, disable on numbers / words / attributes * Hybrid Search — embedders and semantic ratio (see above) * View Raw JSON on each group when something looks off * Bulk index / wipe, plus a live search preview before you ship ranking changes **Search Settings** — federated post-type weights (e.g. products above blog posts), optional AJAX autosuggest (with optional form class targeting), optional matched-term highlighting (`.scry-ms-highlight`). **Ops** — task pane, Logs, Search Analytics (see **For developers**). You can go live from these screens alone. Hooks kick in when a project needs something the UI doesn’t cover. = Autosuggest + highlighting (optional front-end extras) = These are the only front-end UI pieces the plugin ships, and both are off by default. Your theme’s results page stays yours either way. **Autosuggest** — Search Settings toggle. The front-end runtime finds forms via CSS selectors (defaults: `#adminbarsearch`, `form[role="search"]`, including the core Search block). Debounced AJAX, same indexes as full search. Optional form class if you only want typeahead on specific forms. Thumbnails when a featured image exists. Extend discovery selectors with `scry_ms_window_localized` — details in DOCS.md. Shape data with `scry_ms_autosuggest_results` or markup with `scry_ms_autosuggest_results_rendered`. **Highlighting** — optional matched-term markup in results / autosuggest (class `.scry-ms-highlight`). Style it in your theme; we don’t force a look. = Indexes and federation = Each registered post type can get its own Meilisearch index (posts, pages, `product`, CPTs). Federated multi-search merges them with your Search Settings weights — not a home-rolled PHP merge. WooCommerce: select `product`, pick product fields/meta, set weights if you also search posts/pages. Catalog search upgrades; theme and checkout stay as they are. = Ops: indexing = * Auto-index on save; remove on trash/delete; re-index on untrash. Bulk index / wipe from Index Settings. * Task pane, Logs, and Search Analytics are covered under **For developers** below (they’re useful for site owners too, but they’re built as day-to-day ops tooling). = For developers = **Full hook reference + JS API:** [DOCS.md on GitHub](https://github.com/jtgraham38/ScryWP-Search/blob/main/DOCS.md) **45 PHP hooks** documented there (filters + actions). Names below; args/returns/timing in the docs. Call sites tagged `//@HOOK: scry_ms_…` in source. **Task pane** — drawer on plugin admin screens for Meilisearch tasks on indexes this plugin owns: status, duration, errors, paginated history. Shared Meilisearch instances won’t dump unrelated tasks. Useful when bulk indexing stalls or a settings update fails silently. **Error / debug logs** — Scry Search → Logs. Debug and Error levels, filterable viewer, DB-backed newest-first with load-more, API keys/tokens redacted before storage, retention + daily cleanup (or clean on demand). Hook `scry_ms_log_message` if you need to divert or annotate lines. **Search analytics** — Scry Search → Search Analytics. Dashboard with summary metrics, charts, and recent searches; optional IP anonymization / omit identifying fields; retention with WP-Cron cleanup; CSV export (admin-only, nonce-protected). Extend rows with `scry_ms_analytics_event_to_insert` (non-column keys go into `search_metadata`, including hybrid usage when enabled). Filters — indexing / documents: * `scry_ms_should_index`, `scry_ms_should_delete`, `scry_ms_index_prepare_document` * `scry_ms_index_names`, `scry_ms_index_searchable_attributes`, `scry_ms_index_filterable_attributes`, `scry_ms_index_filterable_fields` * `scry_ms_index_typo_tolerance`, `scry_ms_index_ranking_rules`, `scry_ms_index_fields`, `scry_ms_index_meta_keys` * `scry_ms_bulk_index_query_args`, `scry_ms_bulk_index_batch_size` Filters — settings: * `scry_ms_index_settings_ajax`, `scry_ms_index_settings_backup` * `scry_ms_index_ranking_rules_before_update`, `scry_ms_index_searchable_attributes_before_update` * `scry_ms_index_synonyms_before_update`, `scry_ms_index_stop_words_before_update` * `scry_ms_index_filterable_attributes_before_update`, `scry_ms_index_dictionary_before_update`, `scry_ms_index_typo_tolerance_before_update` Filters — search / client: * `scry_ms_should_search`, `scry_ms_meilisearch_client` * `scry_ms_multi_search_index_names`, `scry_ms_multi_search_query_params`, `scry_ms_multi_search_query`, `scry_ms_multi_search_queries` * `scry_ms_multi_search_federation`, `scry_ms_multi_search_raw_results`, `scry_ms_multi_search_final_results` Filters — autosuggest / admin / analytics / logs / window: * `scry_ms_autosuggest_query`, `scry_ms_autosuggest_results`, `scry_ms_autosuggest_results_rendered`, `scry_ms_autosuggest_localized` * `scry_ms_admin_pages`, `scry_ms_analytics_event_to_insert`, `scry_ms_log_message`, `scry_ms_window_localized` Actions: * `scry_ms_after_index_document`, `scry_ms_after_delete_document`, `scry_ms_after_bulk_index`, `scry_ms_after_create_index` * `scry_ms_index_settings_restore`, `scry_ms_index_update_settings`, `scry_ms_index_settings_sections_ui` **JS:** `window.scrySearch` (handle `scry_ms_window-script`). Wait for `scrySearchReady`. Forms from `windowLocalized.searchFormSelectors`; filter `scry_ms_window_localized` to add selectors (e.g. `form.my-search`). Per-form pre/post submit + AJAX hooks for custom front-end behavior. Code lives under `features//`. Prefer a search-only key on the front; the client factory supports admin vs search. = Managed hosting (ScryWP) = **Self-hosting is first-class.** Paste any Meilisearch URL and keys into Connection Settings — Docker, bare metal, VPS, or local dev all work the same way. Pick post types, index, ship. When you'd rather not run the search engine itself, [ScryWP](https://scrywp.com) is managed hosting built for WordPress. What you get upfront: * **Engine upkeep** — Meilisearch stays current; you're not tracking release notes or patching prod yourself. * **Monitoring & ops** — health and capacity on the hosting side, so search failures aren't a surprise SSH session. * **Same plugin, same hooks** — identical integration. No forked workflow; federation, hybrid, analytics, and `scry_ms_*` hooks behave the same as self-host. That's the managed value: less infrastructure to operate, not a different product. Choose ScryWP when ops time or handoff complexity isn't where you want to spend budget. Choose self-host or local when you need full control, compliance boundaries, or an offline sandbox. = Hosting options = 1. **[ScryWP](https://scrywp.com)** — managed: patched engine, monitoring, ops handled for you 2. **Self-hosted** — your infrastructure, full control 3. **Local (dev)** — same plugin path, offline or sandbox Paste URL + keys, pick post types, index. Done. = Fits what you already have = * Your theme's `search.php` / results markup — unchanged * `searchform.php`, core search block/widget, page-builder search boxes * WooCommerce products * Custom post types + meta * Headless / custom front via `WP_Query` or REST if you build one == Installation == 1. Have a Meilisearch instance running — self-hosted, local, or [ScryWP](https://scrywp.com) managed (see **Managed hosting (ScryWP)** above). 2. Install and activate the plugin (upload to `wp-content/plugins/` or via Plugins → Add New). 3. Scry Search → Connection Settings: URL, admin key, optional search key; test connection. 4. Scry Search → Index Settings: choose post types, save, Index Posts for each. 5. WordPress search now uses Meilisearch. No theme changes required. 6. Optional: enable autosuggest or highlighting under Search Settings. 7. Optional: open DOCS.md and add your first `add_filter( 'scry_ms_…' )`. You can complete the whole flow from wp-admin without custom code. Hooks are there when you need them. == Frequently Asked Questions == = What makes this developer-friendly? = 45 documented `scry_ms_*` hooks, call sites marked in source, shared client filter, and a real docs file — not a marketing PDF. Plus the tooling you’d actually use on a site: task pane for Meilisearch jobs, error/debug logs, and search analytics (dashboard + CSV). Start here: [DOCS.md](https://github.com/jtgraham38/ScryWP-Search/blob/main/DOCS.md). Optional `window.scrySearch` if you need front-end glue. No forced search results UI. = Can non-developers use it? = Yes. Connect Meilisearch, pick post types, index, tune ranking/synonyms/weights/hybrid/autosuggest from wp-admin. Bring a developer when you need behavior the screens don't cover. = Do I need semantic / AI search? = Optional. Keyword search works without it. Hybrid is in core when you want vector similarity alongside full-text — configure embedders per index, reindex, same results templates. = Do I have to use a frontend UI from the plugin? = No. We don’t own your results page — your theme (or builder) still displays posts from `WP_Query`. Ranking, fields, synonyms, typo tolerance, hybrid, weights, etc. are configured in wp-admin. Autosuggest and highlighting are the optional front-end extras; leave them off and you’re indexing + query routing only. = Do I need to change my theme? = No. Forms and `search.php` (or equivalent) keep working. We swap the query engine, not the markup. Page-builder search boxes that hit WordPress search work the same way. = What is Meilisearch? = Open-source, typo-tolerant search engine: [meilisearch.com](https://www.meilisearch.com/). This plugin assumes you already chose it (or will via ScryWP); we focus on the WordPress integration. = ScryWP or self-host? = **Self-host** (or local dev) when you want full control, compliance boundaries, or you already run Meilisearch elsewhere. **ScryWP** when you'd rather not operate the engine — Meilisearch kept patched and monitored on the hosting side, same plugin integration (paste URL + keys like any instance). Federation, hybrid, and hooks work identically either way. = Custom post types and meta? = Yes. Each selected post type gets its own index. Meta shows up in searchable fields; tweak via admin or `scry_ms_index_fields` / `scry_ms_index_meta_keys` / `scry_ms_index_prepare_document`. = How does federated search work? = Meilisearch multi-search with federation across your indexes, using the weights you set in Search Settings. Adjust the request with `scry_ms_multi_search_*`. = Will this work with WooCommerce? = Yes. Index `product`, choose fields/meta, set weights if you federate with other types. Theme and checkout stay unchanged. = Synonyms, stopwords, dictionary, and typo tolerance? = Yes — per index in the Index Settings dialog (dedicated tabs), no Meilisearch config files required. Also filterable from code when you need that. = Can I configure filterable fields from WordPress? = Yes. The Filterable Fields tab lets you pick core fields, taxonomy IDs, and related attributes. Defaults and the field tree are adjustable with `scry_ms_index_filterable_attributes` / `scry_ms_index_filterable_fields`. = How do I customize with code? = Hook list is under **For developers** above. Common starters: `scry_ms_should_index`, `scry_ms_index_prepare_document`, `scry_ms_meilisearch_client`, `scry_ms_autosuggest_results` / `scry_ms_autosuggest_results_rendered`, `scry_ms_admin_pages`. Full signatures: [DOCS.md](https://github.com/jtgraham38/ScryWP-Search/blob/main/DOCS.md). = JavaScript API? = Optional. Wait for `scrySearchReady`, then `window.scrySearch` + per-form pre/post (and AJAX) hooks. Skip it if you're not doing front-end work. Examples in DOCS.md. = How do I debug indexing? = Task pane for Meilisearch tasks on managed indexes; Scry Search → Logs for plugin debug/error lines (secrets redacted, retention available). See **For developers**. = Can I export analytics? = Yes — Search Analytics includes CSV export, retention/cleanup, privacy options, and `scry_ms_analytics_event_to_insert` for extra fields. Covered under **For developers**. = Is it secure? = AJAX nonces, capability checks, sanitized/escaped I/O. Prefer a search-only API key for front-end paths; the client factory supports `admin` vs `search` keys. == Screenshots == 1. Index Settings Dashboard - Manage post type indexes, view document counts, and trigger indexing operations 2. Index Configuration Modal - Tabbed settings for ranking rules, searchable/filterable fields, synonyms, stop words, dictionary, typo tolerance, and hybrid search embedders 3. Connection Settings - Configure Meilisearch URL and API keys with connection testing 4. Search Settings - Configure post type search weights for federated search, enable AJAX autosuggest, and set the class selector for which forms receive predictive search 5. Task Drawer - Monitor Meilisearch tasks with status, timing, and error details 6. Live Search Preview - Test search queries directly from the admin panel 7. Search Analytics - Dashboard, privacy/retention settings, CSV export of analytics data == Changelog == = 1.5.2 = * Fixed a bug with the updated indexing logic * Enabled filtering of the localization of autosuggest script = 1.5.1 = * Front-end form discovery via CSS selectors (`#adminbarsearch`, `form[role="search"]` by default), including Gutenberg Search block forms * Extend discovery selectors with `scry_ms_window_localized` (`searchFormSelectors`) * Autosuggest class selector limits typeahead to discovered forms that carry a given CSS class on `
` * Window and autosuggest use separate localized JS objects (avoids config collisions) * DOCS.md / README updated for form discovery and autosuggest targeting = 1.5.0 = * Hybrid / semantic search in core — Hybrid Search tab per index with embedder add/edit/delete, semantic ratio, and federated search integration * Embedder definitions backed up in WordPress and restored when an index is recreated; preserved when wiping/reindexing * Search analytics records hybrid usage in `search_metadata` (`scry_search_hybrid`) when hybrid is active * Searchable fields: drag-and-drop reorder (saved as Meilisearch `searchableAttributes` order) * Default searchable attribute order prioritizes title, excerpt, then content * Index settings UI treats Meilisearch `["*"]` searchable attributes as all fields selected * DOCS.md / README updated = 1.4.0 = * Tabbed Index Settings dialog covering ranking rules, searchable fields, filterable fields, synonyms, stop words, dictionary, and typo tolerance * Filterable attributes managed in core — including post taxonomies (`taxonomies..id`) and `post_date_unix` * Custom ranking rules (`attribute:asc` / `attribute:desc`) with drag-and-drop ordering alongside built-in rules * Dictionary and typo tolerance settings (enable/disable, min word sizes, disable on numbers/words/attributes) * View Raw JSON on each settings section for debugging * Settings backup/restore now includes filterable attributes, dictionary, and typo tolerance * New hooks: `scry_ms_index_filterable_attributes`, `scry_ms_index_filterable_fields`, `scry_ms_index_filterable_attributes_before_update`, `scry_ms_index_dictionary_before_update`, `scry_ms_index_typo_tolerance`, `scry_ms_index_typo_tolerance_before_update`, `scry_ms_bulk_index_batch_size` * Bulk indexing processes posts in batches (memory-friendly; batch size filterable) * Setup breadcrumb navigation on admin pages * DOCS.md / README updated for the new index settings surface = 1.3.0 = * New hooks: `should_index`, `should_delete`, `should_search`, `after_index_document`, `after_delete_document`, `after_bulk_index`, `index_names`, `index_searchable_attributes`, `bulk_index_query_args`, `meilisearch_client`, `autosuggest_results`, `autosuggest_results_rendered`, `admin_pages` * Customize how your site displays autosuggest results with the `autosuggest_results_rendered` hook * Documents now include public taxonomy terms; `index_prepare_document` gets `WP_Post` as second arg * Sync on `delete_post` and `untrash_post` * DOCS.md / README updated * Optional matched-term highlighting in results and autosuggest (Search Settings; CSS class `.scry-ms-highlight`) * Autosuggest can show featured-image thumbnails * Analytics: extra keys on `scry_ms_analytics_event_to_insert` stored in `search_metadata` (CSV too) * Premium Upgrades lists Scry Search Hybrid alongside Filters * Index settings restored from WP only when an index is newly created (avoids re-PATCHing Meilisearch every admin load when embedders are set) = 1.2.1 = * Task drawer only lists tasks for indexes this plugin manages * Premium Upgrades page layout/assets fix = 1.2.0 = * Logs screen (debug/error, retention, secret redaction) * More `scry_ms_*` hooks; documented in DOCS.md * `window.scrySearch` JS API * Premium Upgrades admin page * Federated search hit-count fix = 1.1.2 = * Analytics CSV export, retention/cleanup, privacy settings on Search Analytics = 1.0.3 = * Optional AJAX autosuggest (Search Settings toggle + optional class selector) = 1.0.2 = * Synonyms and stopwords from the WordPress admin = 1.0.1 = * ScryWP-hosted Meilisearch support = 1.0.0 = * Initial release: per-post-type indexes, federated search, ranking/searchable fields, auto + bulk indexing, task drawer, live preview, drop-in WP search == Upgrade Notice == = 1.5.2 = Bug fixes and added a new hook. = 1.5.1 = Search forms are discovered by CSS selector; extend the list with `scry_ms_window_localized`, and optionally limit autosuggest by form class. See DOCS.md. = 1.5.0 = Hybrid/semantic search and embedder management are now built into Index Settings, plus draggable searchable-field ordering and analytics for hybrid queries. See DOCS.md. = 1.4.0 = Tabbed Index Settings: filterable fields, custom ranking rules, dictionary, typo tolerance, raw JSON viewers, plus batched bulk indexing and new `scry_ms_*` hooks. See DOCS.md. = 1.3.0 = More developer hooks (indexing/search gates, client factory, autosuggest results, admin tabs), optional highlighting, autosuggest thumbnails, analytics metadata, Hybrid listing, indexing fix for embedder setups. See DOCS.md. = 1.2.1 = Upgrades page updates; task pane fix for multi-tenant Meilisearch. = 1.2.0 = Logs screen and expanded hooks / `window.scrySearch` (see DOCS.md). = 1.1.2 = Analytics CSV export and retention cleanup. = 1.0.3 = Optional AJAX autosuggest under Search Settings. = 1.0.0 = Initial release. == Requirements == * WordPress 5.2 or higher * PHP 8.1 or higher * A Meilisearch instance (ScryWP or self-hosted) == Support == Hooks/docs: DOCS.md or [GitHub](https://github.com/jtgraham38/ScryWP-Search). Issues and questions: same repo or [JG Web Development](https://jacob-t-graham.com).