Zebra Skimmers · Redesign Plan

Mock R · Metaobjects & metafields — Phase 1 data layer

Ten metaobject types and forty-plus metafield bindings that ship in Phase 1. The complete data-layer contract — what gets defined in Shopify admin, where it gets attached, how the storefront reads it. Companion to the main plan and the other Phase 1 deliverables.
§ 01

Ten metaobjects, three intent clusters.

Six previously specified in the original schema docs, four newly identified through working the data-to-design mapping. The newly-identified four (product_video, faq_item, glossary_term, distributor) are specified in full below — same level of detail as the originals.

Metaobject Status Purpose Feeds
product_document Specified Files attached to products — manuals, datasheets, drawings, certifications. Replaces the 46-PDF-per-product scrape with explicit, reusable entries. D · I · L · M
product_relationship Specified Editorial parent-curated links between products — required accessories, replacement parts, upgrade paths. D · I
product_spec_group Specified Spec category container — Performance, Electrical, Mechanical, etc. The grouping for spec rows. D · E · F
product_spec_row Specified Single structured spec value with US/metric units, comparable/filterable flags, variant override support. A · D · E · F · G · K
product_video New Structured video metadata. Replaces iframe embeds — searchable, filterable, emits JSON-LD VideoObject. D · H · I · L
faq_item New Discrete question-answer pairs. Indexable individually, attachable to products and collections, emits FAQPage schema. J · D · E
glossary_term New Single technical term with definition, examples, related products and articles. Emits DefinedTerm schema. J · I
distributor New A single distributor with location, contact, partner tier. Drives the map, search, and list on Mock O. O
ai_policy Specified Single-entry site-wide AI metadata. Renders meta tags in <head> on every page. ALL · <head>
ai_crawler_policy Specified Multi-entry per-crawler policies. Drives the robots.txt template and the /llms.txt Cloudflare Worker. ALL · robots.txt

Phase 1 ceiling is ten metaobject types. Phase 2 brings four more: company_stat, company_milestone, finder_intent_path / finder_step, learn_category. v1 ships those as hardcoded section blocks; promotion to metaobjects is a refactor, not new work.

METAOBJECT 01 · CATALOG DATA

product_document

A file attached to a product, variant, or the shop — manual, datasheet, drawing, install guide, certification, SDS, warranty, calibration cert. Replaces the prior scrape-and-attach-PDFs pattern that left some products with 46 attachments duplicating the same six PDFs. Each entry is created once and referenced from wherever it applies.

SPECIFIED MULTI-ENTRY ~60 entries projected
FIELDS
FieldTypeReqDescription
title single_line_text Display title (e.g., "Tube Oil Skimmer Installation Manual").
document_type single_line_text Drives section grouping on PDP and filtering on support hub.manual · datasheet · drawing · install_guide · troubleshooting · warranty · sds · certification · calibration_cert · spec_sheet · case_study · white_paper · catalog · regulatory
file file_reference PDF/document file. Either this or external_url is required.
external_url url External hosted document (e.g., third-party datasheet on a manufacturer's site).
language single_line_text ISO 639-1 code. Drives language-filtered surfacing for multilingual stores.en · es · fr · de · it · ja · zh · ...
version single_line_text Document version (e.g., "Rev. 3.2"). Surfaces as badge on document card.
revision_date date Last update. Sorts the support hub guides by recency. Emits as dateModified.
valid_until date Auto-expire date for certifications, calibration certs.
file_size_bytes number_integer Auto-derived from file; manual override for external URLs.DERIVED FROM FILE
description multi_line_text Short blurb under document title on PDP card. ~80 chars.
audience list.single_line_text Who the document is for. Drives audience-filtered surfacing.installer · engineer · buyer · shop_floor · maintenance · operator · qa · safety
thumbnail file_reference Override thumbnail; if blank, auto-generated from page 1 of PDF at render time.
EXAMPLE ENTRY
title:           "Tube Oil Skimmer Manual"
document_type:   "manual"
file:            files/zebra-tube-oil-skimmer-manual-v3.pdf
language:        "en"
version:         "Rev. 3.2"
revision_date:   "2025-08-14"
file_size_bytes: 2147483  // 2.1 MB
description:     "Installation, operation, and maintenance for the ZVA family."
audience:        ["installer", "maintenance", "shop_floor"]
thumbnail:       // auto-generated from PDF page 1
BINDINGS
shop theme.shop_documentslist.metaobject_reference
product theme.documentslist.metaobject_reference
variant theme.documentslist.metaobject_reference · variant-specific overrides
Notes · PDP merges product.theme.documents with selectedVariant.theme.documents at render, deduping by metaobject id. file_size_bytes is computed on-save by a metaobject hook; external URLs need manual entry. The 51 unique documents in the current catalog become ~60 entries with audience tags and revision dates.
METAOBJECT 02 · CATALOG DATA

product_relationship

Editorial parent-curated link between a product and another product or variant. The parent product owns the relationship — "the ZVA8-08 requires a ZT8-08 tube as a consumable." Reverse-lookup happens via the fits_products metafield on the child (the part), not via a metaobject.

SPECIFIED MULTI-ENTRY ~500 entries projected
FIELDS
FieldTypeReqDescription
target_product product_reference The other end of the relationship. Required.
target_variant variant_reference Optional variant-level specificity (e.g., "fits ZVA8-08 specifically, not ZVA8-101"). If blank, applies to all variants of target_product.
relationship_type single_line_text Drives section grouping on PDP ("Required parts" vs "Recommended accessories" vs "Upgrade").required_accessory · recommended_accessory · replacement_part · consumable · upgrade · alternative · complementary · accessory
display_label single_line_text Override the auto-derived label (e.g., "Recommended" instead of "Recommended accessory").
notes multi_line_text Editorial note shown on the relationship card (e.g., "Replace every 2,000 hours of operation").
display_priority number_integer Sort order within relationship_type group. Lower numbers first. Defaults to 100.
BINDINGS
product theme.related_productslist.metaobject_reference
product theme.fits_productslist.variant_reference · child-side reverse lookup, no metaobject
Notes · Two-way compatibility uses two separate metafields, not one metaobject. The parent (a skimmer) lists its parts via theme.related_products with this metaobject. The part (a tube) lists which variants it fits via theme.fits_products, which is a plain list.variant_reference — no metaobject needed. PDP's parts-and-accessories section queries both directions and merges. Variant-granular compatibility means a part can declare "fits ZVA8-08 only" without affecting other reach variants of the same family.
METAOBJECT 03 · CATALOG DATA

product_spec_group

Category container for spec rows. Each group is a section header in the PDP spec table ("Performance", "Electrical", "Mechanical & materials"). Defining groups as a metaobject means the order and labels are admin-editable without code changes, and new groups can be added when product categories require them.

SPECIFIED MULTI-ENTRY 6 seeded · expandable
FIELDS
FieldTypeReqDescription
label single_line_text Display name (e.g., "Performance", "Electrical").
key single_line_text Machine-readable identifier (e.g., performance). Stable across language; used to match spec rows to groups.
description multi_line_text Subhead under the group label on the PDP spec table.
display_order number_integer Order on PDP spec table. Defaults: performance=10, electrical=20, mechanical=30, materials=40, certifications=50, service=60.
icon file_reference Optional SVG icon for group header.
SEEDED ENTRIES
// Six default groups created at theme install:
performance      "Performance"          (capacity, reach, flow rate, throughput)
electrical       "Electrical"           (voltage, frequency, amperage, power)
mechanical       "Mechanical & materials" (mount style, materials, weight, dimensions)
certifications   "Certifications"       (UL, CE, NIST, ISO, OSHA)
connectivity     "Connectivity"         (protocols, APIs, network) [for automation products]
service          "Service & warranty"   (warranty term, country of origin, MOQ, lead time)
BINDINGS
product_spec_row groupmetaobject_reference · referenced from each spec row
Notes · Groups are referenced by spec rows, not directly bound to products. A product gets groups indirectly — render the PDP spec table by collecting all spec rows from product.theme.specs, grouping them by row.group.key, then rendering groups in display_order. A product with no connectivity rows simply doesn't render that group.
METAOBJECT 04 · CATALOG DATA

product_spec_row

A single specification value — Reach is 8 inches, Voltage is 115 VAC, Capacity is 1 qt/h. Has US and metric values with units, comparable/filterable flags, optional variant-level overrides, and a stable key for cross-product alignment so Compare and the collection filter rail can match equivalent rows across different products.

SPECIFIED MULTI-ENTRY ~1,800 entries projected
FIELDS
FieldTypeReqDescription
label single_line_text Display label (e.g., "Reach", "Capacity", "Voltage").
key single_line_text Machine identifier for cross-product alignment (e.g., reach_depth, voltage_primary). Stable across products.
group metaobject_reference References a product_spec_group.
value_text single_line_text Free-text value for non-numeric specs ("Stainless steel", "USA · Solon, OH"). Mutually exclusive with the number fields.
value_number_us number_decimal Numeric value in US units. Required if unit_us set.
value_number_metric number_decimal Numeric value in metric units. If only one is set, the other is computed at render via a canonical conversion map.
unit_us single_line_text Canonical US unit string.in · ft · lb · oz · qt · gal · gph · gpm · hp · °F · psi · ...
unit_metric single_line_text Canonical metric unit string.mm · cm · m · kg · g · L · L/h · kW · °C · kPa · ...
value_range_min number_decimal Lower bound for range values (e.g., "Reach 8–101 in"). Optional.
value_range_max number_decimal Upper bound for range values.
comparable boolean If true, surfaces in compare table, card spec pills, featured-product callout. Defaults to true.
filterable boolean If true, surfaces in collection filter rail facets. Defaults to false (avoid facet pollution).
display_priority number_integer Order within group. Lower numbers first.
notes multi_line_text Footnote shown beneath the row on PDP (e.g., "Measured at 70 °F ambient").
applies_to_variants list.variant_reference If set, this row only renders when one of these variants is selected. Used for variant-level overrides at the product level.
auto_derived boolean If true, value is computed from variant options (e.g., the Reach number comes from the option1 value) rather than entered manually. Defaults false.
VARIANT OVERRIDE STRATEGY

Two ways to express variant-specific spec values. Option A · per-variant metafield: attach a complete row to variant.theme.specs; render-time merge replaces the product-level row by matching key. Option B · applies_to_variants: keep all rows at product level, use the applies_to_variants field on rows that only apply to specific variants. Option A is cleaner for fully variant-driven specs (Reach changes per variant). Option B is better for sparse overrides (only the 220V variant has a different motor amperage).

EXAMPLE · ZVA8-08 PERFORMANCE ROW
label:               "Capacity"
key:                 "capacity"
group:               → product_spec_group "performance"
value_number_us:     1
unit_us:             "qt/h"
value_number_metric: 0.95
unit_metric:         "L/h"
comparable:          true
filterable:          false  // continuous-range, doesn't facet well
display_priority:    10
notes:               "Measured at 70 °F ambient with light tramp oil load"
BINDINGS
product theme.specslist.metaobject_reference
variant theme.specslist.metaobject_reference · overrides product-level by key
Notes · The heaviest metaobject by entry count — ~15 rows × 120 products = ~1,800 entries to seed. Migration plan: extract spec rows from existing product descriptions via the AI Search corpus, human review pass to clean unit normalization and value accuracy, bulk metaobjectCreate in batched mutations. Estimated ~12 hours of human work for 120 products.
METAOBJECT 05 · CATALOG DATA · NEW

product_video

Structured metadata for a video associated with a product, variant, or shop. Replaces the current pattern of raw YouTube iframe embeds inside product descriptions — those are unsearchable, can't emit JSON-LD VideoObject for rich-result eligibility, and can't be filtered by audience or topic. The AI Search corpus already has clean source data for ~5 videos per major product.

NEW IN MOCK R MULTI-ENTRY ~250 entries projected
FIELDS
FieldTypeReqDescription
title single_line_text Display title (e.g., "How to install the Sidewinder tube skimmer").
video_type single_line_text Drives section placement and filtering.install · demo · overview · tutorial · troubleshooting · case_study · spec_walkthrough · unboxing
platform single_line_text Where the video is hosted.youtube · vimeo · self_hosted · wistia
video_id single_line_text Platform's video ID (e.g., dQw4w9WgXcQ for YouTube).
watch_url url Computed from platform + video_id if not provided.DERIVED FROM PLATFORM + ID
embed_url url Computed iframe-embeddable URL.DERIVED FROM PLATFORM + ID
duration_seconds number_integer Total duration in seconds. Used for VideoObject.duration (ISO 8601 PT format on emit) and the card duration badge.
thumbnail file_reference Override thumbnail. If blank, fetched from platform at render.
description multi_line_text Short description for cards and VideoObject.description.
transcript rich_text Full transcript for accessibility, SEO, and on-page rendering. Highly recommended for indexability.
published_date date When the video was first published. Emitted as VideoObject.uploadDate.
audience list.single_line_text Same enum as product_document.audience — installer, engineer, buyer, etc.
applies_to_variants list.variant_reference If set, the video only renders on PDP when one of these variants is selected.
chapters json Optional chapter markers [{label, t}]. Emitted as VideoObject.hasPart Clip entries.
EXAMPLE ENTRY
title:            "How to install the ZVA8 Sidewinder tube skimmer"
video_type:       "install"
platform:         "youtube"
video_id:         "abc123XYZ"
duration_seconds: 187  // 3:07
description:      "Mounting options, voltage check, first-run procedure."
published_date:   "2024-11-12"
audience:         ["installer", "shop_floor"]
chapters:         [
  { label: "Mounting options", t: 0 },
  { label: "Voltage check",    t: 75 },
  { label: "First run",        t: 142 }
]
BINDINGS
product theme.videoslist.metaobject_reference
variant theme.videoslist.metaobject_reference · variant-specific
shop theme.featured_install_videoslist.metaobject_reference · for support hub
Notes · The AI Search pipeline at /Users/dylanburkey/active/execution/client/zebraskimmers/zebra-product-images already structures video data with the same shape — title, platform, video_id, watch_url, embed_url, thumbnail_url. Migration is a transform-and-bulk-create from products_full.json. Transcripts are not in the source data; generating them via Workers AI is a Phase 1.5 enhancement.
METAOBJECT 06 · EDITORIAL · NEW

faq_item

A single question-and-answer pair. Each FAQ becomes a discrete metaobject entry — individually searchable, attachable to a specific product or collection or the global FAQ page, emits cleanly as FAQPage structured data. Replaces the rich-text FAQ page (which dedupes badly across PDPs and isn't indexable per-question).

NEW IN MOCK R MULTI-ENTRY ~80 entries projected
FIELDS
FieldTypeReqDescription
question single_line_text The question text. Renders as the accordion heading.
answer rich_text The answer body. Rich text — supports inline links to products, articles, and glossary terms.
category single_line_text Section grouping on the FAQ page.ordering · shipping · payment · installation · maintenance · warranty · returns · technical · parts · international · account
display_order number_integer Sort within category. Lower numbers first.
products list.product_reference If set, the FAQ also appears on these PDPs in a per-product FAQ block. Empty = global FAQ only.
collections list.collection_reference If set, the FAQ appears on these collection pages in a category-level FAQ block.
related_terms list.metaobject_reference References glossary_term entries — for "see also" cross-links.
last_updated date Freshness signal. Surfaces as dateModified in structured data.
display_priority number_integer Promote a high-value FAQ to the top of its category irrespective of display_order. Defaults to 0.
BINDINGS
shop theme.faq_itemslist.metaobject_reference · global FAQ aggregation
product theme.faqslist.metaobject_reference · per-product FAQ block
collection theme.faqslist.metaobject_reference · per-collection FAQ block
Notes · Reverse-attachment is symmetrical with the metafield approach. A FAQ entry can declare which products it applies to via faq_item.products, OR a product can declare its FAQs via product.theme.faqs. Theme renderer queries both directions and dedupes by metaobject id. The PDP renders only FAQs where the product is referenced (either way). Global FAQ page aggregates all shop.theme.faq_items grouped by category.
METAOBJECT 07 · EDITORIAL · NEW

glossary_term

A single technical term — "Coalescer", "Tramp oil", "Sump", "Refractometer". Defines the term, points to products and articles that exemplify it, and cross-links related terms. Indexable as a discrete unit so technical buyers searching for terminology land directly on the glossary page with the term highlighted. Emits as DefinedTerm structured data.

NEW IN MOCK R MULTI-ENTRY ~60 entries projected
FIELDS
FieldTypeReqDescription
label single_line_text Primary term (e.g., "Coalescer", "Coolant concentration").
abbreviation single_line_text Acronym or short form (e.g., "CNC", "VFD"). Surfaces alongside label and as additional indexable token.
alternate_names list.single_line_text Synonyms or variants (e.g., for "Tramp oil" — ["leak oil", "way oil contamination"]). Used in search and "also known as" labels.
category single_line_text Section grouping on glossary page.equipment · process · material · measurement · regulation · general · application
definition rich_text Primary definition. Rich text supports inline links to related products and other terms.
examples multi_line_text "In a typical CNC sump, a coalescer separates emulsified tramp oil from water-soluble coolant before disposal." Renders as a callout below the definition.
related_terms list.metaobject_reference Self-referential. Cross-links to other glossary_term entries.
related_products list.product_reference Products that exemplify the term. "Coalescer" links to the Z-17 Muscle Coalescer.
related_articles list.article_reference Learn articles that explain the term in depth. The glossary card invites readers into the long-form content.
citations rich_text Sources / references for definition. Footnote-style under the entry.
BINDINGS
storefront metaobjects(type: "glossary_term")aggregated via Storefront API · no shop-level metafield needed
Notes · Unlike most other metaobjects, glossary_term doesn't need a shop-level metafield binding. The glossary page route queries the Storefront API directly for all entries of the type. Cross-linking from PDPs and articles uses inline anchor tags that point at /learn/glossary?focus=coalescer — the entry handle becomes the deep link.
METAOBJECT 08 · EDITORIAL · NEW

distributor

A single distributor or reseller. Drives the map, the searchable list, and the regional contact routing on Mock O. The current state of the truth (68 distributors across 42 countries) lives in a spreadsheet; promoting it to a metaobject makes the list admin-editable, the map auto-rendered, and adds the metafield bindings needed for "find a distributor near you" features.

NEW IN MOCK R MULTI-ENTRY ~68 entries
FIELDS
FieldTypeReqDescription
name single_line_text Display name of the company.
legal_name single_line_text Legal entity name if different from display name (for contracts, agreements page).
continent single_line_text Region grouping on the distributor list.north_america · south_america · europe · asia · africa · oceania · middle_east
country single_line_text ISO 3166-1 alpha-2 code (e.g., US, DE, JP).
region single_line_text State, province, or sub-region (e.g., "California", "Ontario", "Bayern").
city single_line_text Primary city.
latitude number_decimal For map pin placement. Decimal degrees, WGS-84.
longitude number_decimal For map pin placement. Decimal degrees, WGS-84.
service_areas list.single_line_text Postal codes, states, or country codes the distributor serves beyond their city. Drives "find a distributor near you" zip lookup.
primary_phone single_line_text With country code, E.164 format preferred (e.g., +1 216 555 0100).
email single_line_text Primary contact email.
website url Distributor's own site.
product_categories list.single_line_text Which product lines they carry (matches collection handles).skimmers · automation · refractometers · parts · accessories
contact_name single_line_text Primary rep at the distributor.
contact_title single_line_text Rep's title (e.g., "Sales Manager").
partner_tier single_line_text Partner level. Surfaces as a badge on the distributor card.authorized · certified · master · regional · exclusive
partner_since date Partnership start date.
notes multi_line_text Internal-only notes (not rendered on storefront).
BINDINGS
storefront metaobjects(type: "distributor")aggregated via Storefront API · no shop-level metafield needed
Notes · The distributor list page queries all entries, groups by continent for display, and renders the map by reading latitude and longitude per entry. Client-side filter ("near me" by zip code) reads service_areas against the user's input. Internal-only notes field never reaches the storefront — useful for tracking renewal dates, contract terms, or contact history that admin staff need but customers shouldn't see.
METAOBJECT 09 · SITE-LEVEL

ai_policy

Single-entry shop-level AI metadata. Renders meta tags in <head> on every page, drives the /llms.txt Cloudflare Worker, and provides JSON-LD isAccessibleForFree and licensing annotations. Admin-editable so policy changes don't require a code deploy.

SPECIFIED SINGLE-ENTRY 1 entry
FIELDS
FieldTypeReqDescription
content_licensesingle_line_textLicense declaration.all_rights_reserved · cc_by · cc_by_sa · cc_by_nc · cc0 · custom
training_allowedbooleanWhether AI training is allowed on site content. Renders ai-training-allowed meta tag.
attribution_requiredbooleanIf true, citation/attribution requested for AI surfacing of content.
descriptionmulti_line_textSite-wide description for ai-description meta tag. ~160 chars optimal.
summary_shortsingle_line_textShort version for SERP-style AI surfaces. ~60 chars.
keywordslist.single_line_textSite-wide topic tags (e.g., ["oil skimmer", "CNC coolant", "tramp oil removal"]).
product_typesingle_line_textPrimary product category. Renders ai-product-type.
industrysingle_line_textIndustry vertical (e.g., "manufacturing", "machining", "fluid handling").
llms_urlurlPath to /llms.txt. Renders link rel.
ai_info_urlurlPath to an AI-policy-detail page if one exists.
structured_data_formatslist.single_line_textWhich structured-data schemas the site emits (Product, Article, FAQPage, DefinedTerm, VideoObject, ...).
max_image_previewsingle_line_textRobots directive — large recommended.
last_reviewed_datedateWhen admin last confirmed policy is current.
BINDINGS
shop theme.ai_policymetaobject_reference · single entry
Notes · Zebra's default policy is permissive — training allowed, attribution requested. The bespoke ai-* meta tags aren't honored by any major crawler currently, but they're cheap insurance and signal good faith. The effective controls live in robots.txt (driven by ai_crawler_policy below) and the JSON-LD emission. The Cloudflare Worker at /llms.txt reads this metaobject via the Admin API on cold start and caches for 5 minutes.
METAOBJECT 10 · SITE-LEVEL

ai_crawler_policy

Per-crawler allow/deny rules. Each entry is one AI crawler (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, etc.) and its policy. Drives the dynamic /robots.txt.liquid template — admin can disable a specific crawler without a code deploy. Seeded with 12 named crawlers at theme install, all allow-by-default given Zebra's permissive policy.

SPECIFIED MULTI-ENTRY 12 seeded · expandable
FIELDS
FieldTypeReqDescription
user_agentsingle_line_textExact user-agent token (e.g., GPTBot, ClaudeBot, Google-Extended).
display_namesingle_line_textFriendly name for admin UI (e.g., "OpenAI GPT", "Anthropic Claude").
enabledbooleanMaster toggle. Renders Disallow-everything if false.
allow_pathslist.single_line_textExplicit allow rules. Defaults to ["/"] when enabled.
disallow_pathslist.single_line_textExplicit disallow rules (e.g., ["/cart", "/account", "/admin"]).
crawl_delaynumber_integerSeconds between requests. Most crawlers ignore but harmless to set.
notesmulti_line_textWhy this policy was set (e.g., "Disabled 2025-Q3 due to scraping volume").
SEEDED ENTRIES
// 12 default crawlers, all enabled, attached at theme install:
GPTBot              OpenAI · ChatGPT browsing & training
ClaudeBot           Anthropic Claude
Claude-Web          Anthropic Claude · web fetch
PerplexityBot       Perplexity
Google-Extended     Google Gemini training opt-in
GoogleOther         Google research / dev crawlers
Bingbot             Microsoft Copilot via Bing index
CCBot               Common Crawl
Applebot            Apple Intelligence
Applebot-Extended   Apple LLM training
Meta-ExternalAgent  Meta AI
Bytespider          ByteDance / TikTok
BINDINGS
shop theme.ai_crawler_policieslist.metaobject_reference
Notes · The robots.txt.liquid template iterates the bound list and emits a User-agent block per crawler with its allow/disallow paths. Crawlers not in the list fall through to the default User-agent: * block. Admin can disable a crawler by flipping enabled to false; the change appears in the next /robots.txt serve (no cache).
§ 11 · METAFIELDS

The metafield bindings, by owner.

Every metaobject reaches the storefront through a metafield attached to a Shopify primitive — product, variant, collection, article, or shop. This is the exhaustive list of metafields the theme needs to read. Each is namespaced under theme so they're scoped to this theme and don't collide with anything else the merchant has installed.

PRODUCT
product theme.documents list.metaobject_reference Manuals, datasheets, drawings. References product_document.
product theme.specs list.metaobject_reference Structured specifications. References product_spec_row.
product theme.related_products list.metaobject_reference Curated relationships. References product_relationship.
product theme.fits_products list.variant_reference Compatibility — which variants this product fits. No metaobject; native variant refs.
product theme.videos list.metaobject_reference Install, demo, tutorial videos. References product_video.
product theme.faqs list.metaobject_reference Per-product FAQ block. References faq_item.
product theme.overview_rich rich_text_field Optional structured overview for PDP. Falls back to descriptionHtml.
VARIANT
variant theme.documents list.metaobject_reference Variant-specific documents (e.g., 220V variant gets a different manual).
variant theme.specs list.metaobject_reference Variant-specific spec overrides. Merge-by-key with product-level theme.specs.
variant theme.videos list.metaobject_reference Variant-specific video overrides.
COLLECTION
collection theme.faqs list.metaobject_reference Per-collection FAQ block. References faq_item.
collection theme.fyf_banner single_line_text · json Find Your Fit banner copy override for this collection.
collection theme.featured_filters list.single_line_text Spec-row keys to promote to the top of the filter rail. Override defaults.
ARTICLE (Shopify Blog)
article editorial.standfirst multi_line_text Editorial subtitle / dek beneath the article title. Renders larger than body.
article editorial.reviewer single_line_text "Reviewed by" credit (e.g., a P.E. or technical authority).
article related.products list.product_reference Products referenced by the article. Renders at the foot.
article related.terms list.metaobject_reference Glossary terms the article touches. Cross-link block.
SHOP (singletons & aggregations)
shop theme.ai_policy metaobject_reference Single-entry ai_policy. Rendered on every page in <head>.
shop theme.ai_crawler_policies list.metaobject_reference All crawler policies. Drives /robots.txt.
shop theme.shop_documents list.metaobject_reference Site-wide documents — catalog, warranty terms, return form. Surfaces on support hub.
shop theme.faq_items list.metaobject_reference Global FAQ aggregation. Drives /learn/faq.
shop theme.featured_product product_reference Homepage featured product callout.
shop theme.featured_install_videos list.metaobject_reference Featured install videos on the support hub.
shop theme.featured_learn_article article_reference Featured article on the Learn hub.
shop theme.popular_parts_models list.variant_reference Quick-pick model pills on Find Parts by Model (Mock K).
shop theme.brand_tagline · theme.hero_* single_line_text · multi_line_text Homepage editorial copy. ~5 fields total.
shop theme.about_* · theme.warranty_* · theme.contact_* various Editorial copy for About, Warranty, Contact pages. ~15 fields total across these pages.
§ 12 · IMPLEMENTATION

Creating these in Shopify — GraphQL mutations.

Every metaobject and metafield gets defined via a single Admin API mutation, run once per environment. The full create script is a Node script that posts these mutations sequentially with retries. Below is the pattern for one metaobject definition and the corresponding metafield definition; the full script applies the same shape to all ten metaobject types and all twenty-plus metafield definitions.

1. Create the metaobject definition

mutation CreateProductDocumentDefinition {
  metaobjectDefinitionCreate(definition: {
    type: "product_document"
    name: "Product document"
    description: "A PDF or document attached to a product."
    fieldDefinitions: [
      {
        key: "title"
        name: "Title"
        type: "single_line_text_field"
        required: true
      },
      {
        key: "document_type"
        name: "Document type"
        type: "single_line_text_field"
        required: true
        validations: [
          {
            name: "choices"
            value: "[\"manual\",\"datasheet\",\"drawing\",\"install_guide\",\"troubleshooting\",\"warranty\",\"sds\",\"certification\",\"calibration_cert\",\"spec_sheet\",\"case_study\",\"white_paper\",\"catalog\",\"regulatory\"]"
          }
        ]
      }
      /* ... remaining 10 field definitions ... */
    ]
    access: { storefront: PUBLIC_READ }
    displayNameKey: "title"
  }) {
    metaobjectDefinition { id type }
    userErrors { field message }
  }
}

2. Create the metafield definition that binds the metaobject to products:

mutation CreateProductDocumentsMetafield {
  metafieldDefinitionCreate(definition: {
    name: "Documents"
    namespace: "theme"
    key: "documents"
    description: "Manuals, datasheets, drawings attached to this product."
    type: "list.metaobject_reference"
    ownerType: PRODUCT
    validations: [
      {
        name: "metaobject_definition_id"
        value: "gid://shopify/MetaobjectDefinition/123456789"
        // the ID returned by the metaobjectDefinitionCreate mutation above
      }
    ]
    access: { admin: MERCHANT_READ_WRITE, storefront: PUBLIC_READ }
  }) {
    createdDefinition { id key }
    userErrors { field message }
  }
}

3. Wire-up sequence for the full data layer — order matters because some metaobjects reference others:

// Stage 1 — base metaobjects (no inter-references)
1.  product_spec_group       // seeded with 6 entries after creation
2.  product_document
3.  product_video
4.  glossary_term            // self-reference allowed, no other deps
5.  distributor
6.  ai_policy                // single-entry · seed 1 entry after
7.  ai_crawler_policy        // seeded with 12 entries

// Stage 2 — metaobjects with references to Stage 1
8.  product_spec_row         // references product_spec_group
9.  product_relationship     // references product, variant
10. faq_item                 // references glossary_term

// Stage 3 — metafield definitions (after all metaobjects exist)
11. product.theme.{documents, specs, related_products,
                  fits_products, videos, faqs, overview_rich}
12. variant.theme.{documents, specs, videos}
13. collection.theme.{faqs, fyf_banner, featured_filters}
14. article.{editorial.standfirst, editorial.reviewer,
             related.products, related.terms}
15. shop.theme.{ai_policy, ai_crawler_policies, shop_documents,
                faq_items, featured_product, featured_install_videos,
                featured_learn_article, popular_parts_models,
                brand_tagline, hero_*, about_*, warranty_*, contact_*}
Implementation plan · Single Node script at scripts/create-data-layer.mjs runs all three stages with retry-on-rate-limit and an idempotency check (skips if the definition already exists). Same script targets either the Zebra production store or the sellable-theme demo store via env var. Estimated runtime ~2 minutes per environment. Same script reverses for teardown via --rollback flag — important for the demo store where definitions change as we iterate. Token scopes needed: write_metaobject_definitions, write_metaobjects, write_metafields, plus write_products for the seeding step that attaches the seeded entries to sample products.