Skip to content

Product Discovery

Learn how to search, filter, and sort products to help users find exactly what they're looking for.

Product Filtering

Available filtering options:

  • Category filters - categoryId, categorySlug (matches category + subcategories)
  • Price ranges - minPriceInCents, maxPriceInCents (prices in cents)
  • Text search - name, producer, origin, search (full-text)
  • Boolean flags - isSeasonal, isVqa, isKosher, isBuyable
  • Numeric ranges - minAlcoholPercent, maxAlcoholPercent, minVolumeMl, maxVolumeMl

Filter by Category

Using Category ID

Use case: User selects a category from a dropdown or navigation menu.

graphql
query ProductsByCategory($categoryId: String!) {
  products(
    filters: {
      categoryId: $categoryId
      maxPriceInCents: 5000
    }
    pagination: { first: 20 }
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        producerName
        origin
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Variables:

json
{
  "categoryId": "123"
}

Using Category Slug

Use case: Building SEO-friendly URLs like /wine/red-wine.

graphql
query WineProducts {
  products(
    filters: {
      categorySlug: "wine/red-wine"
      maxPriceInCents: 5000
    }
    pagination: { first: 20 }
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        producerName
        thumbnailUrl
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Category Matching

Both categoryId and categorySlug match the category and all its subcategories. For example, filtering by "wine" will return red wines, white wines, sparkling wines, etc.

To search for categories by name, see the Categories & Collections guide.

Filter by Price

Use case: User sets a price range slider or selects "Under $20" filter.

Find products under $20:

graphql
query AffordableProducts {
  products(
    filters: {
      categorySlug: "wine"
      maxPriceInCents: 2000
    }
    pagination: { first: 20 }
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        producerName
        origin
        unitVolumeMl
        thumbnailUrl
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Prices in Cents

All prices are in cents (not dollars). To filter for products under $20, use maxPrice: 2000. To display prices, divide by 100: priceInCents / 100.

Filter by Producer

Use case: User searches for products from their favorite winery or brewery.

graphql
query ProducerProducts($producer: String!, $minPriceInCents: Int!, $maxPriceInCents: Int!) {
  products(
    filters: {
      producer: $producer
      minPriceInCents: $minPriceInCents
      maxPriceInCents: $maxPriceInCents
    }
    pagination: { first: 30 }
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        unitVolumeMl
        alcoholPercent
        thumbnailUrl
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Variables:

json
{
  "producer": "Jackson-Triggs",
  "minPriceInCents": 1000,
  "maxPriceInCents": 3000
}

Filter by Characteristics

Use case: Show only seasonal VQA wines during holiday promotions.

graphql
query SeasonalVQAWines {
  products(
    filters: {
      categorySlug: "wine"
      isSeasonal: true
      isVqa: true
    }
    pagination: { first: 20 }
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        producerName
        origin
        unitVolumeMl
        alcoholPercent
        thumbnailUrl
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Boolean Filters

  • isSeasonal: true - Limited-time seasonal products
  • isVqa: true - VQA (Vintners Quality Alliance) certified wines
  • isKosher: true - Kosher-certified products
  • isBuyable: true - Currently available for purchase

Combined Filters and Sorting

Use case: User searches for "French Chardonnay under $40, sorted by price".

graphql
query ComplexProductSearch {
  products(
    filters: {
      name: "Chardonnay"
      origin: "France"
      minPriceInCents: 1500
      maxPriceInCents: 4000
      isVqa: false
    }
    pagination: { first: 15 }
    sortBy: PRICE
    sortDirection: ASC
  ) {
    edges {
      node {
        sku
        name
        priceInCents
        producerName
        origin
        unitVolumeMl
        alcoholPercent
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Sorting Products

Available sort fields:

  • NAME - Alphabetical by product name
  • PRICE - By price (combine with ASC for low-to-high, DESC for high-to-low)
  • ALCOHOL_PERCENT - By alcohol content
  • VOLUME - By bottle/package size
  • PRICE_PER_ALCOHOL_ML - Best value for alcohol content
  • SELL_RANK_MONTHLY / SELL_RANK_YEARLY - By popularity
  • UPDATED_AT - Recently updated products

Use sortDirection: ASC (ascending) or DESC (descending).

Pagination

Use case: Load more products as user scrolls ("infinite scroll").

graphql
query ProductsPage($after: String) {
  products(
    filters: { categorySlug: "wine" }
    pagination: { 
      first: 25
      after: $after
    }
    sortBy: NAME
  ) {
    edges {
      node {
        sku
        name
        priceInCents
      }
      cursor
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

To load the next page, pass pageInfo.endCursor as the after parameter:

json
{
  "after": "cursor-value-from-previous-response"
}

Pagination Best Practices

  • Product lists: 20-50 items per page
  • Search results: 15-25 items per page
  • Infinite scroll: 25-30 items per load

Always use pageInfo.endCursor and after for consistent results. See Pagination Explained for details on cursor-based pagination.

Next Steps