mcpField
S
shopify-metafields

shopify-metafields

github.com/finsilabs数据与数据库6077 次安装6 天前更新
代码仓库

关于 shopify-metafields

此技能指南说明如何使用 Shopify metafields 和 Metaobjects 为商品、订单、客户等资源添加结构化自定义数据,适合构建定制 storefront 和内容模块的开发者。内容涵盖定义、API 读写、Liquid 展示及数据类型验证。

主要功能

  1. 01为 Shopify 资源添加结构化数据
  2. 02通过定义验证字段类型
  3. 03使用 Admin API 写入 metafields
  4. 04在 Liquid 和 Storefront API 中读取数据
  5. 05创建可复用的 Metaobjects

适用场景

  1. 01为商品补充尺寸、护理说明或认证信息
  2. 02保存客户等级或订单配送说明
  3. 03在主题中管理 FAQ、尺码指南等内容
  4. 04创建可重复使用的团队或规格内容条目

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill shopify-metafields

安装后在 Claude Code 中输入/shopify-metafields确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

tile.json
evals/metafield-definitions-and-bulk-write/
criteria.json
task.md
evals/metaobjects-for-structured-content/
criteria.json
task.md
evals/storefront-api-metafield-queries/
criteria.json
task.md

详细介绍

Shopify 元字段

概述

元字段让你无需单独构建数据库,即可为 Shopify 资源添加结构化自定义数据,例如产品、变体、订单、客户、系列和页面。元字段定义会强制执行类型验证(文本、数字、日期、URL、JSON、文件、产品引用等),并让元字段可用于 Liquid 模板编辑器和 Storefront API。元对象扩展了这一概念,可创建可重复使用的独立自定义数据结构。

何时使用此技能

  • 当产品需要 Shopify 默认字段以外的其他属性时(护理说明、尺寸、认证)
  • 当需要存储每位客户的数据时,例如忠诚度等级、订阅状态或 B2B 账号
  • 当需要在主题中使用元字段引用构建由内容管理的版块时(常见问题、尺码指南、功能亮点)
  • 当需要添加结账时提供的订单级自定义数据时(礼品留言、配送说明)
  • 当需要使用元对象创建可重复使用的结构化内容条目时(团队成员、媒体报道、规格)

核心说明

  1. 通过 Admin API 创建元字段定义

    定义会强制执行类型,并使元字段可供店面访问:

    // Create a metafield definition for product care instructions
    const response = await adminClient.request(`
      mutation CreateMetafieldDefinition($definition: MetafieldDefinitionInput!) {
        metafieldDefinitionCreate(definition: $definition) {
          createdDefinition {
            id
            name
            namespace
            key
            type { name }
          }
          userErrors { field message code }
        }
      }
    `, {
      variables: {
        definition: {
          name: "Care Instructions",
          namespace: "custom",
          key: "care_instructions",
          type: "multi_line_text_field",
          ownerType: "PRODUCT",
          description: "Washing and care instructions for the product",
          visibleToStorefrontApi: true,
          // Optional: pin to product admin UI (use pinnedPosition in API version 2023-10+)
          pinnedPosition: 1,
        },
      },
    });
    

    可用类型:single_line_text_field、multi_line_text_field、number_integer、number_decimal、date、date_time、boolean、url、json、color、weight、volume、dimension、rating、file_reference、product_reference、variant_reference、collection_reference、page_reference、metaobject_reference、list.<type>。

  2. 通过 Admin API 写入元字段

    // Set a metafield on a product
    export async function setProductMetafield(
      productId: string,
      namespace: string,
      key: string,
      value: string,
      type: string
    ) {
      const response = await adminClient.request(`
        mutation SetMetafield($metafields: [MetafieldsSetInput!]!) {
          metafieldsSet(metafields: $metafields) {
            metafields {
              id key namespace value
            }
            userErrors { field message code }
          }
        }
      `, {
        variables: {
          metafields: [
            {
              ownerId: productId,
              namespace,
              key,
              value,
              type,
            },
          ],
        },
      });
      return response.data.metafieldsSet;
    }
    
    // Example: Set care instructions on a product
    await setProductMetafield(
      "gid://shopify/Product/1234567890",
      "custom",
      "care_instructions",
      "Machine wash cold. Tumble dry low. Do not bleach.",
      "multi_line_text_field"
    );
    
  3. 在 Liquid 模板中读取元字段

    定义设置了 visibleToStorefrontApi: true 后,即可通过 metafields 对象在 Liquid 中使用元字段:

    {% comment %} product.metafields.namespace.key {% endcomment %}
    
    {% if product.metafields.custom.care_instructions != blank %}
      <div class="care-instructions">
        <h3>Care Instructions</h3>
        {{ product.metafields.custom.care_instructions | metafield_tag }}
      </div>
    {% endif %}
    
    {% comment %} Access a product reference metafield {% endcomment %}
    {% assign related = product.metafields.custom.related_product.value %}
    {% if related %}
      <a href="{{ related.url }}">{{ related.title }}</a>
    {% endif %}
    
    {% comment %} Access a list of file references (images) {% endcomment %}
    {% for image in product.metafields.custom.gallery_images.value %}
      <img src="{{ image | image_url: width: 800 }}" alt="{{ image.alt }}">
    {% endfor %}
    
  4. 通过 Storefront API 读取元字段

    // Query product with metafields in the Storefront API
    const { data } = await storefront.request(`
      query GetProductWithMetafields($handle: String!) {
        product(handle: $handle) {
          id
          title
          # Metafields must be explicitly requested by namespace + key
          careInstructions: metafield(namespace: "custom", key: "care_instructions") {
            value
            type
          }
          relatedProduct: metafield(namespace: "custom", key: "related_product") {
            reference {
              ... on Product {
                id title handle
                featuredImage { url altText }
              }
            }
          }
          certifications: metafield(namespace: "custom", key: "certifications") {
            references(first: 5) {
              edges {
                node {
                  ... on Metaobject {
                    id
                    fields {
                      key value
                    }
                  }
                }
              }
            }
          }
        }
      }
    `, { variables: { handle: "my-product" } });
    
  5. 创建和使用元对象

    元对象是独立的自定义数据条目,适用于常见问题、客户评价或任何结构化内容:

    // Create a Metaobject definition
    await adminClient.request(`
      mutation {
        metaobjectDefinitionCreate(definition: {
          name: "FAQ Entry"
          type: "faq_entry"
          fieldDefinitions: [
            { name: "Question", key: "question", type: "single_line_text_field", required: true }
            { name: "Answer", key: "answer", type: "multi_line_text_field", required: true }
            { name: "Sort Order", key: "sort_order", type: "number_integer" }
          ]
        }) {
          metaobjectDefinition { id type }
          userErrors { field message }
        }
      }
    `);
    
    // Create a Metaobject entry
    await adminClient.request(`
      mutation {
        metaobjectCreate(metaobject: {
          type: "faq_entry"
          fields: [
            { key: "question", value: "What is your return policy?" }
            { key: "answer", value: "We accept returns within 30 days of purchase." }
            { key: "sort_order", value: "1" }
          ]
        }) {
          metaobject { id handle }
          userErrors { field message }
        }
      }
    `);
    

示例

批量导入产品属性元字段
// Import dimensions for multiple products at once (up to 25 per request)
export async function bulkSetDimensions(
  products: Array<{ id: string; weight: number; length: number; width: number; height: number }>
) {
  const metafields = products.flatMap(({ id, weight, length, width, height }) => [
    { ownerId: id, namespace: "custom", key: "weight_grams", value: weight.toString(), type: "number_integer" },
    { ownerId: id, namespace: "custom", key: "length_cm", value: length.toString(), type: "number_decimal" },
    { ownerId: id, namespace: "custom", key: "width_cm", value: width.toString(), type: "number_decimal" },
    { ownerId: id, namespace: "custom", key: "height_cm", value: height.toString(), type: "number_decimal" },
  ]);

  // Process in batches of 25 (API limit)
  for (let i = 0; i < metafields.length; i += 25) {
    const batch = metafields.slice(i, i + 25);
    await adminClient.request(`
      mutation SetMetafields($metafields: [MetafieldsSetInput!]!) {
        metafieldsSet(metafields: $metafields) {
          userErrors { field message }
        }
      }
    `, { variables: { metafields: batch } });
  }
}
在 Liquid 中渲染常见问题元对象
{% comment %} sections/faq.liquid {% endcomment %}
{% assign faqs = shop.metafields.custom.faq_entries.value %}

<div class="faq-section">
  <h2>Frequently Asked Questions</h2>
  {% for faq in faqs %}
    <details class="faq-item">
      <summary>{{ faq.question.value }}</summary>
      <div class="faq-answer">{{ faq.answer.value | newline_to_br }}</div>
    </details>
  {% endfor %}
</div>

最佳实践

  • 写入元字段前务必先创建定义——定义可启用类型验证、店面 API 访问和 Admin UI 字段编辑器;未定义的命名空间/键组合会显示为原始 JSON
  • 商家管理的数据使用 custom 命名空间——其他命名空间(例如 app_name)留给应用自有数据,避免商家直接编辑
  • 对需要在主题或无头前端中读取的定义设置 visibleToStorefrontApi: true——元字段默认是私有的
  • 使用 metafieldsSet 批量写入元字段——每次变更最多接受 25 个元字段;批量操作时使用它,而不是单独调用 productUpdate
  • 对富文本和文件引用元字段使用 Liquid 的 metafield_tag 过滤器——它会根据元字段类型渲染正确的 HTML 元素(img、p 等)
  • 结构化的多字段数据优先使用元对象,而非 JSON 元字段——元对象具有强类型,并且可在 Shopify Admin UI 中编辑内容
  • 记录命名空间规范——确定一套约定(商家使用 custom.*,应用使用 yourapp.*),并记录所用的键,方便开发者查找

常见问题

问题解决方案
Metafield 在 Storefront API 中返回 nullMetafield 定义必须将 visibleToStorefrontApi: true 设为 true;如果创建时未设置此标志,请更新定义
Liquid 中的 metafields.custom.key 为空确保存在对应 namespace/key 的定义;Liquid 仅公开已注册定义的 metafield
列表类型 metafield 的值是 JSON 字符串,而非数组在 Liquid 中使用 `
metafieldsSet 因 TYPE_MISMATCH 失败value 必须是与类型匹配的 JSON 序列化字符串;对于 number_integer,请传入 "42",而非 42
Metaobject 字段未更新使用 metaobjectUpdate mutation,并提供 metaobject GID 和 fields 数组;支持部分更新
应用的 namespace 与其他应用冲突使用应用的 handle 作为 namespace 前缀(例如 myapp-handle),以避免在共享商店中发生冲突

相关技能

  • @shopify-admin-api
  • @shopify-storefront-api
  • @shopify-app-development
  • @shopify-theme-development
  • @custom-product-attributes

评论

支持 Markdown