Skip to content

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.

  • Variant price mapping

    • BaseField.variantPrice now compiles to Shopify’s documented price field.
    • Example: a DSL rule variantPrice between 10 and 20 compiles to price:>=10 price:<=20.
    • Covered by compileToShopifyQuery and filters.compile.test.ts ("maps variantPrice equals to price field").
  • Variant-only fields

    • variantName (variant title = combined option values), variantOption1/2/3 (individual option values), and variantPosition never compile into Shopify search tokens.
    • They are evaluated only by local logic (matchesVariantRule / matchesVariantFilter in bulkEditPreview.ts) for:
      • Preview.
      • Variant-level actions (price, SKU, barcode, variant add/delete/edit/replace).
    • Verified by tests that expect compileToShopifyQuery to 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.).
    • compileToShopifyQuery still returns metafieldRules alongside the query, but product selection is entirely driven by the compiled query string passed to products.
    • Net effect: metafield filters now truthfully limit which products are edited.
  • Status and multi-value syntax

    • Multi-status filters (e.g., "ACTIVE", "DRAFT") use the comma form status:ACTIVE,DRAFT instead of OR chains, matching Shopify examples.
  • 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.
  • 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”).
  • Execution

    • ActionConfig stores only the variant filter DSL per action type (for example, priceVariantFilter, skuVariantFilter, variantDeleteFilter, variantEditFilter).
    • convertActionConfigsToBulkEditActions passes these through as { dsl: FilterDSL } without a separate selection object.
    • filterVariants applies:
      • Variant filter (variantFilter.dsl via matchesVariantFilter) to decide which variants are edited.
    • Covered by:
      • tests/variantSelection.test.ts (variant filter + filterVariants behavior).
      • Runner and preview code paths in bulkEditPreview.ts and bulkEditRunner.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 fetchProductStatus and log errors if the status does not match.
  • Product create (productCreate)

    • Helper:
      • productCreate in adminMutations.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, variants with optionValues, price, compareAtPrice, inventoryItem.sku, barcode).
  • Metafields

    • Set:
      • metafieldsSet(metafields: [MetafieldsSetInput!]!) with ownerId, namespace, key, type, value.
    • Delete:
      • metafieldDeleteByKey:
        • Lookup metafield by owner/namespace/key.
        • Call metafieldsDelete(metafields: [MetafieldIdentifierInput!]!).
  • 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 productSet to replace options + variants, with a post-pass media update if enabled.

4. Test coverage snapshot

  • Unit tests

    • filters.compile.test.ts:
      • Confirms variantPriceprice.
      • Validates metafield rule compilation and that variant-only fields do not appear in compiled queries.
    • variantSelection.test.ts:
      • Confirms selection wiring for all modes (including 1-based “By number”).
      • Exercises filterVariants and matchesVariantFilter for All/First/Last/ByIndex/ByOption.
    • adminMutations.test.ts:
      • Verifies productUpdate, productCreate, and metafieldsDelete helpers use the new schema shapes.
  • 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.