Ana içeriğe geç

Introduction

One query across your whole project - products, pages, blocks, forms, orders and more, grouped by entity type.


🎯 What does this module do?

The Search module wraps the public cross-entity search endpoint. You pass a text query and get back every record whose name or attribute value matches it, from 18 entity types at once, grouped per type and annotated with how each record matched.

Use it to power a global "search everything" box - the kind that shows a few products, a couple of pages and a matching form in one dropdown - and then drill down into a single type when the user asks for more.

This is keyword search: it matches on the literal text of titles, identifiers, urls and attribute values. For meaning-based search (a query like "warm jacket for winter" matching a product named "Insulated parka"), use the semantic search of the individual modules - see Vector search vs global search below.

🚀 Quickstart

Initialize the module from defineOneEntry:


const { Search } = defineOneEntry(
"your-project-url", {
"token": "your-app-token"
}
);

Search everything, then walk the groups:

// Search every entity type for "winter".
const result = await Search.globalSearch('winter');

console.log(result.query); // "winter"

result.groups.forEach((group) => {
console.log(group.type, group.items.length, group.hasMore);

group.items.forEach((item) => {
console.log(item.id, item.title, item.matchKind, item.fragment);
});
});

✨ Key Concepts

Groups

The response is not a flat list. It is { query, groups }, where every group holds the records of one entity type:

{
query: "winter",
groups: [
{ type: "products", items: [ /* … */ ], hasMore: false },
{ type: "pages", items: [ /* … */ ], hasMore: false }
]
}

hasMore tells you whether more records of that type exist beyond the returned page - the cue to offer a "show all products" link that re-runs the query in drilldown mode.

Match context

Every item carries the context of how it matched, so you can render a meaningful result row instead of a bare title:

FieldWhat it tells you
matchKindRanking kind of the match: exact, title, attributeName or attributeValue
matchedFieldThe concrete field that matched: id, title, identifier, url, attributeName, attributeValue, importId, nodeName
matchedAttributeThe attribute the match happened in (when the match came from an attribute)
fragmentPlain-text context around the match, with no markup - highlight it yourself
langCodeLanguage of the matched value, so you can label cross-language hits
parentThe owning record for entities that have no page of their own (a slide → its block, an order → its storage)

Entity types

types narrows the search. Pass any of these, and the SDK sends them comma-separated:

products, pages, blocks, slides, templates, discounts, user_groups, users, admins, menus, forms, attributes_sets, attributes, orders, workflows, events, subscriptions, collections.

Omit types to search all of them.

Drilldown mode

offset and limit switch the endpoint into drilldown mode - paging through one entity type instead of previewing all of them.

⚠️ They are accepted only together with exactly one accessible type in types. Any other combination answers 400 - Drilldown mode (limit/offset) requires exactly one accessible type in types.

The SDK does not default them: omit both and every group comes back in full.

// Overview: every type, every group complete.
const overview = await Search.globalSearch('winter');

// Drilldown: page 1 of the products only.
const products = await Search.globalSearch('winter', ['products'], 'visible', 0, 20);

Visibility

visibility filters the searched records: 'all' (default), 'visible' or 'hidden'.

📋 What You Need to Know

  • id is a number for most types, a string for workflows and attributes - number | string, so don't assume numeric ids when building keys or urls.
  • title is optional: records with no name of their own (orders, users without a login) come back without it. Fall back to identifier or subtitle.
  • subtitle carries the secondary line the type happens to have - a page url, an order storage, a node name.
  • attributeSetId is present only for type: "attributes", pointing at the set the attribute belongs to.
  • Only records the current caller may see are returned; the search respects the same access rules as the rest of the API.

📊 Quick Reference Table

MethodDescription
globalSearch()Search names and attribute values across all entity types

Both find records from a text query, but they answer different questions:

globalSearchget…ByVectorSearch
Matches onThe literal text of titles, identifiers, urls and attribute valuesMeaning - a semantic (vector) similarity
Scope18 entity types in one callOne module per call
Returns{ query, groups[] } - grouped by type{ items, total } - a flat container
Typical useA global search box / command palette"Find me something like this" over one entity

The semantic counterparts live in the modules themselves: products, pages, users, orders, discounts, admins and form data.

❓ Common Questions (FAQ)

Why is my offset / limit answered with a 400?

Because they only work in drilldown mode. Pass exactly one accessible entity type in types alongside them, or drop them entirely.


How do I highlight the match in the UI?

Use fragment - it is the plain-text context around the match, deliberately free of markup, so you can highlight the query in it yourself without sanitizing anything.


An item has no title. Is that a bug?

No. Orders and users without a login have no own name, so title is simply absent. Render identifier, subtitle or a type-specific label instead.


Can I search hidden records?

Pass visibility: 'hidden' (or 'all') - subject to the access rules that apply to the caller.


🎓 Best Practices

  • Debounce the query in a search-as-you-type box: every keystroke is a request.
  • Show the overview call first (no offset/limit), then switch to drilldown when the user picks a type - that is exactly what hasMore is for.
  • Narrow types to what your UI can actually render; searching 18 types to display 2 is wasted work.
  • Treat id as number | string when building links and React keys.