Collection mapping
StagingCollection is a flat shape — title, image, optional product
list, and a few menu hierarchy hints that get stored as metafields.
A collection can be manual (a fixed product list, via products
here or collections on the product mapping), rule-driven (map
rules to recreate the source’s automated collections), or
metafield-driven smart (smart_collection: true, matching
products by the collection names in their custom.collections
metafield).
Quick reference — minimum loadable collection
{
"original_id": category_id,
"title": name,
"handle": $lowercase(url_key)
}Identity & display
titlestringCollection display name.
"title": namehandlestringURL slug. Auto-derived from title if omitted.
"handle": $lowercase(url_key)descriptionHtmlstringCollection description with HTML.
"descriptionHtml": descriptionsortOrderstringHow products are ordered within the collection. Common values:
MANUAL, BEST_SELLING, ALPHA_ASC, ALPHA_DESC,
PRICE_ASC, PRICE_DESC, CREATED_DESC. Defaults to Shopify’s
default if omitted.
"sortOrder": "MANUAL"templateSuffixstringCustom theme template suffix. Use only if the merchant has a non-default collection template.
Image
Collection cover image. Two flat fields — different shape from product images.
image_srcstringURL of the collection’s cover image. Setting this is what triggers the image being created.
"image_src": image_urlimage_altstringAlt text for the cover image.
"image_alt": image_alt ? image_alt : nameProducts
The product list lives on the collection or on each product — pick one.
productsstring[]Array of source-platform product IDs to include in the collection. Graftport resolves these to Shopify GIDs at load time using the product migration’s results.
"products": product_idsYou don’t have to populate products here — alternatively, set
collections: [<this collection's original_id>] on the product
mapping and the membership goes the
other direction. Pick one approach per migration; mixing is
confusing.
rulesobject[]Turns the collection into an automated collection: Shopify decides membership from these conditions and keeps deciding, instead of holding the fixed list you migrated.
Each rule is { column, relation, condition } — for example
{"column": "TAG", "relation": "EQUALS", "condition": "wool"}.
"rules": [{
"column": "VENDOR",
"relation": "EQUALS",
"condition": brand_name
}]Mapping rules drops products: a collection is either rule-driven or
a fixed list, never both.
rules_match_anybooleantrue when a product only has to match one rule, false when it
has to match them all. Required whenever rules is mapped — there
is no default, so a rule-driven collection that leaves this out fails
validation rather than guessing which behavior you meant.
smart_collectionbooleanCreates this collection as a smart collection matching on a product
metafield: its single rule is “the product’s custom.collections
metafield contains this collection’s reference name”. Graftport sets
up the metafield definition on the destination shop automatically.
Fill the metafield from the product mapping’s
smart_collections field.
"smart_collection": trueMutually exclusive with rules and with a manual products list —
the metafield rule is the membership. Requires title and the
source ID, which together form the default reference name.
smart_collection_referencestringThe reference name the smart collection matches on — the join key
between this collection and the values in each product’s
custom.collections metafield. You normally don’t map this: it
defaults to “Collection name #id” (“Dame #2915”, “Tilbehør #2760”),
which is unique even when many collections share a name, and still
readable where it matters — on the product in Shopify admin. Plain
names are not used as the join key on purpose: category trees
routinely reuse names (“Dame” under both Trøjer and Jakker), and a
name-keyed rule would put a product into every same-named collection.
Map it explicitly only as an exception — most usefully to pin the previous reference after renaming a collection: the reference is locked once the collection has loaded (changing it would silently empty the collection, because loaded products still carry the old value), so a rename keeps the old reference unless you re-load the products too.
"smart_collection_reference": name & " #" & category_idTwo collections resolving to the same reference name fail validation loudly — never silently — since a shared join key would merge their memberships.
SEO
meta_titlestringmeta_descriptionstringMenu hierarchy (auto-metafields)
Source platforms with category trees often need this preserved. The staging model auto-converts these to custom metafields.
include_in_menubooleanWhether the source category was visible in the storefront menu.
Set it to false to keep a category out of the generated menu. Its
subcategories move up to the nearest category that is in the menu, so
they aren’t lost. Also becomes a custom.include_in_menu boolean
metafield for theme code.
is_menu_rootbooleanWhether this category was a top-level / root menu entry. Becomes a
custom.is_menu_root boolean metafield.
parent_idstringThe category this one sits under, using the source store’s own ID for
the parent. This is what Storefront navigation
builds the menu from, so map it whenever the source has a category tree.
It also becomes a custom.parent_id metafield, so theme code can read
the hierarchy directly.
Leave it empty (or null) for top-level categories.
Patterns
Magento category → Shopify collection
{
"original_id": entity_id,
"title": name,
"handle": url_key,
"descriptionHtml": description,
"image_src": image,
"image_alt": name,
"include_in_menu": include_in_menu = "1",
"is_menu_root": level = 2,
"parent_id": parent_id,
"meta_title": meta_title,
"meta_description": meta_description
}Membership-on-collection (push the product list explicitly)
{
"original_id": entity_id,
"title": name,
"handle": $lowercase(name),
"products": products.product_id
}Membership-on-product (the recommended pattern)
In the product mapping, list each product’s collection memberships:
{
"original_id": entity_id,
"title": name,
"collections": $append(category_ids, ["all-products"]),
…
}Then in the collection mapping, just declare the collection itself — no need to list products:
{
"original_id": entity_id,
"title": name,
"handle": $lowercase(name)
}Metafield-driven smart collections
Like membership-on-product, but the membership stays visible and
editable on each product in Shopify admin: the product carries its
collections’ reference names (“Dame #2915”) in a custom.collections
metafield, and each collection is a smart collection matching on its
own reference.
In the product mapping:
{
"original_id": entity_id,
"title": name,
"smart_collections": category_ids,
…
}In the collection mapping:
{
"original_id": entity_id,
"title": name,
"handle": $lowercase(name),
"smart_collection": true
}Hierarchical category names
If the merchant wants the path encoded in the title:
{
"original_id": entity_id,
"title": $join($append(parent_path, [name]), " / "),
"handle": $join(parent_path & [name], "-") ~> $lowercase
}Gotchas
A collection can’t switch kind after it loads. Shopify doesn’t
convert a manual collection into a smart one (or back) on update, so
a collection first loaded without rules/smart_collection and
later re-mapped with them fails to update. Delete the collection in
Shopify admin (or purge and re-run) to change kind.
- Membership conflict. If a product references a collection in
its
collectionsarray AND the collection’sproductsarray also includes that product, the second load wins. Avoid the conflict by picking one direction. image_srcwithoutimage_altstill loads — the alt is just empty. Set it from the source name as a sensible default.sortOrdervalues are case-sensitive. Shopify accepts the exact uppercase enum values listed above;"manual"(lowercase) fails.- Handle collisions. Two collections with the same auto-derived
handle silently overwrite. If two source categories have similar
names (
Newsandnews), sethandleexplicitly with a disambiguating suffix. - The menu is built separately. Mapping
parent_idandinclude_in_menurecords the tree on each category; it doesn’t create the storefront menu by itself. Once the load finishes, use Storefront navigation to turn that tree into a real Shopify menu.