lineUpdate ile kişiselleştirme ücreti

Bir satır özelliği (line item property) doldurulduğunda satırın fiyatına ve adına gravür ücreti ekleyen Shopify cart transform Function’ı. Shopify Plus.

Function API
Cart Transform
Hedef (target)
cart.transform.run
İşlem (operation)
lineUpdate
Plan
Shopify Plus ya da geliştirme mağazası
Uygulama yetkisi
write_cart_transforms
API sürümü
2026-10
Son kontrol

Kısaca

Bu cart transform Function’ı, gravür bilgisi olan her satırın birim fiyatına bir kişiselleştirme ücreti (varsayılan olarak mağaza para biriminde 10) ekler ve adını işaretler. Gravür metni bir satır özelliğinden (line item property) gelir. Cart Transform API’nin cart.transform.run hedefindeki lineUpdate işlemini kullanır (2026-10); Shopify bu işleme yalnızca Plus ve geliştirme mağazalarında izin verir.

Nasıl kullanılır

  1. Ürün formuna bir metin alanı ekleyin: <input name="properties[Engraving]">.
  2. Shopify CLI ile bir uygulama oluşturun, uzantıyı ekleyin (shopify app generate extension --template cart_transform) ve dosyalarını aşağıdakilerle değiştirin.
  3. Testleri shopify app function run --input tests/engraved-line.input.json ile çalıştırın, ardından deploy edin.
  4. cartTransformCreate ile etkinleştirin; farklı değerler istiyorsanız metafield’ına {"fee": 10, "titleSuffix": " (gravürlü)"} yazın.
  5. Yeni adın görünmesi için sepet şablonunda item.title’ı kullanın.

Kod

shopify.extension.toml
api_version = "2026-10"

[[extensions]]
name = "Personalization fee with lineUpdate"
handle = "personalization-fee-line-update"
type = "function"

  [[extensions.targeting]]
  target = "cart.transform.run"
  input_query = "src/cart_transform_run.graphql"
  export = "cart-transform-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
src/cart_transform_run.graphql
query CartTransformRunInput {
  presentmentCurrencyRate
  cart {
    lines {
      id
      engraving: attribute(key: "Engraving") {
        value
      }
      cost {
        amountPerQuantity {
          amount
        }
      }
      merchandise {
        __typename
        ... on ProductVariant {
          product {
            title
          }
        }
      }
    }
  }
  cartTransform {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
src/cart_transform_run.js
// @ts-check

/**
 * @typedef {import("../generated/api").CartTransformRunInput} CartTransformRunInput
 * @typedef {import("../generated/api").CartTransformRunResult} CartTransformRunResult
 */

/**
 * Settings stored as JSON in the cart transform's metafield. The engraving
 * text comes from a line item property named "Engraving" on the product form
 * (<input name="properties[Engraving]">); change the attribute key in the
 * query if your theme uses another name.
 */
const DEFAULT_CONFIG = {
  // Added to each engraved unit, in the store's currency.
  fee: 10,
  // Appended to the product title on engraved lines.
  titleSuffix: " (engraved)",
};

/**
 * @param {CartTransformRunInput} input
 * @returns {CartTransformRunResult}
 */
export function cartTransformRun(input) {
  const config = { ...DEFAULT_CONFIG, ...input.cartTransform?.metafield?.jsonValue };
  // Prices in the input and output are in the customer's currency.
  const fee = config.fee * Number(input.presentmentCurrencyRate);

  const operations = input.cart.lines
    .filter((line) => line.merchandise.__typename === "ProductVariant" && (line.engraving?.value ?? "").trim() !== "")
    .map((line) => {
      const title = line.merchandise.__typename === "ProductVariant" ? line.merchandise.product.title : "";
      // A fixed unit price replaces the variant price, so it includes the fee.
      const unitPrice = Number(line.cost.amountPerQuantity.amount) + fee;
      return {
        lineUpdate: {
          cartLineId: line.id,
          title: `${title}${config.titleSuffix}`,
          price: { adjustment: { fixedPricePerUnit: { amount: unitPrice.toFixed(2) } } },
        },
      };
    });

  return { operations };
}
Test girdisi ve beklenen çıktı
tests/blank-engraving.input.json
{
  "presentmentCurrencyRate": "1.0",
  "cart": {
    "lines": [
      {
        "id": "gid://shopify/CartLine/1",
        "engraving": { "value": "   " },
        "cost": { "amountPerQuantity": { "amount": "49.0" } },
        "merchandise": { "__typename": "ProductVariant", "product": { "title": "Brass Pocket Watch" } }
      }
    ]
  },
  "cartTransform": { "metafield": null }
}
tests/blank-engraving.output.json
{ "operations": [] }
tests/converted-fee.input.json
{
  "presentmentCurrencyRate": "1.25",
  "cart": {
    "lines": [
      {
        "id": "gid://shopify/CartLine/1",
        "engraving": { "value": "JS" },
        "cost": { "amountPerQuantity": { "amount": "80.0" } },
        "merchandise": { "__typename": "ProductVariant", "product": { "title": "Leather Wallet" } }
      }
    ]
  },
  "cartTransform": { "metafield": { "jsonValue": { "fee": 8, "titleSuffix": " · monogrammed" } } }
}
tests/converted-fee.output.json
{
  "operations": [
    {
      "lineUpdate": {
        "cartLineId": "gid://shopify/CartLine/1",
        "title": "Leather Wallet · monogrammed",
        "price": { "adjustment": { "fixedPricePerUnit": { "amount": "90.00" } } }
      }
    }
  ]
}
tests/engraved-line.input.json
{
  "presentmentCurrencyRate": "1.0",
  "cart": {
    "lines": [
      {
        "id": "gid://shopify/CartLine/1",
        "engraving": { "value": "For Ada, 2026" },
        "cost": { "amountPerQuantity": { "amount": "49.0" } },
        "merchandise": { "__typename": "ProductVariant", "product": { "title": "Brass Pocket Watch" } }
      },
      {
        "id": "gid://shopify/CartLine/2",
        "engraving": null,
        "cost": { "amountPerQuantity": { "amount": "49.0" } },
        "merchandise": { "__typename": "ProductVariant", "product": { "title": "Brass Pocket Watch" } }
      }
    ]
  },
  "cartTransform": { "metafield": null }
}
tests/engraved-line.output.json
{
  "operations": [
    {
      "lineUpdate": {
        "cartLineId": "gid://shopify/CartLine/1",
        "title": "Brass Pocket Watch (engraved)",
        "price": { "adjustment": { "fixedPricePerUnit": { "amount": "59.00" } } }
      }
    }
  ]
}

Lintel tarafından yazıldı. MIT lisansı: kendi mağazanızda da müşteri işlerinizde de ücretsiz kullanabilirsiniz.

Sınırlar ve özel durumlar

  • Shopify Plus ya da geliştirme mağazası olmayan mağazalarda lineUpdate reddedilir.
  • Aynı anda ayrılan (expand) ya da birleştirilen (merge) bir satır güncellenemez; Shopify lineUpdate’i yok sayar.
  • Ücret presentmentCurrencyRate ile çevrilir; input ve output’taki fiyatlar müşterinin para birimindedir.
  • Function’ın değiştirdiği adlar sepette, checkout’ta ve bildirim e-postalarında yalnızca şablon item.title ya da line.title kullanıyorsa görünür.

Sık sorulan sorular

Shopify’da gravür için nasıl ek ücret alınır?
Shopify Plus’ta, bu örnekteki gibi lineUpdate kullanan bir cart transform gravürlü satırın fiyatını artırabilir. Diğer planlarda sepete ayrı bir ücret ürünü ekleyin.
Fiyatı neden temada değiştirmiyoruz?
Temadaki fiyatlar yalnızca gösterimdir. Müşterinin ödediği fiyat sunucu tarafında belirlenir; bir varyanttan, indirimden ya da cart transform’dan gelmelidir.
Mağazam Shopify Plus değilse ne yapabilirim?
Tema tarafından gravürlü ürünle birlikte sepete eklenen ayrı bir “gravür ücreti” ürünü kullanın.
  • Function API sürümü 2026-10 için yazıldı ve gösterilen tarihte Shopify’ın başvuru belgeleriyle karşılaştırıldı. Shopify her çeyrekte yeni bir sürüm yayımlar.
  • Function içeren özel (custom) uygulamalar yalnızca Shopify Plus mağazalarında çalışır. Aynı Function herkese açık bir uygulamada, sayfada aksi yazmıyorsa her planda çalışır.
  • Her örnek test verileriyle gelir ve yayımlamadan önce bu testleri çalıştırırız. Kodu değiştirdikten sonra testleri tekrar çalıştırın: shopify app function run.
  • MIT lisansı. Kodu kendi mağazanızda da müşteri işlerinizde de kullanabilirsiniz.

Mağazanız için kurulmasını, test edilmesini ve bakımını isterseniz: Shopify Functions geliştirme.

Geliştirmek istediğiniz bir şey mi var? Gelin, birlikte konuşalım.

Aynı anda sınırlı sayıda proje alıyoruz.

Gencer KarakayaShopify mühendisi

Proje özetinizi bir mühendis okur; size e-postayla yanıt veririz.