Skip to main content

AJAX Live Search

Overview​

AJAX Live Search replaces WooCommerce's search box with one that answers while the customer types. Results come from the module's own index table rather than from a LIKE query against posts, so matching is fast and the index can be weighted.

Three things make the matching better than a plain search. The index stores title, content, SKU and terms separately, so a store can decide what is searched. Synonyms map a term a customer types to the terms the catalogue uses. And fuzzy matching tolerates a misspelling, with a configurable threshold.

Searches are logged with their result counts, and a click on a result is recorded against the search that produced it — which is what makes "what did people search for and did they find it" answerable.

It is for stores whose catalogue is too large to browse.

Availability​

ItemValue
Module keysearch
TierPremium
Entitlement keysearch
Admin tabsearch
Enabled optionaiowc_module_enabled_search (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the three tables below and schedules the index rebuild and log cleanup jobs.

registerHooks() performs no licence check of its own; the module registry applies the entitlement gate centrally before calling it.

Settings​

Stored in the bundled option row aiowc_als_settings.

Stored keyDefaultMeaning
min_chars2How many characters before a search fires.
max_results10How many results the dropdown shows.
search_intitle,content,skuWhich indexed fields are searched, as a comma-separated list.
fuzzy_enabledtrueWhether a near-miss still matches.
fuzzy_threshold70How close a near-miss must be, as a similarity percentage.
debounce_ms300Milliseconds waited after a keystroke before searching.
show_imagestrueWhether results show a product image.
show_pricestrueWhether results show a price.
show_categoriestrueWhether results show the product's category.

search_in is the setting worth understanding: dropping content makes search much stricter and usually more precise, since a word appearing anywhere in a long description no longer counts as a match.

The index​

Each indexed row holds the object type and id, its title, content, SKU and terms, and a weight — so a product can be promoted or demoted in results without changing its content.

Matching uses MySQL's own full-text index, in boolean mode, and results are ordered by the full-text relevance score multiplied by the row's weight. A SKU lookup and a title lookup are handled as separate prefix and substring queries, so a customer typing a part number is not at the mercy of word-based relevance. This means the module needs a database whose storage engine supports full-text indexing on the index table.

The index is maintained incrementally: the module hooks woocommerce_new_product, woocommerce_update_product, woocommerce_trash_product and before_delete_post, so a product edited in the admin is re-indexed straight away rather than waiting for the rebuild job. The job is the safety net, not the mechanism.

Synonyms​

A synonym row maps a term to a list of alternatives, stored as JSON. This is how "sofa" finds "couch", or how a customer's word for a product finds the manufacturer's. Synonyms are managed through their own routes.

Search analytics​

Every search writes a row with the query, the result count, the session and — when signed in — the user. POST /search/click then records which product was opened from that search, tying the outcome back to the query.

A search with results that nobody clicks is a different problem from a search with no results, and the two are distinguishable here.

Admin screen​

The Search tab shows an overview and the search analytics, manages synonyms, reports index statistics, triggers a rebuild, and edits the nine settings.

REST API endpoints​

All routes are on aiowc/v1 and answer with the { success, data, message } envelope.

MethodPathPurposePermissionRequired args
GET/searchSearch the index (q).Public, rate-limitedq
GET/search/suggestionsSuggestions for a partial query.Public, rate-limited–
POST/search/clickRecord which result was opened.Public, rate-limitedlog_id, product_id
GET/search/analyticsQueries, counts and click-through.manage_woocommerce–
GET/search/overviewSummary of search activity.manage_woocommerce–
GET/search/index/statsIndex size and freshness.manage_woocommerce–
POST/search/index/rebuildRebuild the index now.manage_woocommerce–
GET/search/synonymsEvery synonym.manage_woocommerce–
POST/search/synonymsAdd a synonym.manage_woocommerceterm, synonyms
DELETE/search/synonyms/{id}Remove a synonym.manage_woocommerceid
GET / PATCH / PUT / POST/search/settingsRead and write the settings.manage_woocommerce–

/search/click is a public write, which is unusual but necessary: the click happens in the customer's browser, and it carries only a log id and a product id.

WooCommerce integration​

HookWhat the module does
get_search_form, get_product_search_formReplaces the search form with the live one.
woocommerce_before_shop_loopRenders the search box above the catalogue.
woocommerce_no_products_foundOffers suggestions when a search returns nothing.
woocommerce_product_query_meta_queryApplies the search to the product query.
woocommerce_new_product, _update_product, _trash_product, before_delete_postKeeps the index in step with the catalogue.
the_titleUsed when rendering results.
wp_enqueue_scripts, wp_footerLoads the search assets and the results container.

The module registers no shortcode — the search box is placed by replacing WordPress's own search form, not by being dropped into a page.

Database schema​

TableHolds
{prefix}aiowc_search_indexThe searchable copy of each product: type and id, title, content, SKU, terms, and a weight.
{prefix}aiowc_search_synonymsTerm-to-alternatives mappings, stored as JSON.
{prefix}aiowc_search_logEvery search: the query, result count, session, user, and the product clicked from it.

Background jobs​

HookWork
aiowc_search_index_rebuildRebuilds the whole index, as a safety net behind the live updates.
aiowc_search_log_cleanupPrunes old search log rows.

Both run on Action Scheduler.

Action hooks for integrators​

HookFired when
aiowc_track_eventThe module is enabled or disabled.
aiowc_capture_errorAn error is caught during indexing or search.

The module exposes no filter for adjusting relevance or result ordering.

Entitlement limits​

search is an on/off grant with no cap on the index, synonyms or log rows.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive, and otherwise reports that it is functioning normally. A disabled module reports that it is disabled.

Known gaps​

  • Two search modules ship and both maintain their own index. This one and Smart Product Search each keep a separate index, a separate query log and a separate rebuild job. Running both means indexing the catalogue twice and collecting two incomplete pictures of what customers searched for. A store should pick one.
  • The log-cleanup job has no retention setting — unlike the two analytics modules, how long search logs are kept is not exposed as an option.
  • Search queries are stored with a session id and, for signed-in customers, a user id. That is behavioural data about identifiable people and belongs in the store's privacy notice.
  • There is no relevance filter, so result ordering can only be influenced through the per-row index weight.
  • weight is on the index row but there is no route or screen for setting it, so promoting a product means writing to the table directly.