Skip to main content

Feature: Reusable Collection Overrides Editor with Shopify Collection Picker

Status: Planned

Context

UI component settings (collection page image, swatches, subcollections) are currently global — they apply to all collections. Merchants need per-collection control (e.g., hide the collection image on "Men's Innerwear" but show it on "Socks"). Danyil's PR #3019 added a basic inline collection overrides pattern for swatches with manual handle entry.

This plan extends that into a proper reusable modal-based editor with a Shopify collection picker, usable by any settings section.

Interim workaround: Collection overrides can be pushed manually via the settings API. The collectionOverrides array on any UI component follows the same resolveCollectionSetting() pattern from storefront_search/src/vue/collection-overrides.ts.

Example — disable collection image for specific collections via API:

# Fetch current settings
curl -s -H "Authorization: Bearer {key}" \
"https://admin.ecom.marqo.ai/api/v1/storefront/shops/{domain}/settings" > settings.json

# Edit collection_page_config.value.collectionOverrides in settings.json:
# {
# "collectionOverrides": [
# { "collections": ["mens-innerwear"], "showImage": false },
# { "collections": ["socks", "hats"], "showDescription": false }
# ]
# }

# Push updated settings
curl -s -X POST -H "Authorization: Bearer {key}" -H "Content-Type: application/json" \
-d @settings.json "https://admin.ecom.marqo.ai/api/v1/storefront/shops/{domain}/settings"

The storefront widget reads these via resolveCollectionSetting() — first matching rule wins, unmatched collections use global defaults.

Admin UI Design

UX: Modal with Shopify collection picker

Each settings section that supports overrides has a "Collection Overrides (N)" button that opens a modal:

List page:

┌─ Collection Overrides ─────────────┐
│ │
│ ┌ Men's Innerwear ──────── [✎] ┐ │
│ │ showImage: false │ │
│ └───────────────────────────────┘ │
│ ┌ Socks ────────────────── [✎] ┐ │
│ │ showDescription: false │ │
│ └───────────────────────────────┘ │
│ │
│ [+ Add Override] [Done] │
└────────────────────────────────────┘

Add/Edit page:

┌─ Add Collection Override ──────────┐
│ │
│ Collection: │
│ ┌──────────────────────────────┐ │
│ │ 🔍 Search collections... │ │
│ ├──────────────────────────────┤ │
│ │ Men's Shirts & Polos │ │
│ │ Men's Innerwear │ │
│ │ Socks │ │
│ └──────────────────────────────┘ │
│ │
│ Show Image: [toggle] │
│ Show Description: [toggle] │
│ │
│ [Cancel] [Save] │
└────────────────────────────────────┘

Reusable Component: CollectionOverrideEditor

A headless modal component that any settings section can embed:

interface CollectionOverrideEditorProps<T extends Record<string, unknown>> {
overrides: Array<{ id: string; collections: string[] } & T>;
onUpdate: (overrides: Array<{ id: string; collections: string[] } & T>) => void;
renderFields: (override: T, onChange: (updates: Partial<T>) => void) => React.ReactNode;
newOverrideDefaults: T;
label?: string;
}

Parent component provides override-specific fields as a render prop. The shared component handles collection picking, CRUD, and modal navigation.

Implementation

Backend

New endpoint: GET /api/v1/storefront/shops/{domain}/collections

  • Authenticates via API key
  • Queries Shopify Admin API with existing LIST_COLLECTIONS GraphQL query
  • Returns { collections: [{ handle, title }] }

GraphQL query already exists: admin_server/graphql/queries/collection_queries.py:LIST_COLLECTIONS

Admin UI

FileChange
admin_server/routes/storefront_routes.pyNew collections list endpoint
storefront_admin/app/lib/api-client.tsAdd listCollections() method
storefront_admin/app/components/ui/collection-override-editor.tsxReusable modal editor (NEW)
storefront_admin/app/components/settings/collection-page-section.tsxFirst consumer
storefront_admin/app/lib/types.tsAdd CollectionPageOverrideRule
storefront_admin/app/lib/settings-converter.tsCollection page overrides conversion

Storefront Widget

Uses existing resolveCollectionSetting() from collection-overrides.ts (Danyil's PR #3019). Each render function that reads component settings calls resolveCollectionSetting() to check for per-collection overrides.

Future consumers

Once the shared editor is built, migrate:

  • Swatch overrides (currently inline in product-display-section.tsx)
  • Subcollection settings per parent collection
  • Any future component that needs per-collection behavior