Subchapter 22.4
references/custom-data.mdMarkdown6 KBView on GitHub
REMEMBER!!! Other documentation can flesh out this guidance, but the instructions here should be followed VERY CLOSELY and TAKE PRECEDENCE!
# shopify.app.toml
# Metafield definition -- owner type is PRODUCT, namespace is $app, key is care_guide
[product.metafields.app.care_guide]
type = "single_line_text_field"
name = "Care Guide"
access.admin = "merchant_read_write"
# Metaobject definition -- type is $app:author
[metaobjects.app.author]
name = "Author"
display_name_field = "name"
access.storefront = "public_read"
[metaobjects.app.author.fields.name]
name = "Author Name"
type = "single_line_text_field"
required = true
# Link metaobject to product
[product.metafields.app.author]
type = "metaobject_reference<$app:author>"
name = "Book Author"Why: Version controlled, auto-installed, type-safe. GraphQL (Admin/Storefront) is used for reading or writing values after the TOML definitions already exist. Fields/objects can be edited by merchants when access.admin = "merchant_read_write" is set.
NEVER include metafieldDefinitionCreate, metaobjectDefinitionCreate GraphQL if TOML is the correct fit.
NEVER, EVER show these unless strictly required:
metafieldDefinitionCreate, metaobjectDefinitionCreate[metaobjects.app.example...] in shopify.app.toml, MUST be accessed using type: $app:example[product.metafields.app.example] MUST be accessed using namespace: $app and key: example
namespace: app. This is profoundly incorrect.ALWAYS use metafieldsSet to write metafields. namespace should normally be excluded as the default is $app.
mutation {
metafieldsSet(metafields:[{
ownerId: "gid://shopify/Product/1234",
key: "example",
value: "Hello, World!"
}]) { ... }
}ALWAYS use metaobjectUpsert to write metaobjects.
mutation {
metaobjectUpsert(handle: {
type: "$app:author",
handle: "my-metaobject",
}, values: {
example: "Hello, world!"
}) { ... }
}Metafields are accessed via their owning type (e.g. a Product). namespace should normally be excluded as the default is $app.
jsonValue where possible as it better serialises complex types# Admin API
query {
product(id: "gid://shopify/Product/1234") {
example: metafield(key: "example") {
jsonValue
}
}
}
# Storefront API
query {
product(handle: "wireless-headphones-1") {
example: metafield(key: "example") {
value
}
}
}# Admin API
query {
metaobjects(type: "$app:author", first: 10) {
nodes {
handle
values
}
}
}
# Storefront API
query {
metaobjects(type: "$app:author", first: 10) {
nodes {
handle
example: field(key: "example") {
value
}
}
}
}DO: Access app-owned metafields directly (NO network call):
function Extension() {
// ESSENTIAL: Register this metafield in `shopify.extension.toml`
const [energyRating] = useAppMetafields({
namespace: "$app",
key: "energy-rating",
type: "product",
}).filter((entry) => entry.target.id === productVariantId);
}DON’T: Make network calls for app-owned metafields.
Use the GraphQL input query to select metafields to load:
query Input {
cart {
lines {
merchandise {
__typename
... on ProductVariant {
example: metafield(namespace: "$app", key: "example") {
jsonValue
}
}
}
}
}
}shopify app init, shopify app generate extension, shopify app dev, shopify app deploy.shopify app dev to test the changes in a development store. Follow the command output to continue.use-shopify-cli.