Appearance
Filters, Variants, and Actions – Implementation Status (Post–Workstreams A–C)
This document captures the current, implemented behavior of filters, variant targeting, and bulk actions, based on the code on staging plus docs/1001, docs/1002, and docs/1003.
1. Filters and DSL → Shopify search
Variant price mapping
BaseField.variantPricenow compiles to Shopify’s documentedpricefield.- Example: a DSL rule
variantPrice between 10 and 20compiles toprice:>=10 price:<=20. - Covered by
compileToShopifyQueryandfilters.compile.test.ts("maps variantPrice equals to price field").
Variant-only fields
variantName(variant title = combined option values),variantOption1/2/3(individual option values), andvariantPositionnever compile into Shopify search tokens.- They are evaluated only by local logic (
matchesVariantRule/matchesVariantFilterinbulkEditPreview.ts) for:- Preview.
- Variant-level actions (price, SKU, barcode, variant add/delete/edit/replace).
- Verified by tests that expect
compileToShopifyQueryto produce an empty query when only variant-only fields are present.
Metafield filters
- Metafield rules (
type: "metafield",namespace,key,operator,value) are compiled into search tokens:metafields.{namespace}.{key}:{value}, with appropriate operator handling (equals,contains,in,exists, etc.).
compileToShopifyQuerystill returnsmetafieldRulesalongside thequery, but product selection is entirely driven by the compiled query string passed toproducts.- Net effect: metafield filters now truthfully limit which products are edited.
- Metafield rules (
Status and multi-value syntax
- Multi-status filters (e.g.,
"ACTIVE","DRAFT") use the comma formstatus:ACTIVE,DRAFTinstead of OR chains, matching Shopify examples.
- Multi-status filters (e.g.,
Synced reference dropdowns
- Collections, vendors, and product types share the same synced reference-data pattern (snapshot table + list/sync routes + support hooks).
- Filter dropdowns show helper text with a Sync button (plus last-synced tooltip) so merchants can refresh the options in-place.
- Collection actions reuse the same selector; automated collections stay disabled with explanatory tooltip, while manual collections remain selectable.
2. Variant targeting behavior (Variant filter per action)
Two-step mental model
- Step 1 – Product filter (Filter products card): decides which products enter the job.
- Step 2 – Variant filter (per action): decides which variants on each matching product are edited.
Default behavior
- For variant-aware actions (Price, SKU, Barcode, Variants & Options: Add/Edit/Delete/Clone), the card shows:
Variants to edit: All variants on each matching product [Change].
- If the merchant never clicks Change, the job edits all variants on each matching product with no variant filter.
- For variant-aware actions (Price, SKU, Barcode, Variants & Options: Add/Edit/Delete/Clone), the card shows:
Variant filter layout
- Inside Change:
- Uses a variant-only DSL builder so only variant-level fields (variant title, option values, position, SKU, barcode, price) are available.
- Common patterns:
- All variants on each product: leave the variant filter blank.
- By number: add rule Variant position equals N (1 = first, 2 = second, …).
- By option: add rule(s) Variant option 1/2/3 equals … (for example, Option 2 (usually Color) equals “Red”).
- Inside Change:
Execution
ActionConfigstores only the variant filter DSL per action type (for example,priceVariantFilter,skuVariantFilter,variantDeleteFilter,variantEditFilter).convertActionConfigsToBulkEditActionspasses these through as{ dsl: FilterDSL }without a separate selection object.filterVariantsapplies:- Variant filter (
variantFilter.dslviamatchesVariantFilter) to decide which variants are edited.
- Variant filter (
- Covered by:
tests/variantSelection.test.ts(variant filter +filterVariantsbehavior).- Runner and preview code paths in
bulkEditPreview.tsandbulkEditRunner.server.ts.
3. Bulk actions and GraphQL helpers
Product update (
productUpdate)- Helpers:
updateProductTitleSeo– title, SEO title, SEO description.updateProductVendorTypeStatus– vendor, productType, status.
- Mutation shape:
mutation UpdateProduct($product: ProductUpdateInput!) { productUpdate(product: $product) { userErrors { field message } } }
- Status update flow:
- Map
"active" | "draft" | "archived"→"ACTIVE" | "DRAFT" | "ARCHIVED". - Call
updateProductVendorTypeStatus. - Verify via
fetchProductStatusand log errors if the status does not match.
- Map
- Helpers:
Product create (
productCreate)- Helper:
productCreateinadminMutations.server.ts.
- Mutation shape:
mutation ProductCreate($product: ProductCreateInput!) { productCreate(product: $product) { product { id } userErrors { field message } } }
- Payload:
- Maps CSV-derived fields into
ProductCreateInput(title,vendor,productType,tags,variantswithoptionValues,price,compareAtPrice,inventoryItem.sku,barcode).
- Maps CSV-derived fields into
- Helper:
Metafields
- Set:
metafieldsSet(metafields: [MetafieldsSetInput!]!)withownerId,namespace,key,type,value.
- Delete:
metafieldDeleteByKey:- Lookup metafield by owner/namespace/key.
- Call
metafieldsDelete(metafields: [MetafieldIdentifierInput!]!).
- Set:
Variant-level mutations
- Use modern bulk variants APIs:
productVariantsBulkCreate(productId, variants: [ProductVariantsBulkInput!]!).productVariantsBulkDelete(productId, variantsIds: [ID!]!).productVariantsBulkUpdate(productId, variants: [ProductVariantsBulkInput!]!).
- All price/SKU/barcode and variant add/delete/edit operations are routed through these helpers.
- Clone uses
productSetto replace options + variants, with a post-pass media update if enabled.
- Use modern bulk variants APIs:
4. Test coverage snapshot
Unit tests
filters.compile.test.ts:- Confirms
variantPrice→price. - Validates metafield rule compilation and that variant-only fields do not appear in compiled queries.
- Confirms
variantSelection.test.ts:- Confirms selection wiring for all modes (including 1-based “By number”).
- Exercises
filterVariantsandmatchesVariantFilterfor All/First/Last/ByIndex/ByOption.
adminMutations.test.ts:- Verifies
productUpdate,productCreate, andmetafieldsDeletehelpers use the new schema shapes.
- Verifies
Playwright (
tests/**/*.pw.spec.ts)tests/bulk-tasks/*.pw.spec.ts:- Exercise the single-action editor (Tags/Price/Metafield) plus filter builder + task controls.
tests/bulk-variants/variant-actions.pw.spec.ts:- Covers variant add/edit/delete/replace using variant filters (position, options) to target specific variants.
tests/non-bulk/filters-and-usage.pw.spec.ts&tests/non-bulk/csv-flows.pw.spec.ts:- Validate OR/NOT filter combinations, variant filter helper copy, usage page developer tools, and CSV export/import flows.
This document should be used alongside docs/1001_variant-simplifaction.md (UX and mental model) and docs/1003_filters-variants-actions-workstreams.md (planning) as the up-to-date reference for how filters, variants, and actions actually behave in the shipped app.