用途
该技能用于识别并清除 Shopify 商品变体中不再代表真实折扣的 compareAtPrice(划线价),使店面划线价反映真实节省,而非历史遗留的噪声。它标记两类情况:
- compareAtPrice <= price(无折扣,通常由涨价后遗留导致);
- compareAtPrice 设置时间超过 max_age_days(陈旧的“永远在促销”观感,会损害长期价格认知,在某些地区可能违反广告标准)。
默认以 dry-run 模式运行。
前置条件
- 已认证的 Shopify CLI 会话:
shopify store auth --store <domain> --scopes read_products,write_products - API 权限范围:read_products、write_products
参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| store | string | 是 | — | 店铺域名(例如 mystore.myshopify.com) |
| dry_run | bool | 否 | true | 预览清理而不执行变更 |
| clean_no_discount | bool | 否 | true | 当 price >= compareAtPrice 时清除 compareAtPrice |
| clean_stale | bool | 否 | true | 清除设置时间超过 max_age_days 的 compareAtPrice |
| max_age_days | integer | 否 | 90 | 陈旧规则的天数阈值(以变体 updatedAt 作为代理) |
| collection_id | string | 否 | — | 可选的集合 GID,用于限定清理范围 |
| tag_filter | string | 否 | — | 可选的产品标签,用于限定清理范围 |
| format | string | 否 | human | 输出格式:human 或 json |
安全提示
⚠️ 第 2 步会执行 productVariantsBulkUpdate 变更,将 compareAtPrice 覆盖为 null。原始划线价不会在服务端保留——如需恢复路径,请在提交前记录 dry-run CSV。始终先以 dry_run: true 运行并审阅 CSV,再以 dry_run: false 执行。
工作流程
-
OPERATION: productVariants — 查询
- 输入:first: 250,query: <由 collection_id 或 tag_filter 构建>,选择 price、compareAtPrice、updatedAt、product { id, title, vendor }、sku、分页游标
- 预期输出:范围内所有变体及其当前定价;分页直到 hasNextPage: false
-
筛选满足任一规则的变体:clean_no_discount 且 compareAtPrice != null 且 parseFloat(compareAtPrice) <= parseFloat(price),或 clean_stale 且 compareAtPrice != null 且 (now - updatedAt) > max_age_days。按 product.id 分组以便批量变更。
-
OPERATION: productVariantsBulkUpdate — 变更(dry_run: true 时跳过)
- 输入:每个产品,productId 加上 [{ id: variantId, compareAtPrice: null }]
- 预期输出:更新后的变体,compareAtPrice 置为 null;收集每批次的 userErrors
-
写入 CSV(始终执行,即使 dry run),用于审计追踪和回滚能力。
GraphQL 操作
# productVariants:query — 已针对 api_version 2025-01 验证
query VariantsForCompareAtCleanup($query: String, $after: String) {
productVariants(first: 250, after: $after, query: $query) {
edges {
node {
id
sku
price
compareAtPrice
updatedAt
product {
id
title
vendor
tags
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
# productVariantsBulkUpdate:mutation — 已针对 api_version 2025-01 验证
mutation ClearCompareAtPrice($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
productVariants {
id
price
compareAtPrice
}
userErrors {
field
message
}
}
}
会话跟踪
Claude 必须在每个阶段输出以下内容。这是强制性的。
开始时输出:
╔══════════════════════════════════════════════╗
║ SKILL: Compare-At Price Cleanup ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
每步之后输出:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
如果 dry_run: true,为每个变更步骤添加 [DRY RUN] 前缀,且不执行它。
完成时输出:
对于 format: human(默认):
══════════════════════════════════════════════
COMPARE-AT PRICE CLEANUP (<dry-run|live>)
Variants inspected: <n>
No-discount cleared: <n>
Stale (>= <days>d): <n>
Total cleared: <n>
Errors: <n>
Output: compare_at_cleanup_<date>.csv
══════════════════════════════════════════════
对于 format: json,输出:
{
"skill": "compare-at-price-cleanup",
"store": "<domain>",
"dry_run": true,
"variants_inspected": 0,
"cleared_no_discount": 0,
"cleared_stale": 0,
"total_cleared": 0,
"errors": 0,
"output_file": "compare_at_cleanup_<date>.csv"
}
输出格式
CSV 文件 compare_at_cleanup_<YYYY-MM-DD>.csv,列包括: variant_id, product_id, product_title, vendor, sku, price, original_compare_at_price, rule_matched, variant_updated_at, mutation_status
错误处理
| 错误 | 原因 | 恢复方式 |
|---|---|---|
| 变更响应中的 userErrors | 变体被锁定或处于活跃订阅合同中 | 记录每个变体的错误,继续处理剩余变体 |
| THROTTLED | 超出 API 速率限制 | 等待 2 秒,最多重试 3 次 |
| 运行中 compareAtPrice 已为 null | 另一进程并发清除 | 跳过,计为无操作成功 |
| updatedAt 比预期更新 | 审计期间发生并发编辑 | 变更前重新查询单个变体;若规则不再匹配则跳过 |
最佳实践
- 始终先以 dry_run: true 运行并审阅 CSV。compareAtPrice 清除没有批量撤销功能。
- 在长期计划促销期间禁用 clean_stale(设置 clean_stale: false)——你的“陈旧”促销实际上是有意为之。
- 使用 collection_id 将清理范围限定为常青产品,并排除活跃促销集合。
- 实时运行后,在店面抽查 5–10 个变体,确认划线价已消失。
- 作为目录卫生的一部分,安排每季度运行一次;结合 seo-metadata-audit 和 product-data-completeness-score 进行季末商品整理。