PlutocracyMercury developer docs

Filters and sorting

The `query` filter format the collection, search and zone routes accept, how clauses combine, the facet counts, and the sort names, including Shopify's.

Filtering collection, search and zone results

The collection, search and zone routes take filters in one query parameter, query: a JSON array of clauses, URL-encoded.

const query = [
  { type: 'tag', condition: 'equals', value: ['linen', 'cotton'] },
  { type: 'min_price', condition: 'between', value: ['20', '100'] },
];
const url = `https://mercury.plutocracy.io/search/query/shirt?take=24&query=${encodeURIComponent(JSON.stringify(query))}`;

Each clause has a type, a condition, a value array of strings, and an optional disjunctive flag. If query is not valid JSON or not an array, it is ignored, so a bad filter never empties a page. A single clause that can't be used (no type, an empty value, a number that isn't one, an unknown type) is skipped and the rest still apply.

typeMatchesConditions
tagShopify product tagsequals, contains (the same for tags), not_equals, not_contains
vendor, type, titletext fieldsequals and not_equals match the exact phrase; contains and not_contains match words
idproduct ids(none; an empty list matches nothing)
min_price, variant_pricethe product's lowest price, in major units ("49.95")less_than, more_than (or greater_than), between, equals
variant_compare_at_pricethe lowest compare-at price, in major unitsas above
pricethe lowest price, in cents ("4995"): the kit's own operatoras above
total_stocktotal inventoryas above
variant_inventorytotal inventory above the value(none)
is_price_reducedproducts on saleis_not_set inverts it
fuzzytitle words within one typo(none)

Conditions are lowercase: BETWEEN is not understood. Two values with no condition mean between.

How clauses combine

  • Values within a clause are ORed: tag equals [linen, cotton] matches either tag. Set "disjunctive": false on the clause to require all of them.
  • Clauses are ANDed, except that a clause with "disjunctive": true is ORed with the clause before it. That is how a sidebar expresses "(colour red OR blue) AND size M".

Custom facet types a store defines in its grid config are not filter types here: filter them with the tag the facet is built from.

Facets

Every page response includes facets: counts for the tags, vendors and types in the result set, which a sidebar renders as checkboxes. The store's grid config (send grid_config=1) maps raw tags to facet groups, colours and sizes.

Sorting

Send sort with one of Mercury's sort names:

sortOrder
newestcreated date, newest first
oldestcreated date, oldest first
az, zatitle
priceLow, priceHighlowest price
manual, best-sellingthe collection's own order (collections only)
randomcollections: the page is shuffled after fetching. Search: the same as newest

On search, no sort (or a name not in this table) gives relevance order.

Sorting collections

  • With no sort, a collection uses its own Shopify sort order, translated: alpha-asc → az, alpha-desc → za, created-asc → oldest, created-desc → newest, price-asc → priceLow, price-desc → priceHigh, and manual and best-selling → the collection's order. The response's sort_order is reported in Mercury's names.
  • ?sort= only understands Mercury's names. A Shopify name (or anything unknown) falls back to the collection's manual order, so translate before you send.

Zones are ordered by the zone itself: the merchant's picks, or the collection's own order for a collection zone.

Shopify's sort names

Shopify themes use their own names (price-ascending, title-descending, created-descending...). The routes only understand Mercury's names in ?sort=, so translate in your theme. A Shopify name sent as-is is not an error: it gives relevance order on search and manual order on a collection.

const toMercury = { 'price-ascending': 'priceLow', 'price-descending': 'priceHigh', 'title-ascending': 'az',
  'title-descending': 'za', 'created-ascending': 'oldest', 'created-descending': 'newest', 'manual': 'manual',
  'best-selling': 'best-selling' };
const sort = toMercury[shopifySort]; // undefined: leave sort out (relevance on search, the collection's own order)