Skip to content

Add filters, sort and pagination to the collection route using Pilot's composable model #78

Description

@hta218

Problem

Filters only exist on /shop. Collection routes (/shop/<collectionHandle>) have none.

/shop (src/app/shop/page.tsx) is a hand-written theme-owned page: it parses category, activity and sort from searchParams, builds filterGroups, and renders FilterSidebar + ProductResults off storefront.listProducts(filter, sort).

/shop/[collectionHandle]/page.tsx renders nothing of its own — it hands everything to WeaversePage. It receives searchParams but forwards them untouched to loadWeaversePage() (used only for Weaverse preview/version resolution); no filter or sort is parsed. storefront.getCollectionProducts(handle) takes only a handle, so there is no seam to pass a filter through in the first place. collection-grid (src/sections/collection-grid/index.tsx) reads collectionProducts from context and maps the whole array — no toolbar, no facets, no pagination.

Root cause: the architecture treats collection grid behavior as theme-owned and not a section, but the collection route delegates 100% of its rendering to Weaverse. Nothing is left holding the filter state.

Reference: how Pilot does it

pilot/app/routes/collections/collection.tsx

  • The loader owns filter state. It reads sort via getSortValuesFromParam() and collects every searchParams entry prefixed with FILTER_URL_PREFIX into a ProductFilter[], then passes filters, sortKey and reverse straight into COLLECTION_QUERY as GraphQL variables. Filtering happens server-side in Shopify, not in app code.
  • Facets come from Shopify: collection.products.filters returns the available Filter[] per collection (including PRICE_RANGE). The loader resolves appliedFilters labels against those values.
  • The page is a composable section tree:
    • main-collection -> mc--header, mc--toolbar, mc--content
    • mc--content -> mc--filters + mc--product-grid
  • Filter interaction is client-side over the URL: useSearchParams() + navigate(link, { preventScrollReset: true }) (filters/filter-item.tsx), so the URL is the source of truth and the loader re-runs.
  • Pagination uses Hydrogen <Pagination> with getPaginationVariables(request, { pageBy: 12 }), with infinite-scroll or load-more as a merchant setting.

Scope

  • Extend the storefront data boundary: getCollectionProducts(handle, filter?, sort?) returning products plus the Shopify facets (filters) and applied-filter labels. Static adapter must return an equivalent shape.
  • Parse sort and the filter-prefixed params in src/app/shop/[collectionHandle]/page.tsx and pass the resolved products, facets and applied filters through dataContext.
  • Add the section tree: main-collection shell with mc--header / mc--toolbar / mc--content, and mc--filters + mc--product-grid under content. Register them in src/lib/weaverse/components.ts.
  • Sort control and product count in the toolbar; mobile filter drawer.
  • Pagination or load-more on the grid (getCollectionProducts currently returns the full array).
  • Decide what happens to collection-grid — replaced by mc--product-grid, or kept for non-filtered use.
  • Run bun run check:graphql after touching any gql() document.

Architecture decision needed

AGENTS.md currently states:

Functional, stateful, and security-owned surfaces are not sections and stay theme-owned: the collection and Shop grid behavior, Cart, and /account/**.

Pilot's model does the opposite — filters and the product grid are sections with merchant-facing settings (sidebar width, expand, swatches, load-more behavior). Adopting it requires amending that constraint in AGENTS.md, keeping the filter state in the URL and owned by the route while the sections stay presentational.

Files touched

  • src/app/shop/[collectionHandle]/page.tsx
  • src/lib/storefront/data-source.ts, src/lib/storefront/types.ts, src/lib/storefront/shopify/*
  • src/sections/collection-grid/ (replace or refactor)
  • new src/sections/main-collection/**
  • src/lib/weaverse/components.ts, src/lib/weaverse/data-context.ts
  • AGENTS.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

  • Status
    In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions