← back to Newmor Onboard

artifacts/METAFIELD-MAP.md

50 lines

# Newmor → Shopify spec→METAFIELD mapping (TK-10670)

HARD RULE (Steve, 2026-08-18): **all spec/metafield info goes into Shopify METAFIELDS, never body_html.**
`body_html` stays clean marketing prose only. This map is the enforcement contract for the
(gated) publish/backfill.

Source: `newmor_catalog` columns → Shopify metafield. Namespace defaults to `custom.*`;
FINAL namespace/keys must be reconciled against the existing DW live metafield schema
(verify from a live Newmor/commercial product in cycle 2 before any write) so we don't fork keys.

| catalog column        | Shopify target                    | metafield type          | notes |
|-----------------------|-----------------------------------|-------------------------|-------|
| width / width_inches  | `custom.width`                    | dimension               | coverage 787/1294 — gap |
| length                | `custom.roll_length`              | dimension               | coverage 1045/1294 |
| coverage              | `custom.coverage`                 | single_line_text_field  | EMPTY (0) — needs refresh |
| repeat_v              | `custom.pattern_repeat_vertical`  | dimension               | EMPTY (0) — needs refresh |
| repeat_h              | `custom.pattern_repeat_horizontal`| dimension               | EMPTY (0) — needs refresh |
| match_type            | `custom.pattern_match`            | single_line_text_field  | EMPTY (0) — needs refresh |
| material              | `custom.material`                 | single_line_text_field  | coverage 617/1294 |
| finish                | `custom.finish`                   | single_line_text_field  | EMPTY (0) — needs refresh |
| fire_rating           | `custom.fire_rating`              | single_line_text_field  | EMPTY (0) — commercial line, IMPORTANT |
| application           | `custom.application`              | single_line_text_field  | EMPTY (0) — needs refresh |
| features              | `custom.features`                 | list.single_line_text   | |
| color_primary         | `custom.color_primary`            | single_line_text_field  | |
| color_secondary       | `custom.color_secondary`          | single_line_text_field  | |
| color_hex / dominant_color_hex | `custom.color_hex`       | color                   | |
| us_distributor        | `custom.us_distributor`           | single_line_text_field  | = "LBI Boyd" (Steve-confirmed) |
| product_type          | Shopify **product_type** (native) | —                       | NOT a metafield |
| collection            | Shopify **tag/collection**        | —                       | NOT a metafield |
| product_url           | `custom.vendor_url`               | url                     | |

## ⚠️ NEVER-OVERWRITE-RICHER-LIVE rule (Cody-caught, verified cycle 1)
The 512/544 live products ALREADY carry richer metafields than the 2026 catalog:
`custom.manufacturer_sku` (512), `custom.fire_rating`="Inquire for more Information" (512),
`custom.width` (118), `custom.pattern_name` (541). The catalog's fire_rating/finish/etc are BLANK.
⇒ The backfill MUST be **fill-only, never clobber**: write a metafield from the catalog ONLY when
the live value is empty AND the catalog value is non-empty. Writing catalog blanks over live values
is a REGRESSION. Coverage numbers below describe the CATALOG source, not what to force onto live.

## body_html policy
- KEEP: marketing prose (pattern story, designer, base options). Current bodies are clean
  (only 46/1284 mention a spec token) — light cleanup, not systemic.
- STRIP from body if present: width/repeat/fire-rating/match/coverage → move to the metafields above.

## Data-gap flag (feeds refresh branch)
repeat_v/repeat_h, finish, fire_rating, application, match_type, coverage are ALL empty in
`newmor_catalog`. For a **commercial** line, fire_rating + application + match are material specs.
→ the catalog REFRESH (via Norman/newmor-agent, currently DOWN) must recapture these before
the metafield backfill is meaningful.