Koleksiyon hariç, tutar üstü ücretsiz kargo

Sepet tutarı bir sınırı aşınca ücretsiz kargo veren, hariç tutulan koleksiyonlardaki ürünleri bu tutara saymayan Shopify indirim Function’ı.

Function API
Discount
Hedef (target)
cart.delivery-options.discounts.generate.run
İndirim sınıfı
SHIPPING
Plan
Herkese açık uygulamada her plan; özel uygulamada Shopify Plus
Uygulama yetkisi
write_discounts
API sürümü
2026-10
Son kontrol

Kısaca

Bu indirim Function’ı, sepet bir eşiğe (varsayılan olarak mağaza para biriminde 1.000) ulaşınca ücretsiz kargo verir; tutara yalnızca hariç tuttuğunuz koleksiyonların dışındaki ürünleri sayar. Koleksiyonlar sorguya input değişkeni olarak gider. Discount Function API’nin cart.delivery-options.discounts.generate.run hedefini kargo indirim sınıfıyla (SHIPPING) kullanır, sürüm 2026-10.

Nasıl kullanılır

  1. Shopify CLI 4.9.0 ya da üstüyle bir uygulama oluşturun ve uzantıyı ekleyin: shopify app generate extension --template discount, dil olarak JavaScript.
  2. Yalnızca teslimat hedefini bırakın: shopify.extension.toml ve src/ dosyalarını aşağıdakilerle değiştirin.
  3. Testleri çalıştırın: shopify app function run --input tests/above-threshold.input.json.
  4. shopify app deploy ile deploy edin ve discountAutomaticAppCreate ile discountClasses: [SHIPPING] olan otomatik bir indirim oluşturun.
  5. İndirimin $app:function-configuration metafield’ını ayarlayın; örneğin {"minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"]}.

Kod

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

[[extensions]]
name = "Free shipping above a total, excluding a collection"
handle = "free-shipping-excluding-collection"
type = "function"

  [[extensions.targeting]]
  target = "cart.delivery-options.discounts.generate.run"
  input_query = "src/cart_delivery_options_discounts_generate_run.graphql"
  input_variables = { namespace = "$app", key = "function-configuration" }
  export = "cart-delivery-options-discounts-generate-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
src/cart_delivery_options_discounts_generate_run.graphql
query CartDeliveryOptionsDiscountsGenerateRunInput($excludedCollectionIds: [ID!]) {
  cart {
    lines {
      cost {
        subtotalAmount {
          amount
        }
      }
      merchandise {
        __typename
        ... on ProductVariant {
          product {
            inAnyCollection(ids: $excludedCollectionIds)
          }
        }
      }
    }
    deliveryGroups {
      id
    }
  }
  presentmentCurrencyRate
  discount {
    discountClasses
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
src/cart_delivery_options_discounts_generate_run.js
// @ts-check

/**
 * @typedef {import("../generated/api").CartDeliveryOptionsDiscountsGenerateRunInput} CartDeliveryOptionsDiscountsGenerateRunInput
 * @typedef {import("../generated/api").CartDeliveryOptionsDiscountsGenerateRunResult} CartDeliveryOptionsDiscountsGenerateRunResult
 */

/**
 * Settings stored as JSON in the discount's metafield. The same metafield
 * feeds the query's $excludedCollectionIds variable (see input_variables in
 * shopify.extension.toml), so Shopify checks collection membership.
 */
const DEFAULT_CONFIG = {
  // In the store's currency; converted to the customer's currency below.
  minimumAmount: 1000,
  message: "Free shipping",
};

/** @type {CartDeliveryOptionsDiscountsGenerateRunResult} */
const NO_DISCOUNT = { operations: [] };

/**
 * @param {CartDeliveryOptionsDiscountsGenerateRunInput} input
 * @returns {CartDeliveryOptionsDiscountsGenerateRunResult}
 */
export function cartDeliveryOptionsDiscountsGenerateRun(input) {
  // A Function may only return operations for the classes the discount was created with.
  if (!input.discount.discountClasses.includes("SHIPPING")) return NO_DISCOUNT;
  const config = { ...DEFAULT_CONFIG, ...input.discount.metafield?.jsonValue };

  // Products in an excluded collection (gift cards, sale items, oversized goods)
  // don't count towards the threshold.
  const qualifyingSubtotal = input.cart.lines
    .filter((line) => !(line.merchandise.__typename === "ProductVariant" && line.merchandise.product.inAnyCollection))
    .reduce((sum, line) => sum + Number(line.cost.subtotalAmount.amount), 0);
  const minimum = config.minimumAmount * Number(input.presentmentCurrencyRate);
  if (qualifyingSubtotal < minimum || input.cart.deliveryGroups.length === 0) return NO_DISCOUNT;

  return {
    operations: [
      {
        deliveryDiscountsAdd: {
          candidates: [
            {
              message: config.message,
              targets: input.cart.deliveryGroups.map((group) => ({ deliveryGroup: { id: group.id } })),
              value: { percentage: { value: "100" } },
            },
          ],
          selectionStrategy: "ALL",
        },
      },
    ],
  };
}
Test girdisi ve beklenen çıktı
tests/above-threshold.input.json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "80.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } },
      { "cost": { "subtotalAmount": { "amount": "35.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["SHIPPING"],
    "metafield": { "jsonValue": { "minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"] } }
  }
}
tests/above-threshold.output.json
{
  "operations": [
    {
      "deliveryDiscountsAdd": {
        "candidates": [
          {
            "message": "Free shipping",
            "targets": [{ "deliveryGroup": { "id": "gid://shopify/CartDeliveryGroup/1" } }],
            "value": { "percentage": { "value": "100" } }
          }
        ],
        "selectionStrategy": "ALL"
      }
    }
  ]
}
tests/excluded-items-dont-count.input.json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "80.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } },
      { "cost": { "subtotalAmount": { "amount": "60.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": true } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": {
    "discountClasses": ["SHIPPING"],
    "metafield": { "jsonValue": { "minimumAmount": 100, "excludedCollectionIds": ["gid://shopify/Collection/1234567890"] } }
  }
}
tests/excluded-items-dont-count.output.json
{ "operations": [] }
tests/no-shipping-class.input.json
{
  "cart": {
    "lines": [
      { "cost": { "subtotalAmount": { "amount": "1500.0" } }, "merchandise": { "__typename": "ProductVariant", "product": { "inAnyCollection": false } } }
    ],
    "deliveryGroups": [{ "id": "gid://shopify/CartDeliveryGroup/1" }]
  },
  "presentmentCurrencyRate": "1.0",
  "discount": { "discountClasses": ["ORDER"], "metafield": null }
}
tests/no-shipping-class.output.json
{ "operations": [] }

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

  • Satır ara toplamları müşterinin para birimindedir; minimum presentmentCurrencyRate ile çevrilir.
  • İndirim her teslimat grubuna, gruptaki tüm seçeneklerle birlikte uygulanır. Yalnızca en ucuz seçeneğe vermek için deliveryOption handle’larını hedefleyin.
  • Liste tipindeki bir input değişkeni en fazla 100 koleksiyon kimliği alabilir.

Sık sorulan sorular

Shopify’da ücretsiz kargo sınırından bazı ürünleri nasıl hariç tutarım?
Bu örnekteki gibi, toplamı hesaplarken seçtiğiniz koleksiyonlardaki satırları dışarıda bırakan bir kargo indirimi Function’ı kullanın.
Ücretsiz kargo yalnızca standart gönderime uygulanabilir mi?
Evet. deliveryOptions’ı handle ve title ile sorgulayın ve yalnızca eşleşen seçeneği deliveryOption: {handle} ile hedefleyin.
Eşik birden fazla para birimiyle çalışır mı?
Evet. Eşiği mağaza para biriminde belirleyin; Function sepetle karşılaştırmadan önce onu presentmentCurrencyRate ile çarpar.
  • 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.