magenxcommerce / module-quick-search-graph-ql
Quick-search dropdown suggestions for the headless storefront: the store's popular search terms and admin-managed sponsored items (products, categories, brands) with keyword targeting and date windows, served by one quickSearchSuggestions GraphQL query. Replaces magenxcommerce/module-popular-search-
Package info
github.com/magenxcommerce/module-quick-search-graph-ql
Type:magento2-module
pkg:composer/magenxcommerce/module-quick-search-graph-ql
Requires
- php: ~8.3.0||~8.4.0||~8.5.0
- magento/framework: *
- magento/module-backend: *
- magento/module-catalog: *
- magento/module-catalog-graph-ql: *
- magento/module-catalog-inventory: *
- magento/module-config: *
- magento/module-eav: *
- magento/module-graph-ql: *
- magento/module-search: *
- magento/module-store: *
- magento/module-swatches: *
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Built with AI assistance. This module is built with significant use of Claude Code, under active human review and guidance. It is open source and in active development. AI assistance does not lower the engineering bar: every change must meet the same correctness, security, documentation and maintainability requirements as any other contribution.
No warranty. We are not responsible for any incompatibility. By installing this software, you accept responsibility for its security, upgrades, patches and monitoring.
Everything the headless storefront's quick-search dropdown shows before search results come in, served by one GraphQL query:
- Popular search terms. These are the store's most searched phrases, from
Magento's
search_querylog. They render as "Top searches" when the box opens. This part used to be Magenx_PopularSearchGraphQl, which this module replaces (see Migrating). - Sponsored items (promotions). Merchants add products, categories or
brands in an admin grid:
- With an empty search box, general promotions (no keywords) show in the dropdown's top area.
- After a term is typed, promotions whose keywords match it, plus the general ones, show below the product results.
Same discipline as the other Magenx companions: GraphQL plus admin only, no Luma templates, no core module touched.
Schema
{
quickSearchSuggestions(popularTermsCount: Int) {
popular_terms { query_text num_results popularity }
promotions {
id
type # PRODUCT | CATEGORY | BRAND | LINK
title # admin override, else product / category name or brand label
image_url # admin override, else the category image / brand image swatch; null if none
keywords # lower-cased; [] = general
product { uid name url_key image { url label } price_range { … } } # PRODUCT
category_url_path # CATEGORY
brand_label # BRAND (manufacturer option label)
link_url # LINK (storefront path or http(s) URL)
}
}
}
- The store view comes from the
Storeheader. popular_termsandpromotionshave their own resolvers, so a client that selects only one of them never pays for the other.- A disabled part returns
[], never an error.
Popular terms
- Terms must have
is_active = 1,num_results > 0anddisplay_in_terms = 1. The last one is the "Display in Suggested Terms" toggle on Marketing > SEO & Search > Search Terms. Terms are scoped to the store view and ordered bypopularity DESC. - Approval (on by default). Shoppers create and rank
search_queryrows just by searching, so anyone could otherwise push a phrase into every visitor's "Top searches" by repeating it. With Show Only Approved Terms on, a term must also be approved (search_query.magenx_top_search = 1, added by this module). Approve or remove terms with the Approve for Top Searches / Remove from Top Searches mass actions on the stock Search Terms grid; its Top Searches column shows the state. These run under the grid's own ACL,Magento_Search::search, and take effect at once. popularTermsCountis capped at the configured count. When it is omitted, the configured count is used.- One indexed select on
search_query, cached for an hour per store, count and approval setting. - The table fills as shoppers search. Headless GraphQL searches are logged
through the same
Magento\Search\Model\Querypath, so a new store shows nothing until searches build up or terms are added in the admin.
Promotions
- A promotion is either for one store view or for all of them (
store_id0). - Only enabled promotions inside their date window are returned. The window
uses the store's local date, and
active_tois inclusive. Results come insort_order, capped at Maximum Items. - A promotion whose target no longer resolves is dropped silently:
- a product that is disabled, not visible, out of stock or not in the store's website
- a category that is inactive or outside the store's root
- a brand option that was deleted
- a link whose target is not a
/path or an http(s) URL
- The promotion rows are cached per store view in the Magento cache, tagged
magenx_quick_search_promotion. Saving or deleting a promotion cleans the tag. The date window is applied on read, so start and end dates need no cache flush. - Targets are resolved in bulk: at most one product collection, one category
collection and one manufacturer-option lookup per call, whatever the pool
size. The core
ProductInterfaceresolvers price the products for the request's customer group. - Keyword matching happens in the storefront. The whole pool is fetched once per dropdown open, so typing costs no extra request.
Admin
- Marketing > SEO & Search > Quick Search Promotions: the grid with
add, edit, delete and mass delete actions. ACL
Magenx_QuickSearchGraphQl::promotion.- Type / Target: Product = SKU, Link = a storefront path such as
/dealsor a CMS page/summer-sale, or a fullhttp(s)URL. A link needs a title and an image. Category and Brand are picked from selects that the Type switches to: categories in tree order as "Women / Tops (#45)", grouped by store root, andmanufactureroptions as "Label (#id)", both with admin names. The selects are loaded only when the edit form opens. SKUs stay a text field, because a product list would not scale to large catalogs. The grid shows category and brand targets as "Name (#id)", looked up once per page of rows. On save:- the SKU, the category (below a store root) or the brand option must exist;
- a link must not use another scheme or
//host, and must not point at an executable or installer (.exe,.msi,.apk,.dmg,.sh, macro-enabled Office files, ...). That check runs on read too. It can only judge the file name: an extension-less URL that serves a download is not detected.
- Title, Image: optional overrides. The image must be a JPG, PNG, GIF,
WebP or AVIF file of up to 5 MB in
pub/media, given as its path or its full media URL (stored as the path). On save the file must exist and its content must be an image of the type its extension says. SVG is refused. The storefront's image loader serves everything through its/mediaproxy, so images hosted elsewhere cannot work. - Title and Target are capped at 255 characters, Image at 512 and Keywords at 2,000.
- Keywords: comma-separated. Empty means general. A promotion matches a search when the term contains one of its keywords, or a keyword starts with the term (so "sams" already matches "samsung").
- Store View, Active From / To, Sort Order.
- Type / Target: Product = SKU, Link = a storefront path such as
- Stores > Configuration > Magenx > Quick Search
- Popular Search Terms:
magenx_popular_search/general/{enabled,count}, defaults on / 8. These are the old module's paths, kept on purpose. Show Only Approved Terms:magenx_popular_search/general/require_approval, default on. - Promotions:
magenx_quick_search/promotions/{enabled,max_items}, defaults on / 10. On by default because nothing shows until a promotion exists.
- Popular Search Terms:
- Popular terms are curated on the stock Search Terms grid: approve terms for top searches with the mass action, and delete junk terms or untick "Display in Suggested Terms" to hide one.
Data
magenx_quick_search_promotionholds the promotions. Its(store_id, is_active, sort_order)index serves the cache-miss read and backs thestore_idforeign key. Deleting a store view cascades.- Popular terms use the stock
search_querytable. This module adds one column to it,magenx_top_search(the approval flag), and a(store_id, magenx_top_search, popularity)index for the approved-terms read.
Deploy
bin/magento module:enable Magenx_QuickSearchGraphQl
bin/magento setup:upgrade
The storefront needs no particular deploy order: nothing is added to
StoreConfig. The storefront calls quickSearchSuggestions only when the
dropdown opens and fails soft, so a storefront deployed before this module
shows no top searches or promotions and nothing else breaks.
Upgrading to approval. Approval is on by default. On upgrade, a data patch approves the terms each store view showed at that moment, so the storefront doesn't change. Only terms that would newly enter the list wait for approval.
Migrating from Magenx_PopularSearchGraphQl
-
Settings carry over. The popular-terms settings are read from the old
magenx_popular_search/*paths, so nothing needs to be migrated. -
Order matters. The storefront release that switches to
quickSearchSuggestionsalso stops selecting the old module'spopular_search_enabled/popular_search_countStoreConfig fields. Remove the old module only after that storefront release is live. An older storefront still selects those fields, and without the old module Magento rejects its wholeGetStoreConfigquery. -
Both modules can run side by side. This module declares its own type and field names (
quickSearchSuggestions,QuickSearchPopularTerm), so there is no schema clash. -
Removing the old module, once the new storefront is live:
bin/magento module:disable Magenx_PopularSearchGraphQl composer remove magenxcommerce/module-popular-search-graph-ql bin/magento setup:upgrade
Storefront wiring
QUICK_SEARCH_SUGGESTIONS (engine features/catalog/queries.ts) is run by
the browser and is allowlisted in /api/graphql. The header search panels
run it once, the first time the dropdown opens, never on page load. It
selects the lean product fields the dropdown renders. No Turnstile: it is
read-only, cheap, returns admin-curated public data and enumerates nothing.