Ürün başına minimum ve maksimum adet
Her ürün için minimum ve maksimum sipariş adedini iki ürün metafield’ından okuyup uygulayan Shopify doğrulama Function’ı; test edilmiş JavaScript.
- Function API
- Cart and Checkout Validation
- Hedef (target)
- cart.validations.generate.run
- Plan
- Herkese açık uygulamada her plan; özel uygulamada Shopify Plus
- Uygulama yetkisi
- write_validations
- API sürümü
- 2026-10
- Son kontrol
Kısaca
Bu doğrulama Function’ı, ürün başına minimum ve maksimum adet uygular; ürünün tüm varyantlarını birlikte sayar. Sınırlar, mağaza sahibinin yönetim panelinden düzenlediği iki tam sayı (Integer) ürün metafield’ından gelir. Cart and Checkout Validation API’nin cart.validations.generate.run hedefini kullanır (sürüm 2026-10) ve herkese açık bir uygulamada her planda çalışır.
Nasıl kullanılır
- Yönetim panelinde Integer tipinde iki ürün metafield tanımı oluşturun: custom.min_quantity ve custom.max_quantity.
- Shopify CLI ile bir uygulama oluşturun ve uzantıyı ekleyin: shopify app generate extension --template cart_checkout_validation, dil olarak JavaScript.
- Oluşturulan shopify.extension.toml dosyasını ve src/ içindeki iki dosyayı aşağıdakilerle değiştirin, ardından testleri shopify app function run ile çalıştırın.
- shopify app deploy ile deploy edin ve doğrulamayı validationCreate ile etkinleştirin.
- Sınır gereken ürünlerde değerleri doldurun; değeri boş ürünlerde sınır yoktur.
Kod
shopify.extension.tomlapi_version = "2026-10"
[[extensions]]
name = "Minimum and maximum quantity per product"
handle = "min-max-quantity-per-product"
type = "function"
[[extensions.targeting]]
target = "cart.validations.generate.run"
input_query = "src/cart_validations_generate_run.graphql"
export = "cart-validations-generate-run"
[extensions.build]
command = ""
path = "dist/function.wasm"
src/cart_validations_generate_run.graphqlquery CartValidationsGenerateRunInput {
buyerJourney {
step
}
cart {
lines {
quantity
merchandise {
__typename
... on ProductVariant {
product {
id
title
minQuantity: metafield(namespace: "custom", key: "min_quantity") {
value
}
maxQuantity: metafield(namespace: "custom", key: "max_quantity") {
value
}
}
}
}
}
}
}
src/cart_validations_generate_run.js// @ts-check
/**
* @typedef {import("../generated/api").CartValidationsGenerateRunInput} CartValidationsGenerateRunInput
* @typedef {import("../generated/api").CartValidationsGenerateRunResult} CartValidationsGenerateRunResult
*/
/** Errors about the cart as a whole show at the top of checkout and on the cart. */
const CART_TARGET = "$.cart";
/** @param {{value: string} | null | undefined} metafield */
function readLimit(metafield) {
const limit = Number.parseInt(metafield?.value ?? "", 10);
return Number.isInteger(limit) && limit > 0 ? limit : null;
}
/**
* @param {CartValidationsGenerateRunInput} input
* @returns {CartValidationsGenerateRunResult}
*/
export function cartValidationsGenerateRun(input) {
// While the cart is being built, a shopper adding one unit at a time would be
// stopped by the minimum before reaching it; enforce it from checkout on.
const checkMinimum = input.buyerJourney?.step !== "CART_INTERACTION";
// Limits are per product, so add up all variants (sizes, colors) of it.
/** @type {Map<string, {title: string, quantity: number, min: number | null, max: number | null}>} */
const products = new Map();
for (const line of input.cart.lines) {
if (line.merchandise.__typename !== "ProductVariant") continue;
const { product } = line.merchandise;
const entry = products.get(product.id) ?? {
title: product.title,
quantity: 0,
min: readLimit(product.minQuantity),
max: readLimit(product.maxQuantity),
};
entry.quantity += line.quantity;
products.set(product.id, entry);
}
const errors = [];
for (const { title, quantity, min, max } of products.values()) {
if (checkMinimum && min !== null && quantity < min) {
errors.push({ message: `${title}: the minimum order quantity is ${min}.`, target: CART_TARGET });
} else if (max !== null && quantity > max) {
errors.push({ message: `${title}: you can buy at most ${max}.`, target: CART_TARGET });
}
}
return { operations: errors.length > 0 ? [{ validationAdd: { errors } }] : [] };
}
Test girdisi ve beklenen çıktı
tests/above-maximum.input.json{
"cart": {
"lines": [
{
"quantity": 3,
"merchandise": {
"__typename": "ProductVariant",
"product": { "id": "gid://shopify/Product/1234567892", "title": "Limited Sneaker", "minQuantity": null, "maxQuantity": { "value": "2" } }
}
}
]
}
}
tests/above-maximum.output.json{
"operations": [
{ "validationAdd": { "errors": [{ "message": "Limited Sneaker: you can buy at most 2.", "target": "$.cart" }] } }
]
}
tests/below-minimum-across-variants.input.json{
"cart": {
"lines": [
{
"quantity": 1,
"merchandise": {
"__typename": "ProductVariant",
"product": { "id": "gid://shopify/Product/1234567890", "title": "Linen Napkin", "minQuantity": { "value": "4" }, "maxQuantity": null }
}
},
{
"quantity": 2,
"merchandise": {
"__typename": "ProductVariant",
"product": { "id": "gid://shopify/Product/1234567890", "title": "Linen Napkin", "minQuantity": { "value": "4" }, "maxQuantity": null }
}
}
]
}
}
tests/below-minimum-across-variants.output.json{
"operations": [
{ "validationAdd": { "errors": [{ "message": "Linen Napkin: the minimum order quantity is 4.", "target": "$.cart" }] } }
]
}
tests/below-minimum-while-building-cart.input.json{
"buyerJourney": {
"step": "CART_INTERACTION"
},
"cart": {
"lines": [
{
"quantity": 1,
"merchandise": {
"__typename": "ProductVariant",
"product": {
"id": "gid://shopify/Product/1234567890",
"title": "Linen Napkin",
"minQuantity": {
"value": "4"
},
"maxQuantity": null
}
}
},
{
"quantity": 2,
"merchandise": {
"__typename": "ProductVariant",
"product": {
"id": "gid://shopify/Product/1234567890",
"title": "Linen Napkin",
"minQuantity": {
"value": "4"
},
"maxQuantity": null
}
}
}
]
}
}tests/below-minimum-while-building-cart.output.json{
"operations": []
}tests/within-limits.input.json{
"cart": {
"lines": [
{
"quantity": 4,
"merchandise": {
"__typename": "ProductVariant",
"product": {
"id": "gid://shopify/Product/1234567890",
"title": "Linen Napkin",
"minQuantity": { "value": "4" },
"maxQuantity": { "value": "24" }
}
}
},
{
"quantity": 1,
"merchandise": {
"__typename": "ProductVariant",
"product": { "id": "gid://shopify/Product/1234567891", "title": "Gift Card Sleeve", "minQuantity": null, "maxQuantity": null }
}
}
]
}
}
tests/within-limits.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
- Adetler ürün bazında toplanır; 2 küçük ve 2 büyük beden 4 sayılır.
- Hatalar sepet sayfasında ve checkout’ta görünür. Storefront API de onları Cart nesnesinde döndürür.
- Mesajlar kodda İngilizce; birden fazla dilde gerekiyorsa input sorgusunda localization.language’ı okuyun.
- Her metafield okuması, bir Function input’unun kullanabileceği 30 sorgu maliyeti puanından 3’ünü harcar; ürün başına iki metafield sorun değildir.
Sık sorulan sorular
- Shopify’da bir ürün için minimum sipariş adedi nasıl belirlenir?
- Bu örnekteki gibi minimumu bir ürün metafield’ından okuyup altında checkout’u engelleyen bir doğrulama Function’ı kullanın. Herkese açık bir uygulamada her planda çalışır.
- Bir müşterinin bir üründen kaç adet alacağını sınırlayabilir miyim?
- Sipariş başına evet: custom.max_quantity’yi ayarlayın. Birden fazla siparişe yayılan sınır için müşterinin ürün bazında geçmiş siparişleri gerekir; Function input’unda bu bilgi yok.
- Temadaki adet seçici bu sınırlara uyar mı?
- Hayır. Function, sepete maksimumdan fazla ürün eklenmesini durdurur; minimumu ise checkout’tan itibaren kontrol eder, böylece müşteri sepetini minimuma kadar doldurabilir. Daha akıcı bir deneyim için aynı metafield’ları temada okuyup adet alanına min ve max değerlerini verin.
Shopify belgeleri
- 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.
