Item search — global, per-catalogue, and per-category, with optional
scope composition (catalogue_uuids AND category_uuids).
Matches case-insensitively against name, description, sku, and
the multilang data JSONB. Excludes items in deleted catalogues or
deleted categories. Uncategorized items are included unless a
:category_uuids filter narrows the search.
Public surface is re-exported from PhoenixKitCatalogue.Catalogue.
Summary
Functions
Returns the total number of items matching search_items/2's filters.
Ignores :limit/:offset. Same scope opts as search_items/2.
Total match count for search_items_in_catalogue/3.
Total match count for search_items_in_category/3.
Narrows any query with an :item named binding to the items a search
term matches — name, description, SKU, and every translated string in
the record's data.
Categories whose NAME or description matches, within one catalogue.
Searches items with flexible scope.
Searches items within a specific catalogue. Convenience wrapper
around search_items/2 with catalogue_uuids: [catalogue_uuid],
but orders by category position first (then item name) for a stable
walk through a catalogue's categories.
Searches items within a specific category. Convenience wrapper around
search_items/2 with category_uuids: [category_uuid].
Functions
@spec count_search_items( String.t(), keyword() ) :: non_neg_integer()
Returns the total number of items matching search_items/2's filters.
Ignores :limit/:offset. Same scope opts as search_items/2.
@spec count_search_items_in_catalogue(Ecto.UUID.t(), String.t()) :: non_neg_integer()
Total match count for search_items_in_catalogue/3.
@spec count_search_items_in_category(Ecto.UUID.t(), String.t()) :: non_neg_integer()
Total match count for search_items_in_category/3.
@spec match_text(Ecto.Query.t(), String.t() | nil) :: Ecto.Query.t()
Narrows any query with an :item named binding to the items a search
term matches — name, description, SKU, and every translated string in
the record's data.
Public because the attribute filter's FACET COUNTS have to agree with
the list beside them: a value offered as live while a search is on has
to still be live under that search, and it can only promise that by
asking the same question the listing asks. nil or a blank term is
"no text constraint" and leaves the query alone.
Callers pass a raw user string; trimming and LIKE-escaping happen here.
@spec search_categories(Ecto.UUID.t(), String.t(), keyword()) :: [ PhoenixKitCatalogue.Schemas.Category.t() ]
Categories whose NAME or description matches, within one catalogue.
Item search never covered these: searching a catalogue for a category it contains returned nothing, and the page looked like it had matched only because that category's own card happened to be on screen (Max, 2026-08-28).
:parent_uuid narrows to that category's SUBTREE (itself excluded),
mirroring how search_items_in_category/3 scopes items when the user
has drilled in. Deleted categories and categories of deleted
catalogues are excluded, as everywhere else.
@spec search_items( String.t(), keyword() ) :: [PhoenixKitCatalogue.Schemas.Item.t()]
Searches items with flexible scope.
Options
:catalogue_uuids— list of catalogue UUIDs to scope to.nilor[]= all.:category_uuids— list of category UUIDs to scope to.nilor[]= all + uncategorized. Must contain only non-nil UUIDs; passing[nil]raisesArgumentError(use:only => :uncategorized_onlyfor that intent).:include_descendants— whentrue(default since V103), each entry in:category_uuidsis expanded to include every descendant category in the nested-category tree. Passfalseto scope strictly to the given UUIDs.:only—:uncategorized_onlyrestricts to items with nocategory_uuid;:categorized_onlyrestricts to items that belong to some category.nil(default) is unrestricted. Combining:uncategorized_onlywith a non-empty:category_uuidsis a logical contradiction and raisesArgumentError.:statuses— list of item statuses to include ("active","inactive","discontinued").nilor[]= all non-deleted (the historical default). Soft-deleted rows stay excluded even if"deleted"is listed. Atoms are accepted and stringified.:limit— max results (default 50).:offset— paging offset (default 0).:preload— extra associations appended to the default[:catalogue, category: :catalogue]. Pass[catalogue_rules: :referenced_catalogue]for smart-pricing.
@spec search_items_in_catalogue(Ecto.UUID.t(), String.t(), keyword()) :: [ PhoenixKitCatalogue.Schemas.Item.t() ]
Searches items within a specific catalogue. Convenience wrapper
around search_items/2 with catalogue_uuids: [catalogue_uuid],
but orders by category position first (then item name) for a stable
walk through a catalogue's categories.
Same :preload opt as search_items/2 (extra associations appended
to the default [:catalogue, category: :catalogue]).
@spec search_items_in_category(Ecto.UUID.t(), String.t(), keyword()) :: [ PhoenixKitCatalogue.Schemas.Item.t() ]
Searches items within a specific category. Convenience wrapper around
search_items/2 with category_uuids: [category_uuid].