E-Ticaret Panel
Mağazalar
Mağaza Düzenle
Mağaza Adı
XML Linki
Shopify Store Name
.myshopify.com
Access Token
API Version
2025-07 (En Güncel - Önerilen)
2025-04
2025-01
2024-10
2024-07
2024-04 (Legacy)
2024-01 (Legacy)
Mevcut: 2025-07
Kontrol Süresi
Saniye
Dakika
Saat
Gün
Product Path (Opsiyonel)
XML'de ürünlerin bulunduğu path
🏷️ Vendor (Marka) Filtreleme
📦 Tüm markalar işleniyor
← Ana sayfadan "Filtre Ekle" butonuyla vendor seçimi yapabilirsiniz
Converter Kodunuz
// productPath: "Products.Product" (örneğin) // "Src cannot be blank" hatasını engellemek için aşırı güvenli sürüm module.exports = function (item, utils) { // ---- helpers ---- const one = (v) => Array.isArray(v) ? v[0] : v; const txt = (v) => (v && typeof v === 'object' && '_' in v) ? v._ : v; const get = (k, d='') => { const val = txt(one(item[k])); return (val === undefined || val === null) ? d : String(val).trim(); }; const validUrl = (u) => utils.isValidUrl(String(u || '').trim()); // meta const name = get('Name'); const brand = get('Brand'); const mainCategory = get('mainCategory'); const category = get('category'); const subCategory = get('subCategory'); // ürün-level görseller: Image1..ImageN gibi const productImages = Object.keys(item) .filter(k => /^Image\d+$/i.test(k)) .map(k => String(one(item[k]) || '').trim()) .filter(validUrl); // base alanlar const prodCode = get('Product_code') || get('Product_id'); const baseHandle = utils.toHandle(name || prodCode || ('p-' + Date.now())); const base = { __PRODUCT_KEY: prodCode || baseHandle, Handle: baseHandle, Title: utils.normalizeTitle(name || prodCode || 'Ürün'), 'Body (HTML)': utils.cleanHTML(get('Description') || ''), Vendor: utils.normalizeVendor(brand || ''), Type: utils.normalizeProductType(subCategory || category || mainCategory || ''), Tags: utils.formatTags([mainCategory, category, subCategory].filter(Boolean)), Published: 'TRUE', Status: 'active', 'Google Shopping / Brand': utils.normalizeVendor(brand || '') }; // fiyat fallback const productPrice = utils.formatPrice(get('Price')); // varyantlar const variantsNode = item.variants && one(item.variants); const variantsArr = variantsNode && variantsNode.variant ? (Array.isArray(variantsNode.variant) ? variantsNode.variant : [variantsNode.variant]) : []; // Tekil varyant görsel toplama fonksiyonu function getVariantPictures(vObj) { const pics = vObj.picture ? (Array.isArray(vObj.picture) ? vObj.picture : [vObj.picture]) : []; return pics.map(p => String(txt(p) || '').trim()).filter(validUrl); } let imagePosition = 1; const rows = []; // Eğer varyant varsa: hepsini yaz if (variantsArr.length > 0) { variantsArr.forEach((vObj, idx) => { const specs = vObj.spec ? (Array.isArray(vObj.spec) ? vObj.spec : [vObj.spec]) : []; const specMap = specs.reduce((acc, s) => { const key = String(s?.$?.name || '').toLowerCase(); const val = String(txt(s) || '').trim(); if (key) acc[key] = val; return acc; }, {}); const renk = specMap['renk'] || ''; const beden = specMap['beden'] || ''; const rawSku = txt(one(vObj.productCode)) || ''; const rawBarcode = txt(one(vObj.barcode)) || ''; const vBarcode = utils.validateBarcode(rawBarcode) || ''; const skuSafe = utils.normalizeSKU(rawSku || vBarcode || (prodCode ? prodCode + '-' + renk + '-' + beden : baseHandle + '-' + renk + '-' + beden)); const vQty = utils.formatInventory(txt(one(vObj.quantity)) || 0); const vPriceRaw = txt(one(vObj.price)); const vPrice = utils.formatPrice((vPriceRaw && vPriceRaw !== '0' && vPriceRaw !== '0.00') ? vPriceRaw : productPrice); const varPics = getVariantPictures(vObj); const row = { ...base, // Options (yalnızca değer varsa yaz) ...(renk ? { 'Option1 Name': 'Renk', 'Option1 Value': utils.normalizeOption(renk) } : {}), ...(beden ? { 'Option2 Name': 'Beden', 'Option2 Value': utils.normalizeOption(beden) } : {}), // Variant core 'Variant SKU': skuSafe, 'Variant Price': vPrice, 'Variant Inventory Qty': vQty, 'Variant Inventory Tracker': 'shopify', 'Variant Inventory Policy': utils.validateInventoryPolicy('deny'), 'Variant Fulfillment Service': utils.validateFulfillmentService('manual'), 'Variant Requires Shipping': 'TRUE', 'Variant Taxable': utils.boolToString(true), ...(vBarcode ? { 'Variant Barcode': vBarcode } : {}), 'Variant Weight Unit': 'kg', 'Variant Grams': 0 }; // İlk varyant satırına ürün ana görselini koy (varsa) if (idx === 0 && productImages.length > 0) { row['Image Src'] = productImages[0]; row['Image Position'] = imagePosition++; row['Image Alt Text'] = base.Title; } // Varyantın ilk resmi varsa Variant Image olarak yaz (Shopify bunu varyanta bağlar) if (varPics.length > 0) { row['Variant Image'] = varPics[0]; } rows.push(row); // Varyantın ekstra görselleri -> image-only satır (yalnızca geçerli URL ise) if (varPics.length > 1) { for (let i = 1; i < varPics.length; i++) { const src = varPics[i]; if (!validUrl(src)) continue; // güvenlik rows.push({ Handle: base.Handle, 'Image Src': src, 'Image Position': imagePosition++, 'Image Alt Text': `${base.Title}${renk ? ' - ' + renk : ''}${beden ? ' ' + beden : ''}` }); } } }); // Ürün-level ekstra görseller -> image-only satır if (productImages.length > 1) { for (let i = 1; i < productImages.length; i++) { const src = productImages[i]; if (!validUrl(src)) continue; rows.push({ Handle: base.Handle, 'Image Src': src, 'Image Position': imagePosition++, 'Image Alt Text': base.Title }); } } } // Varyant yoksa: tek satır ve varsa görseller if (rows.length === 0) { const finalSku = utils.normalizeSKU(prodCode || baseHandle); const firstRow = { ...base, 'Variant SKU': finalSku, 'Variant Price': productPrice, 'Variant Inventory Qty': utils.formatInventory(get('Stock') || 0), 'Variant Inventory Tracker': 'shopify', 'Variant Inventory Policy': utils.validateInventoryPolicy('deny'), 'Variant Fulfillment Service': utils.validateFulfillmentService('manual'), 'Variant Requires Shipping': 'TRUE', 'Variant Taxable': utils.boolToString(true), 'Variant Weight Unit': 'kg', 'Variant Grams': 0 }; // varsa ilk görseli ekle if (productImages.length > 0) { firstRow['Image Src'] = productImages[0]; firstRow['Image Position'] = imagePosition++; firstRow['Image Alt Text'] = base.Title; } rows.push(firstRow); // kalan görseller image-only (sadece src geçerliyse) if (productImages.length > 1) { for (let i = 1; i < productImages.length; i++) { const src = productImages[i]; if (!validUrl(src)) continue; rows.push({ Handle: base.Handle, 'Image Src': src, 'Image Position': imagePosition++, 'Image Alt Text': base.Title }); } } } // EK GÜVENLİK: image-only satırlarda Image Src zorunlu; boşsa satırı tamamen sil. const safeRows = rows.filter(r => { const hasSku = r['Variant SKU'] && String(r['Variant SKU']).trim() !== ''; const hasImage = r['Image Src'] && String(r['Image Src']).trim() !== ''; // image-only ise src zorunlu if (!hasSku && !hasImage) return false; // src varsa ama geçersizse çıkar if (r['Image Src'] && !validUrl(r['Image Src'])) return false; // alt text sadece src varsa anlamlı if (!hasImage) { delete r['Image Alt Text']; delete r['Image Position']; } // boş Variant Image kolonunu hiç yazma if (!r['Variant Image']) delete r['Variant Image']; return true; }); return safeRows; };
Güncelle
İptal
İstatistikler
Toplam Çalışma
3592
Başarı Oranı
92%
İşlenen Ürün
0
Push Edilen
0