FShop Açık Kaynak Ücretsiz E-Ticaret Yazılımı

@admin•5 gün önce (05 Kas 2026)•561 görüntülenme•32 yanıt
a
Mehmet Sancak@admin Yönetici
5 gün önce#1
  • Site Adı: FShop E-ticaret
  • Site Adresi: https://fyazilim.com/fshop/
  • Açıklama: Türkiye'nin açık kaynak ücretsiz ve kolay geliştirilebilir e ticaret yazılımı
  • Açıldığı Tarih: Temmuz 2026

Ekli Görseller (1)

Ekli Dosyalar (1)

frisay-3.0.2.zip
11.1 MB• 12 indirme
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#2

Blue

Modern theme

blue (1).zip(448.1 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#3

FYazılım Template

New theme v2+

fyazilim (1).zip(403.8 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#4

Dress Template

Template for V2.5.5+

dress (1).zip(618.2 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#5

Shopmore

New theme v2+

shopmore (1).zip(442.6 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#6

Modern Store

Multi colors and Customize Template

modern-store (1).zip(255.2 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#7

Paytr Module

Accept credit card payments.


Trendyol Module

Product transfer, order and inquiry integration with Trendyol


Point Of Sale

Quick-sale screen for restaurants, cafes, and markets.

pos (2).zip(50.2 KB)
İndir
paytr-module (1).zip(17 KB)
İndir
modern-store (1).zip(255.2 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#8

Tüm Eklentiler

product-files (2).zip(581.1 KB)
İndir
akakce (2).zip(18.2 KB)
İndir
barcode (1).zip(24.1 KB)
İndir
product-files (1).zip(581.1 KB)
İndir
iyzico (1).zip(26.4 KB)
İndir
question (1).zip(29.2 KB)
İndir
google-shopping (1).zip(31.5 KB)
İndir
blog (1).zip(34.8 KB)
İndir
paytr-taksit (1).zip(11.3 KB)
İndir
nkolaypay (1).zip(19.7 KB)
İndir
bizimhesap (1).zip(15 KB)
İndir
smart-campaign (1).zip(26.4 KB)
İndir
parampos (1).zip(17.3 KB)
İndir
discount-timer (1).zip(24 KB)
İndir
esnekpos (1).zip(23.9 KB)
İndir
backup-pro (1).zip(55.1 KB)
İndir
google-analytics (1).zip(31.3 KB)
İndir
story (1).zip(20.7 MB)
İndir
xml-import (1).zip(31.4 KB)
İndir
ai-chat (2).zip(59.1 KB)
İndir
a
Mehmet Sancak@admin Yönetici
5 gün önce#9
Entegrasyona Hoş Geldiniz

Bu portal, FriSay (FShop) e-ticaret platformunu entegre etmek, Web API ile ürün/sipariş senkronize etmek, vitrin AJAX uçlarını kullanmak ve modül / tema geliştirmek için dokümantasyon sağlar.

Nereden başlamalı?

  1. Hızlı Başlangıç — uçtan uca partner entegrasyon akışı
  2. API Kuralları — sayfalama, hatalar, rate limit
  3. Kimlik Doğrulama — API anahtarı ve izinler
  4. Endpoint sayfaları — ürünler, katalog, siparişler
  5. Modül / Tema — platformu genişletme

Nasıl kullanılır?

  1. FriSay yönetim panelinde API bölümüne gidin.
  2. Web API özelliğini etkinleştirin ve bir anahtar oluşturun (izinleri iş ortağına göre ayarlayın).
  3. Her istekte anahtarı X-API-Key başlığıyla gönderin.
  4. PHP ve cURL örnekleri için ilgili endpoint sayfalarını takip edin.

Temel URL

OrtamURL
Canlıhttps://yoursite.com/api/v1/
Yerelhttp://localhost/fshop/api/v1/

Bu portalda neler var?

Bölümİçerik
BaşlangıçHızlı başlangıç, kurallar, kimlik doğrulama
Ürünler / Katalog / SiparişlerPartner Web API (/api/v1)
Vitrin ve OperasyonTema AJAX API, cron / döviz / pazaryeri
GeliştiricilerModül, ödeme modülü, hook, sabitler, tema

Genel Bilgiler

  • Canlı ortamda HTTPS tercih edin.
  • İstek / yanıt formatı JSON (UTF-8) şeklindedir.
  • POST/PATCH isteklerinde Content-Type: application/json gönderin.
  • API sürümü: v1
  • Ürün sayfası 1 tabanlı; sipariş sayfası 0 tabanlıdır — ayrıntılar için API Kuralları.

HTTP Durum Kodları

KodAnlam
200Başarılı
201Oluşturuldu (ör. yeni ürün / görsel)
400Geçersiz istek
403API kapalı veya geçersiz anahtar
404Kayıt bulunamadı
422Doğrulama hatası
429Rate limit aşıldı
503API anahtarı yapılandırılmamış

Test Sitesi

https://fyazilim.com/fshop/admin

User: admin@fyazilim.com

Pass: admin123

API Key: Admin → API

a
Mehmet Sancak@admin Yönetici
5 gün önce#10
Hızlı Başlangıç

Bu rehber, iş ortağının FriSay Web API ile uçtan uca entegrasyonunu adım adım özetler: API anahtarı, katalog, ürün, sipariş, kargo ve fatura.

Test sitesi: https://fyazilim.com/fshop/admin — kullanıcı admin@fyazilim.com / admin123. API anahtarını Yönetim → API bölümünden alın. Ayrıntılar için Giriş sayfasına bakın.

Adım adım

  1. Yönetim panelinde Web API özelliğini etkinleştirin ve uygun kapsamlarla (ürün / sipariş okuma-yazma vb.) bir anahtar oluşturun. Bkz. Kimlik Doğrulama.
  2. Kategori ve marka listelerini çekin; ürün oluştururken ID veya ad kullanabilirsiniz. Bkz. Kategorileri Listele, Markaları Listele.
  3. Ürün oluşturun (ad, kategori, marka, fiyat zorunlu), ardından görsel yükleyin. Bkz. Ürün Ekle, Görsel Yükle, Ürünleri Listele.
  4. Siparişleri periyodik olarak sorgulayın (page 0 tabanlıdır); durum ve tarih filtrelerini kullanın. Bkz. Siparişleri Listele.
  5. Kargoya verirken durumu güncelleyin ve kargo firması + takip numarası gönderin. Bkz. Sipariş Durumunu Güncelle.
  6. Sevkiyattan sonra herkese açık fatura URL'sini siparişe ekleyin. Bkz. Sipariş Faturası.

Önerilen akış

SıraİşlemEndpoint / sayfa
1API anahtarı + kapsamlarauthentication
2Kategori / marka keşfiGET /categories, GET /brands
3Ürün oluştur + görseladd-product → POST /products/{id}/image
4Siparişleri tara (poll)list-orders (page=0)
5Durum + kargo takibiupdate-order-status
6Fatura URL'siorder-invoice
Önemli: Sipariş, kategori ve marka listelerinde sayfa numarası 0 tabanlıdır; ürün listesinde ise 1 tabanlıdır. Ayrıntılar için API Kuralları sayfasına bakın.

İlgili sayfalar

PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest($method, $url, $apiKey, $data = null)
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

// 1) List categories (0-based page)
$categories = apiRequest('GET', $baseUrl . '/categories?page=0&size=50&active=1', $apiKey);

// 2) Create a simple product
$created = apiRequest('POST', $baseUrl . '/products', $apiKey, [
    'name' => 'API Demo Product',
    'category' => 'Test Category',
    'brand' => 'Test Brand',
    'price' => 149.90,
    'stock' => 20,
    'active' => 1,
    'stock_code' => 'DEMO-001',
]);
$productId = (int) ($created['response']['data']['id'] ?? 0);

// 3) List recent picking orders (0-based page)
$orders = apiRequest(
    'GET',
    $baseUrl . '/orders?page=0&size=20&status=2&date_from=2026-06-01',
    $apiKey
);

print_r([
    'categories_http' => $categories['http_code'],
    'product_id' => $productId,
    'orders_http' => $orders['http_code'],
]);
cURLKopyala
# 1) Smoke test — categories
curl -s -H "X-API-Key: YOUR_API_KEY" -H "Accept: application/json" \
  "https://example.com/api/v1/categories?page=0&size=20"

# 2) Create product
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "API Demo Product",
    "category": "Test Category",
    "brand": "Test Brand",
    "price": 149.90,
    "stock": 20,
    "active": 1,
    "stock_code": "DEMO-001"
  }' \
  "https://example.com/api/v1/products"

# 3) List picking orders (page is 0-based)
curl -s -H "X-API-Key: YOUR_API_KEY" -H "Accept: application/json" \
  "https://example.com/api/v1/orders?page=0&size=20&status=2&date_from=2026-06-01"

# 4) Mark shipped + cargo (replace 15 with order id)
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":3,"cargoCompany":"Yurtiçi Kargo","trackingNumber":"YT123456789"}' \
  "https://example.com/api/v1/orders/15"

# 5) Attach invoice URL
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/fatura.pdf","name":"Invoice"}' \
  "https://example.com/api/v1/orders/15/invoice"
a
Mehmet Sancak@admin Yönetici
5 gün önce#11
API Kuralları

FriSay Web API v1 için ortak kurallar: URL, JSON zarfı, hata biçimi, HTTP kodları, hız limiti, sayfalama ve alan takma adları.

Temel URL ve içerik tipi

  • Canlı: https://yoursite.com/api/v1/
  • Yerel örnek: http://localhost/fshop/api/v1/
  • İstek / yanıt: UTF-8 JSON
  • POST / PUT / PATCH gövdelerinde Content-Type: application/json gönderin
  • Kimlik doğrulama: X-API-Key (önerilen), Bearer veya ?api_key= — bkz. Kimlik Doğrulama
Üretim: Canlı ortamda her zaman HTTPS kullanın. API anahtarını istemci tarafı kodda asla ifşa etmeyin.

Başarı zarfı

Çoğu yanıt şu yapıya yakındır:

{
  "success": true,
  "data": { },
  "content": [ ],
  "message": "",
  "meta": { }
}

Sipariş listesi Trendyol benzeri alanlar da döndürebilir (totalElements, content[]). Ürün oluşturma gibi işlemlerde HTTP durumu 201 olabilir.

Hata gövdesi

{
  "success": false,
  "message": "Açıklayıcı hata metni"
}

HTTP durum kodları

KodAnlam
200Başarılı
201Oluşturuldu (ürün, görsel vb.)
400Geçersiz istek
403API kapalı veya geçersiz / yetkisiz anahtar
404Kayıt bulunamadı
405Yöntem desteklenmiyor
422Doğrulama hatası
429Hız limiti aşıldı
503API anahtarı yapılandırılmamış / servis kullanılamıyor

Hız limiti

  • 300 başarılı istek / 15 dakika / IP
  • Başarısız kimlik doğrulama kilidi: yaklaşık 30 başarısız deneme / 15 dakika

429 aldığınızda geri çekilip yeniden deneyin; anahtarı agresifçe denemeyin.

Sayfalama

Kritik:
  • Ürünler (GET /products): sayfa numarası 1 tabanlıdır (ilk sayfa page=1).
  • Siparişler, kategoriler, markalar: sayfa numarası 0 tabanlıdır (ilk sayfa page=0).
Yanlış tabanı kullanmak boş sayfa veya tekrarlayan kayıtlara yol açar.

_method geçersiz kılma

Bazı istemciler veya proxy'ler PUT / PATCH / DELETE gönderemez. Gerektiğinde POST gövdesinde veya form alanında _method=PUT, _method=PATCH veya _method=DELETE kullanarak gerçek HTTP yöntemini belirtebilirsiniz.

Alan takma adları

Özellikle kargo alanlarında hem camelCase hem snake_case kabul edilir:

  • cargoCompany / cargo_company
  • trackingNumber / tracking_number

Sipariş tarih filtrelerinde date_from / date_to veya milisaniye cinsinden startDate / endDate kullanılabilir.

Webhook yok

Web API v1 webhook göndermez. Yeni veya güncellenen siparişleri almak için siparişleri periyodik olarak sorgulayın (poll). Önerilen yaşam döngüsü için Sipariş Yaşam Döngüsü sayfasına bakın.

İlgili sayfalar

Başarılı yanıt (ürünler)Kopyala
{
  "success": true,
  "data": [],
  "meta": {
    "total": 5,
    "page": 1,
    "limit": 10,
    "pages": 1
  }
}
Hata yanıtıKopyala
{
  "success": false,
  "message": "Geçersiz API anahtarı"
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#12
GEThttps://example.com/api/v1/
Kimlik Doğrulama

Her Web API isteğinde API anahtarınız bulunmalıdır. Anahtarları Yönetim → API bölümünden oluşturun.

Desteklenen Yöntemler (birini kullanın)

YöntemÖrnek
Başlık (önerilen)X-API-Key: YOUR_API_KEY
Bearer tokenAuthorization: Bearer YOUR_API_KEY
Query string?api_key=YOUR_API_KEY
Önemli: API anahtarını istemci tarafı JavaScript veya mobil uygulamalarda asla ifşa etmeyin. API'yi yalnızca sunucunuzdan çağırın.

İzin matrisi

İzin anahtarıAçıklamaEndpoint örnekleri
orders.readSiparişleri oku / çekGET /orders, GET /orders/{id}
orders.writeSipariş güncelle / faturaPATCH /orders/{id}, invoice
products.readÜrünleri okuGET /products, GET /products/{id}
products.createÜrün eklePOST /products
products.updateÜrün / stok / görselPATCH, /quick, /image
products.deleteÜrün silDELETE /products/{id}
categories.readKategorileri okuGET /categories
brands.readMarkaları okuGET /brands

Önerilen anahtar senaryoları

  • ERP / stok: products.read + products.update (+ isteğe bağlı create)
  • Pazaryeri / kargo: orders.read + orders.write
  • Salt okunur rapor: yalnızca *.read izinleri

Rate limit

Başarılı istekler IP başına yaklaşık 300 / 15 dakika ile sınırlıdır. Başarısız kimlik doğrulama denemeleri ayrı olarak kilitlenebilir. Aşımda 429 dönülebilir — ayrıntılar için API Kuralları.

Sık karşılaşılan hatalar

DurumOlası neden
403 Web API kapalıAdmin → API'de Web API kapalı
403 Geçersiz anahtar / yetkiYanlış key veya eksik permission
503Hiç API anahtarı tanımlı değil
Not: Vitrin AJAX uçları (/api/cart.php vb.) API Key kullanmaz; müşteri oturumu + CSRF kullanır. Bkz. Vitrin AJAX API. Cron işleri SHOP_TOKEN kullanır — Cron.
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY'; // Admin → API

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();

    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];

    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }

    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);

    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }

    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    $decoded = json_decode((string) $response, true);

    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

// Connection check — categories
$result = apiRequest('GET', $baseUrl . '/categories', $apiKey);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/categories"
Örnek Yanıt (JSON)Kopyala
{
  "totalElements": 4,
  "content": [
    {
      "id": 3,
      "name": "Vitamin & Takviye",
      "slug": "vitamin-takviye",
      "parentId": 1,
      "parentName": "Sağlık",
      "active": true
    }
  ]
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#13
GEThttps://example.com/api/v1/products
Ürünleri Listele

Sayfalanmış ürün listesini döndürür. Sayfa numaralandırması 1 tabanlıdır (siparişlerden farklı olarak).

Query Parametreleri

ParametreTipZorunluAçıklama
pageintegerHayırSayfa numarası (varsayılan: 1)
limitintegerHayırSayfa başına kayıt (varsayılan: 30, en fazla: 100)
qstringHayırAd, stok kodu veya barkod ile arama
categoryintegerHayırKategori ID'sine göre filtrele
brandintegerHayırMarka ID'sine göre filtrele
activeintegerHayır1 aktif, 0 pasif, -1 tümü (varsayılan)
langstringHayırDil kodu (ör. tr, en)
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest(
    'GET',
    $baseUrl . '/products?page=1&limit=20&q=vitamin&active=1',
    $apiKey
);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/products?page=1&limit=20&q=vitamin&active=1"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "lang": "tr",
  "data": [
    {
      "id": 5,
      "name": "Multivitamin Complex 60 Tablet",
      "slug": "multivitamin-complex-60",
      "url": "https://example.com/multivitamin-complex-60-5",
      "price": 329,
      "old_price": 399,
      "stock": 200,
      "in_stock": true,
      "active": 1,
      "barcode": "8690000000059",
      "stock_code": "DEMO-MULTI60",
      "id_category": 3,
      "category_name": "Vitamin & Takviye",
      "id_brand": 3,
      "brand_name": "FShop Demo",
      "image_url": "https://example.com/img/products/5.jpg",
      "has_variations": false
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "limit": 20,
    "pages": 1
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#14
GEThttps://example.com/api/v1/products/{id}
Ürün Getir

Tek bir ürünü tam detaylarıyla döndürür: açıklamalar, görseller, varyasyonlar ve çeviriler.

URL Parametreleri

ParametreTipAçıklama
idintegerÜrün ID

Query Parametreleri

ParametreTipZorunluAçıklama
langstringHayırYerelleştirilmiş alanlar için tercih edilen dil
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$productId = 6;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest('GET', $baseUrl . '/products/' . (int) $productId, $apiKey);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/products/6"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "lang": "tr",
  "data": {
    "id": 6,
    "name": "Pamuklu Tişört",
    "slug": "pamuklu-tisort",
    "price": 199.99,
    "old_price": 0,
    "stock": 15,
    "active": 1,
    "barcode": "86991233322",
    "stock_code": "fs123",
    "category_name": "Test Category",
    "brand_name": "Test Brand",
    "description_html": "<p>Yumuşak kumaş</p>",
    "has_variations": true,
    "images": [
      {
        "id": 12,
        "url": "https://example.com/img/products/12.jpg",
        "cover": true
      }
    ],
    "variations": [
      {
        "id": 1,
        "sku": "TSH-RED-M",
        "barcode": "8690000001001",
        "options": { "Color": "Red", "Size": "M" },
        "price": 249.9,
        "stock": 12,
        "active": 1
      }
    ],
    "translations": {
      "tr": {
        "name": "Pamuklu Tişört",
        "slug": "pamuklu-tisort",
        "description_html": "<p>Yumuşak kumaş</p>"
      },
      "en": {
        "name": "Cotton T-Shirt",
        "slug": "cotton-t-shirt",
        "description_html": "<p>Soft fabric</p>"
      }
    }
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#15
POSThttps://example.com/api/v1/products
Ürün Ekle

Yeni bir ürün oluşturur. Zorunlu alanlar: ürün adı, kategori, marka ve fiyat. Kategori/marka ID veya ad olarak gönderilebilir (eksik adlar otomatik oluşturulur).

İstek Gövdesi Parametreleri

ParametreTipZorunluAçıklama
namestringEvet*Ürün adı (veya translations kullanın)
category / category_idstring / intEvetKategori adı veya ID
brand / brand_idstring / intEvetMarka adı veya ID
pricefloatEvet*Satış fiyatı (veya doviz_price)
costfloatHayırMaliyet fiyatı
old_pricefloatHayırListe / üzeri çizili fiyat
stockintegerHayırStok miktarı
activeintegerHayır1 veya 0
barcodestringHayırBarkod
stock_codestringHayırSKU / stok kodu
description_htmlstringHayırHTML açıklama
short_descriptionstringHayırKısa metin
vatfloatHayırKDV oranı
dovizstringHayırtry, usd, eur, xau
doviz_pricefloatHayırDöviz cinsinden fiyat
cargo_dayintegerHayırKargo günü
labelstringHayırÜrün etiketi
desifloatHayırDesi / hacimsel ağırlık
translationsobjectHayırDil koduna göre çok dilli alanlar
variationsarrayHayırVaryant satırları (sku, options, price, stock)
Not: Oluşturma sonrası görselleri POST /products/{id}/image ile yükleyin. Başarı durumunda HTTP durumu 201'dir.
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

// Multi-language product with variations
$payload = [
    'translations' => [
        'tr' => [
            'name' => 'Pamuklu Tişört',
            'slug' => 'pamuklu-tisort',
            'description_html' => '<p>Yumuşak kumaş</p>',
        ],
        'en' => [
            'name' => 'Cotton T-Shirt',
            'slug' => 'cotton-t-shirt',
            'description_html' => '<p>Soft fabric</p>',
        ],
    ],
    'category' => 'Test Category',
    'brand' => 'Test Brand',
    'cost' => 50,
    'price' => 199.99,
    'stock' => 15,
    'active' => 1,
    'barcode' => '86991233322',
    'stock_code' => 'fs123',
    'variations' => [
        [
            'sku' => 'TSH-RED-M',
            'barcode' => '8690000001001',
            'options' => [
                'Color' => 'Red',
                'Size' => 'M',
            ],
            'price' => 249.90,
            'stock' => 12,
            'active' => true,
        ],
    ],
];

$result = apiRequest('POST', $baseUrl . '/products', $apiKey, $payload);
$productId = (int) ($result['response']['data']['id'] ?? 0);
print_r($result);
cURLKopyala
# Simple create (category / brand by name)
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Omega 3 Balık Yağı 90 Kapsül",
    "category": "Vitamin & Takviye",
    "brand": "Nutrof",
    "price": 249.90,
    "old_price": 299.90,
    "stock": 50,
    "active": 1,
    "barcode": "8690000000888",
    "stock_code": "OMEGA3-90",
    "description_html": "<p>90 kapsül, soğuk sıkım.</p>"
  }' \
  "https://example.com/api/v1/products"

# Multi-language + variations
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "translations": {
      "tr": { "name": "Pamuklu Tişört", "slug": "pamuklu-tisort", "description_html": "<p>Yumuşak kumaş</p>" },
      "en": { "name": "Cotton T-Shirt", "slug": "cotton-t-shirt", "description_html": "<p>Soft fabric</p>" }
    },
    "category": "Test Category",
    "brand": "Test Brand",
    "cost": 50,
    "price": 199.99,
    "stock": 15,
    "active": 1,
    "barcode": "86991233322",
    "stock_code": "fs123",
    "variations": [
      {
        "sku": "TSH-RED-M",
        "barcode": "8690000001001",
        "options": { "Color": "Red", "Size": "M" },
        "price": 249.90,
        "stock": 12,
        "active": true
      }
    ]
  }' \
  "https://example.com/api/v1/products"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Ürün eklendi",
  "lang": "tr",
  "data": {
    "id": 6,
    "name": "Pamuklu Tişört",
    "slug": "pamuklu-tisort",
    "price": 199.99,
    "stock": 15,
    "active": 1,
    "barcode": "86991233322",
    "stock_code": "fs123",
    "category_name": "Test Category",
    "brand_name": "Test Brand",
    "has_variations": true
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#16
PATCHhttps://example.com/api/v1/products/{id}
Ürün Güncelle

Tam ürün güncellemesi. Zorunlu alanlar (ad, kategori, marka) bulunmalıdır — bazı durumlarda eksik değerler mevcut üründen doldurulur, ancak en iyi uygulama önce GET /products/{id} ile almak, değişiklikleri birleştirmek ve ardından PATCH göndermektir.

Yalnızca fiyat / stok / aktif durumu için Stok ve Fiyat Güncelle (PATCH /products/{id}/quick) endpoint'ini kullanın.

URL Parametreleri

ParametreTipAçıklama
idintegerÜrün ID

Gövde Parametreleri

Ürün Ekle ile aynı alanlar (translations ve variations dahil).

PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$productId = 6;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$payload = [
    'name' => 'Test Name',
    'category' => 'Category Name',
    'brand' => 'Test',
    'cost' => 100,
    'price' => 299.51,
    'stock' => 1,
    'active' => 1,
    'barcode' => 'AS85551212',
    'stock_code' => 'fs123',
    'description_html' => '<p>Test</p><p>Test 2</p>',
];

$result = apiRequest('PATCH', $baseUrl . '/products/' . (int) $productId, $apiKey, $payload);
print_r($result);
cURLKopyala
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Test Name",
    "category": "Category Name",
    "brand": "Test",
    "cost": 100,
    "price": 299.51,
    "stock": 1,
    "active": 1,
    "barcode": "AS85551212",
    "stock_code": "fs123",
    "description_html": "<p>Test</p><p>Test 2</p>"
  }' \
  "https://example.com/api/v1/products/6"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Ürün güncellendi",
  "data": {
    "id": 6,
    "name": "Test Name",
    "slug": "test-name",
    "price": 299.51,
    "stock": 1,
    "active": 1,
    "barcode": "AS85551212",
    "stock_code": "fs123",
    "category_name": "Category Name",
    "brand_name": "Test",
    "description_html": "<p>Test</p><p>Test 2</p>"
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#17
PATCHhttps://example.com/api/v1/products/{id}/quick
Stok ve Fiyat Güncelle

Yalnızca fiyat, maliyet, stok ve aktif durumu için kısmi güncelleme. Değiştirmek istediğiniz alanları gönderin; diğerleri aynı kalır.

URL Parametreleri

ParametreTipAçıklama
idintegerÜrün ID

Gövde Parametreleri

ParametreTipZorunluAçıklama
pricefloatHayırSatış fiyatı
old_pricefloatHayırListe fiyatı (takma ad: list_price)
costfloatHayırMaliyet fiyatı
doviz_pricefloatHayırDöviz fiyatı
doviz_old_pricefloatHayırDöviz liste fiyatı
stockintegerHayırStok miktarı
activeinteger / boolHayır1/0 veya true/false
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$productId = 1;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$payload = [
    'price' => 500,
    'old_price' => 600,
    'stock' => 10,
    'active' => 1,
];

$result = apiRequest(
    'PATCH',
    $baseUrl . '/products/' . (int) $productId . '/quick',
    $apiKey,
    $payload
);
print_r($result);
cURLKopyala
# Full quick update
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"price":500,"old_price":600,"stock":10,"active":1}' \
  "https://example.com/api/v1/products/1/quick"

# Stock only
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"stock":10}' \
  "https://example.com/api/v1/products/1/quick"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Ürün hızlı güncellendi",
  "lang": "tr",
  "data": {
    "id": 1,
    "name": "Test Product",
    "price": 500,
    "old_price": 600,
    "stock": 10,
    "active": 1,
    "has_variations": true
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#18
POSThttps://example.com/api/v1/products/{id}/image
Ürün Görseli Yükle

Bir ürün görseli yükler. İlk görsel otomatik olarak kapak olur. Desteklenen formatlar: JPG, PNG, WEBP (en fazla 5 MB).

URL Parametreleri

ParametreTipAçıklama
idintegerÜrün ID

Yükleme Yöntemleri

YöntemNasıl
Multipart dosya (önerilen)Form alanı image
Uzak URLJSON {"image_url":"https://..."}
Base64JSON {"image_base64":"data:image/jpeg;base64,..."}
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$productId = 6;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

function apiUploadImage(string $url, string $apiKey, string $filePath): array
{
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'X-API-Key: ' . trim($apiKey),
            'Accept: application/json',
        ],
        CURLOPT_POSTFIELDS => [
            'image' => new CURLFile(
                $filePath,
                mime_content_type($filePath) ?: 'image/jpeg',
                basename($filePath)
            ),
        ],
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

// Option A — local file
$result = apiUploadImage(
    $baseUrl . '/products/' . $productId . '/image',
    $apiKey,
    __DIR__ . '/sample-product.jpg'
);

// Option B — remote URL
// $result = apiRequest('POST', $baseUrl . '/products/' . $productId . '/image', $apiKey, [
//     'image_url' => 'https://example.com/urun.jpg',
// ]);

print_r($result);
cURLKopyala
# Multipart file upload
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  -F "image=@C:/path/urun.jpg" \
  "https://example.com/api/v1/products/6/image"

# From remote URL
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"image_url":"https://example.com/urun.jpg"}' \
  "https://example.com/api/v1/products/6/image"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Image uploaded",
  "data": {
    "id": 12,
    "product_id": 6,
    "url": "https://example.com/img/products/12.jpg"
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#19
DELETEhttps://example.com/api/v1/products/{id}
Ürün Sil

Bir ürünü ID'sine göre kalıcı olarak siler.

URL Parametreleri

ParametreTipAçıklama
idintegerSilinecek ürün ID
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$productId = 6;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest('DELETE', $baseUrl . '/products/' . (int) $productId, $apiKey);
print_r($result);
cURLKopyala
curl -s -X DELETE \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/products/6"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Ürün silindi"
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#20
Varyasyonlar ve Çeviriler

Ürün oluşturma ve güncellemede çok dilli metinler için translations, renk/beden gibi seçenekler için variations dizisini kullanın. Temel akış: Ürün Ekle ve Ürün Güncelle.

Çeviriler (translations)

Dil koduna göre anahtarlanan bir nesnedir (tr, en vb.). Her dil altında tipik alanlar:

  • name — ürün adı
  • description_html — HTML açıklama
  • short_description — kısa metin
  • slug — isteğe bağlı URL parçası
Not: Tek dilde çalışıyorsanız düz name / description_html alanları yeterlidir. Çok dilli mağazalarda translations tercih edin.

Varyasyonlar (variations)

Her satır bir stok tutulabilir varyantı temsil eder:

  • sku — stok kodu
  • barcode — barkod
  • stock — varyant stoğu
  • price — varyant fiyatı (üst üründen farklı olabilir)
  • options — seçenek haritası, örn. Renk / Beden
  • active — isteğe bağlı etkinlik bayrağı

Üst stok mu, varyasyon stoğu mu?

  • Varyasyonsuz ürün: stok ve fiyatı üst ürün alanlarında (stock, price) tutun.
  • Varyasyonlu ürün: satılabilir miktar her varyantın stock değerinden gelir. Üst stock özet veya yedek amaçlı olabilir; satış mantığı varyant satırlarına dayanır.
Dikkat: Varyasyon ekledikten sonra yalnızca üst stoğu güncellemek vitrinde yanlış miktar gösterebilir. Stok senkronunda varyant satırlarını da güncelleyin (bkz. Stok Güncelle).

Güncelleme en iyi uygulaması

  1. GET /products/{id} ile mevcut ürünü alın (Ürün Getir.
  2. İhtiyacınız olan alanları / varyantları birleştirin (merge).
  3. Eksik satır kaybetmemek için PATCH ile mümkün olduğunca tam gövdeyi gönderin Ürün Güncelle.

Örnek istek gövdesi

{
  "translations": {
    "tr": {
      "name": "Pamuklu Tişört",
      "description_html": "<p>Yumuşak kumaş</p>",
      "short_description": "Günlük kullanım"
    },
    "en": {
      "name": "Cotton T-Shirt",
      "description_html": "<p>Soft fabric</p>",
      "short_description": "Everyday wear"
    }
  },
  "category": "Giyim",
  "brand": "Demo Marka",
  "price": 199.99,
  "stock": 15,
  "active": 1,
  "variations": [
    {
      "sku": "TSH-KIRMIZI-M",
      "barcode": "8690000001001",
      "options": {
        "Renk": "Kırmızı",
        "Beden": "M"
      },
      "price": 249.90,
      "stock": 12,
      "active": true
    },
    {
      "sku": "TSH-KIRMIZI-L",
      "barcode": "8690000001002",
      "options": {
        "Renk": "Kırmızı",
        "Beden": "L"
      },
      "price": 249.90,
      "stock": 8,
      "active": true
    }
  ]
}

İlgili sayfalar

PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

$payload = [
    'translations' => [
        'tr' => [
            'name' => 'Pamuklu Tişört',
            'slug' => 'pamuklu-tisort',
            'description_html' => '<p>Yumuşak kumaş</p>',
            'short_description' => 'Günlük kullanım',
        ],
        'en' => [
            'name' => 'Cotton T-Shirt',
            'slug' => 'cotton-t-shirt',
            'description_html' => '<p>Soft fabric</p>',
            'short_description' => 'Everyday wear',
        ],
    ],
    'category' => 'Test Category',
    'brand' => 'Test Brand',
    'cost' => 50,
    'price' => 199.99,
    'stock' => 15,
    'active' => 1,
    'barcode' => '86991233322',
    'stock_code' => 'fs123',
    'variations' => [
        [
            'sku' => 'TSH-RED-M',
            'barcode' => '8690000001001',
            'options' => [
                'Color' => 'Red',
                'Size' => 'M',
            ],
            'price' => 249.90,
            'stock' => 12,
            'active' => true,
        ],
        [
            'sku' => 'TSH-RED-L',
            'barcode' => '8690000001002',
            'options' => [
                'Color' => 'Red',
                'Size' => 'L',
            ],
            'price' => 249.90,
            'stock' => 8,
            'active' => true,
        ],
    ],
];

$ch = curl_init($baseUrl . '/products');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'X-API-Key: ' . trim($apiKey),
        'Content-Type: application/json',
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
    CURLOPT_SSL_VERIFYPEER => true,
]);
$response = curl_exec($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo $httpCode . PHP_EOL;
echo $response;
cURLKopyala
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "translations": {
      "tr": {
        "name": "Pamuklu Tişört",
        "slug": "pamuklu-tisort",
        "description_html": "<p>Yumuşak kumaş</p>",
        "short_description": "Günlük kullanım"
      },
      "en": {
        "name": "Cotton T-Shirt",
        "slug": "cotton-t-shirt",
        "description_html": "<p>Soft fabric</p>",
        "short_description": "Everyday wear"
      }
    },
    "category": "Test Category",
    "brand": "Test Brand",
    "cost": 50,
    "price": 199.99,
    "stock": 15,
    "active": 1,
    "barcode": "86991233322",
    "stock_code": "fs123",
    "variations": [
      {
        "sku": "TSH-RED-M",
        "barcode": "8690000001001",
        "options": { "Color": "Red", "Size": "M" },
        "price": 249.90,
        "stock": 12,
        "active": true
      },
      {
        "sku": "TSH-RED-L",
        "barcode": "8690000001002",
        "options": { "Color": "Red", "Size": "L" },
        "price": 249.90,
        "stock": 8,
        "active": true
      }
    ]
  }' \
  "https://example.com/api/v1/products"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Ürün eklendi",
  "lang": "tr",
  "data": {
    "id": 6,
    "name": "Pamuklu Tişört",
    "slug": "pamuklu-tisort",
    "price": 199.99,
    "stock": 15,
    "active": 1,
    "barcode": "86991233322",
    "stock_code": "fs123",
    "category_name": "Test Category",
    "brand_name": "Test Brand",
    "has_variations": true
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#21
GEThttps://example.com/api/v1/categories
Kategorileri Listele

Mağaza kategorilerini döndürür. Ürün oluşturmadan önce (ID çözümlemek veya adları doğrulamak için) kullanışlıdır.

Query Parametreleri

ParametreTipZorunluAçıklama
pageintegerHayır0 tabanlı sayfa (varsayılan: 0)
size / limitintegerHayırSayfa boyutu (varsayılan: 100, en fazla: 500)
activeintegerHayır1 yalnızca aktif (varsayılan), 0 pasif
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest('GET', $baseUrl . '/categories?page=0&size=100&active=1', $apiKey);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/categories?page=0&size=100&active=1"
Örnek Yanıt (JSON)Kopyala
{
  "totalElements": 4,
  "content": [
    {
      "id": 3,
      "name": "Vitamin & Takviye",
      "slug": "vitamin-takviye",
      "parentId": 1,
      "parentName": "Sağlık",
      "active": true
    }
  ]
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#22
GEThttps://example.com/api/v1/brands
Markaları Listele

Mağaza markalarını döndürür.

Query Parametreleri

ParametreTipZorunluAçıklama
pageintegerHayır0 tabanlı sayfa (varsayılan: 0)
size / limitintegerHayırSayfa boyutu (varsayılan: 100, en fazla: 500)
activeintegerHayır1 yalnızca aktif (varsayılan), 0 pasif
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest('GET', $baseUrl . '/brands?page=0&size=100&active=1', $apiKey);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/brands?page=0&size=100&active=1"
Örnek Yanıt (JSON)Kopyala
{
  "totalElements": 2,
  "content": [
    {
      "id": 1,
      "name": "Nutrof",
      "slug": "nutrof",
      "active": true
    }
  ]
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#23
GEThttps://example.com/api/v1/orders
Siparişleri Listele

Siparişleri Trendyol benzeri bir yapıda döndürür: totalElements, content[], ayrıca shipmentAddress, invoiceAddress ve lines[].

Sayfa numaralandırması 0 tabanlıdır.

Durum Kodları

KodEtiketAPI status
1Ödeme BekliyorAwaitingPayment
2HazırlanıyorPicking
3KargodaShipped
4Teslim EdildiDelivered
5İptal EdildiCancelled

Query Parametreleri

ParametreTipZorunluAçıklama
pageintegerHayır0 tabanlı sayfa (varsayılan: 0)
size / limitintegerHayırSayfa boyutu (varsayılan: 30, en fazla: 100)
statusintegerHayır1–5, veya tümü için 0
date_fromstringHayırBaşlangıç tarihi (YYYY-MM-DD veya datetime)
date_tostringHayırBitiş tarihi
startDateintegerHayırUnix ms (Trendyol uyumlu)
endDateintegerHayırUnix ms
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest(
    'GET',
    $baseUrl . '/orders?page=0&size=20&status=2&date_from=2026-06-10&date_to=2026-07-30',
    $apiKey
);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/orders?page=0&size=20&status=2&date_from=2026-06-10&date_to=2026-07-30"
Örnek Yanıt (JSON)Kopyala
{
  "totalElements": 1,
  "totalPages": 1,
  "page": 0,
  "size": 20,
  "content": [
    {
      "id": 15,
      "orderNumber": "FS-20260617-0015",
      "customerFirstName": "Ali",
      "customerLastName": "Yılmaz",
      "customerEmail": "ali@ornek.com",
      "customerPhone": "05551234567",
      "packageTotalPrice": 899.0,
      "paymentMethod": "bankwire",
      "paymentLabel": "Havale / EFT",
      "statusCode": 2,
      "status": "Picking",
      "statusLabel": "Hazırlanıyor",
      "cargoCompany": "",
      "trackingNumber": "",
      "commercial": false,
      "orderDate": 1718611200000,
      "invoice": null,
      "shipmentAddress": {
        "firstName": "Ali",
        "lastName": "Yılmaz",
        "city": "İstanbul",
        "district": "Kadıköy",
        "address1": "Moda Cad. No:5",
        "fullAddress": "İstanbul / Kadıköy — Moda Cad. No:5",
        "phone": "05551234567",
        "countryCode": "TR"
      },
      "lines": [
        {
          "lineId": 42,
          "contentId": 1,
          "productName": "SolNutrof Total 30 Kapsül",
          "quantity": 1,
          "stockCode": "SOLNUTROF30",
          "barcode": "8690000000011",
          "lineUnitPrice": 899.0,
          "lineAmount": 899.0,
          "vatRate": 20.0,
          "orderLineItemStatusName": "Picking"
        }
      ]
    }
  ]
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#24
GEThttps://example.com/api/v1/orders/{id}
Sipariş Getir

Tek bir siparişi, liste öğeleriyle aynı alanlarla döndürür (adresler, satırlar, kargo, isteğe bağlı invoice).

URL Parametreleri

ParametreTipAçıklama
idintegerSipariş ID
Fatura: Ayarlandığında invoice şu şekilde görünür: {"type":"url","url":"...","name":"..."} veya null.
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$orderId = 15;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$result = apiRequest('GET', $baseUrl . '/orders/' . (int) $orderId, $apiKey);
print_r($result);
cURLKopyala
curl -s -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json" \
  "https://example.com/api/v1/orders/15"
Örnek Yanıt (JSON)Kopyala
{
  "id": 15,
  "orderNumber": "FS-20260617-0015",
  "customerFirstName": "Ali",
  "customerLastName": "Yılmaz",
  "customerEmail": "ali@ornek.com",
  "packageTotalPrice": 899.0,
  "statusCode": 2,
  "status": "Picking",
  "statusLabel": "Hazırlanıyor",
  "cargoCompany": "",
  "trackingNumber": "",
  "invoice": null,
  "lines": [
    {
      "lineId": 42,
      "productName": "SolNutrof Total 30 Kapsül",
      "quantity": 1,
      "stockCode": "SOLNUTROF30",
      "lineAmount": 899.0
    }
  ]
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#25
PATCHhttps://example.com/api/v1/orders/{id}
Sipariş Durumunu Güncelle

Sipariş durumunu ve/veya kargo takip alanlarını günceller. Şunlardan en az birini gönderin: status, cargoCompany, trackingNumber (snake_case takma adları da kabul edilir).

Geçerli Durum Değerleri

  • 1 — Ödeme bekliyor
  • 2 — Hazırlanıyor
  • 3 — Kargoda
  • 4 — Teslim edildi
  • 5 — İptal edildi

Gövde Parametreleri

ParametreTipZorunluAçıklama
statusintegerHayır*Yeni durum (1–5)
cargoCompanystringHayır*Kargo firması adı
trackingNumberstringHayır*Takip numarası
PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$orderId = 15;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

$payload = [
    'status' => 3,
    'cargoCompany' => 'Yurtiçi Kargo',
    'trackingNumber' => 'YT123456789',
];

$result = apiRequest('PATCH', $baseUrl . '/orders/' . (int) $orderId, $apiKey, $payload);
print_r($result);
cURLKopyala
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "status": 3,
    "cargoCompany": "Yurtiçi Kargo",
    "trackingNumber": "YT123456789"
  }' \
  "https://example.com/api/v1/orders/15"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Sipariş güncellendi",
  "content": {
    "id": 15,
    "orderNumber": "FS-20260617-0015",
    "statusCode": 3,
    "status": "Shipped",
    "statusLabel": "Kargoda",
    "cargoCompany": "Yurtiçi Kargo",
    "trackingNumber": "YT123456789"
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#26
POSThttps://example.com/api/v1/orders/{id}/invoice
Sipariş Faturası

Bir siparişe harici fatura URL'si ekleyin veya kaldırın. Web API üzerinden dosya yükleme desteklenmez — yalnızca herkese açık bir URL.

Fatura URL'si ayarla

POST /api/v1/orders/{id}/invoice

ParametreTipZorunluAçıklama
urlstringEvetHerkese açık fatura URL'si (PDF/görsel)
namestringHayırGörünen ad

Faturayı kaldır

DELETE /api/v1/orders/{id}/invoice

PHPKopyala
<?php

$baseUrl = 'https://example.com/api/v1';
$apiKey  = 'YOUR_API_KEY';
$orderId = 15;

function apiRequest(string $method, string $url, string $apiKey, ?array $data = null): array
{
    $ch = curl_init();
    $headers = [
        'X-API-Key: ' . trim($apiKey),
        'Accept: application/json',
    ];
    if ($data !== null) {
        $headers[] = 'Content-Type: application/json';
    }
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    }
    $response = curl_exec($ch);
    $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    $decoded = json_decode((string) $response, true);
    return [
        'http_code' => $httpCode,
        'curl_error' => $error,
        'response' => is_array($decoded) ? $decoded : $response,
    ];
}

// Attach invoice URL
$result = apiRequest('POST', $baseUrl . '/orders/' . $orderId . '/invoice', $apiKey, [
    'url' => 'https://example.com/fatura.pdf',
    'name' => 'Fatura',
]);
print_r($result);

// Remove invoice
// $result = apiRequest('DELETE', $baseUrl . '/orders/' . $orderId . '/invoice', $apiKey);
cURLKopyala
# Attach invoice URL
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/fatura.pdf","name":"Fatura"}' \
  "https://example.com/api/v1/orders/15/invoice"

# Remove invoice
curl -s -X DELETE \
  -H "X-API-Key: YOUR_API_KEY" \
  "https://example.com/api/v1/orders/15/invoice"
Örnek Yanıt (JSON)Kopyala
{
  "success": true,
  "message": "Fatura kaydedildi",
  "content": {
    "id": 15,
    "orderNumber": "FS-20260617-0015",
    "invoice": {
      "type": "url",
      "url": "https://example.com/fatura.pdf",
      "name": "Fatura"
    }
  }
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#27
Sipariş Yaşam Döngüsü

Partner entegrasyonunda siparişler webhook ile itilmez; Web API üzerinden okunur, durum güncellenir ve fatura URL'si eklenir. Temel uç noktalar: Listele, Detay, Durum güncelle, Fatura.

Durum kodları

KodTürkçe etiketAPI adı
1Ödeme BekliyorAwaitingPayment
2HazırlanıyorPicking
3KargodaShipped
4Teslim EdildiDelivered
5İptal EdildiCancelled

Tipik akış

AwaitingPayment → Picking → Shipped → Delivered. Herhangi bir aşamada Cancelled olabilir.

  1. Ödeme tamamlanınca veya onaylanınca 2 (Hazırlanıyor).
  2. Paket çıktığında 3 (Kargoda) + takip bilgisi.
  3. Teslimatta 4 (Teslim Edildi).
  4. İptalde 5 (İptal Edildi).

Kargo alanları

cargoCompany ve trackingNumber (veya cargo_company / tracking_number) genellikle durum 3 — Kargoda ile birlikte gönderilir. Yalnızca takip bilgisi de güncellenebilir; en az bir alan gerekir. Bkz. Sipariş Durumunu Güncelle.

Sorgulama stratejisi (polling)

Webhook yok: Web API v1 olay göndermez. Periyodik GET /orders kullanın — sayfa 0 tabanlıdır.
  • date_from / date_to — YYYY-MM-DD veya datetime
  • startDate / endDate — Unix milisaniye (Trendyol uyumlu)
  • status — 1–5, veya tümü için 0
  • page / size — sayfalama (varsayılan boyut 30, en fazla 100)

Son başarılı senkron zamanından itibaren dar bir tarih penceresi tutmak gereksiz yükü azaltır. Kurallar için API Kuralları sayfasına bakın.

Fatura

Sevkiyattan sonra herkese açık bir fatura URL'si ekleyin (POST /orders/{id}/invoice). Dosya yükleme desteklenmez — yalnızca URL. Bkz. Sipariş Faturası.

İzinler

  • orders.read — listeleme ve detay
  • orders.write — durum / kargo güncelleme ve fatura işlemleri
Kapsam: Anahtarda yalnızca okuma varsa durum güncellemesi 403 döner. Anahtarları Yönetim → API bölümünden ayarlayın — Kimlik Doğrulama.

İlgili sayfalar

cURLKopyala
# 1) List picking orders (status=2), page is 0-based
curl -s -H "X-API-Key: YOUR_API_KEY" -H "Accept: application/json" \
  "https://example.com/api/v1/orders?page=0&size=20&status=2&date_from=2026-06-01&date_to=2026-07-30"

# 2) Mark order 15 as shipped + cargo tracking
curl -s -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "status": 3,
    "cargoCompany": "Yurtiçi Kargo",
    "trackingNumber": "YT123456789"
  }' \
  "https://example.com/api/v1/orders/15"

# 3) Attach public invoice URL
curl -s -X POST \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "url": "https://example.com/fatura.pdf",
    "name": "Fatura"
  }' \
  "https://example.com/api/v1/orders/15/invoice"
a
Mehmet Sancak@admin Yönetici
5 gün önce#28
Vitrin AJAX API

Bu uç noktalar iş ortağı Web API değildir. Tema JavaScript'inin müşteri oturumu ve CSRF ile sepet, hesap, favori ve arama gibi vitrin işlemlerini yürütmesi içindir.

Karıştırmayın: Partner entegrasyonu /api/v1/* ve X-API-Key kullanır. Aşağıdaki /api/*.php yolları tarayıcı oturumuna bağlıdır; Web API anahtarı ile çağrılmazlar.

Uç noktalar

YöntemYolİşlemler / not
POST/api/auth.phplogin, register, logout, me
POST/api/cart.phpadd, update, remove, clear, get
POST/api/coupon.phpapply, remove, set_cargo, set_payment, summary
POST/api/account.phpprofil, şifre, adresler, bildirimler
POST/api/favorite.phptoggle, remove
GET/api/product.php?id=Hızlı bakış / ürün özeti
GET/api/search-suggest.php?q=Arama otomatik tamamlama
GET / POST/api/module.php?m={module}&action={action}Modül API yönlendiricisi

CSRF

Durum değiştiren isteklerde jeton zorunludur. Kaynaklar:

  • Oturum: $_SESSION['csrf_token']
  • Başlık: X-CSRF-Token
  • Form / AJAX alanı: token
Tema ipucu: header.tpl içinde tanımlı global csrfToken değişkenini kullanın; jetonu şablona sabit yazmayın. Yönetim veya cron jetonunu vitrin AJAX'ında CSRF olarak kullanmayın.

Modül API'leri

Modül uç noktaları her zaman /api/module.php üzerinden gider; /modules/{name}/api/*.php dosyalarına doğrudan erişim engellenir. Ayrıntılar: Yeni Modül Oluştur, Kanca Listesi, Şablonlar.

İlgili sayfalar

PHPKopyala
// Cart AJAX — CSRF from global csrfToken (header.tpl) or meta[name="csrf-token"]
(function () {
  function getCsrfToken() {
    if (typeof window.csrfToken === 'string' && window.csrfToken !== '') {
      return window.csrfToken;
    }
    var meta = document.querySelector('meta[name="csrf-token"]');
    return meta ? meta.getAttribute('content') : '';
  }

  function cartRequest(action, body) {
    var data = Object.assign({ action: action, token: getCsrfToken() }, body || {});
    return fetch('/api/cart.php', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-CSRF-Token': getCsrfToken(),
        'Accept': 'application/json'
      },
      credentials: 'same-origin',
      body: new URLSearchParams(data).toString()
    }).then(function (res) {
      return res.json();
    });
  }

  // Add product id 12 (optional variation)
  cartRequest('add', {
    id_product: '12',
    id_variation: '0',
    qty: '1'
  }).then(function (json) {
    console.log(json);
  });
})();
Giriş (auth.php) — CSRF ileKopyala
// Login via storefront auth API (session + CSRF, not X-API-Key)
(function () {
  function getCsrfToken() {
    if (typeof window.csrfToken === 'string' && window.csrfToken !== '') {
      return window.csrfToken;
    }
    var meta = document.querySelector('meta[name="csrf-token"]');
    return meta ? meta.getAttribute('content') : '';
  }

  fetch('/api/auth.php', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
      'X-CSRF-Token': getCsrfToken(),
      'Accept': 'application/json'
    },
    credentials: 'same-origin',
    body: new URLSearchParams({
      action: 'login',
      token: getCsrfToken(),
      login: 'customer@example.com',
      password: 'secret',
      remember: '1'
    }).toString()
  })
    .then(function (res) { return res.json(); })
    .then(function (json) {
      console.log(json);
      if (json.success && json.redirect) {
        window.location.href = json.redirect;
      }
    });
})();
a
Mehmet Sancak@admin Yönetici
5 gün önce#29
Cron ve Arka Plan İşleri

FriSay, döviz fiyatı yenileme, terk edilmiş sepet hatırlatmaları, modül cron'ları ve pazaryeri senkronu için HTTP tabanlı zamanlanmış işler sunar. Jeton, yönetim ayarlarındaki SHOP_TOKEN değeridir (Settings::get('SHOP_TOKEN')).

Kimlik doğrulama

  • Query: ?token=YOUR_SHOP_TOKEN
  • Başlık: X-Cron-Token: YOUR_SHOP_TOKEN
Güvenlik: SHOP_TOKEN değerini şablonlarda, istemci JS'inde veya genel depolarda asla açığa çıkarmayın. Yalnızca sunucu crontab / gizli yapılandırmada tutun.

Çekirdek cron — döviz

GET veya POST /api/cron.php?action=currency&token=... — döviz kurlarına göre ürün fiyatlarını yeniler.

curl -s "https://yoursite.com/api/cron.php?action=currency&token=YOUR_SHOP_TOKEN"

curl -s -X POST \
  -H "X-Cron-Token: YOUR_SHOP_TOKEN" \
  "https://yoursite.com/api/cron.php?action=currency"
Öneri: Sunucu crontab'ında döviz işini her 15–60 dakikada bir çalıştırın.

Terk edilmiş sepet

action=abandoned-cart — yalnızca abandoned-cart modülü kuruluysa anlamlıdır.

curl -s "https://yoursite.com/api/cron.php?action=abandoned-cart&token=YOUR_SHOP_TOKEN"

Modül cron'ları

Modülde $apiActions içinde 'cron' => 'api/cron.php' kaydı varsa:

curl -s "https://yoursite.com/api/module.php?m=MODULE_NAME&action=cron&token=YOUR_SHOP_TOKEN"

Modül mimarisi için Yeni Modül Oluştur sayfasına bakın.

Pazaryeri cron

Sipariş veya soru senkronu için: /api/marketplace.php?action=cron&type=orders|questions&platform=trendyol|hepsiburada|n11&token=...

curl -s "https://yoursite.com/api/marketplace.php?action=cron&type=orders&platform=trendyol&token=YOUR_SHOP_TOKEN"

curl -s "https://yoursite.com/api/marketplace.php?action=cron&type=questions&platform=hepsiburada&token=YOUR_SHOP_TOKEN"

Crontab örneği

# Her 30 dakikada döviz
*/30 * * * * curl -s "https://yoursite.com/api/cron.php?action=currency&token=YOUR_SHOP_TOKEN" >/dev/null 2>&1

# Her saat terk edilmiş sepet (modül kuruluysa)
0 * * * * curl -s "https://yoursite.com/api/cron.php?action=abandoned-cart&token=YOUR_SHOP_TOKEN" >/dev/null 2>&1

İlgili sayfalar

cURLKopyala
# Currency / FX product price refresh
curl -s "https://example.com/api/cron.php?action=currency&token=YOUR_SHOP_TOKEN"

# Same via header
curl -s -H "X-Cron-Token: YOUR_SHOP_TOKEN" \
  "https://example.com/api/cron.php?action=currency"

# Abandoned-cart reminders (module must be installed)
curl -s "https://example.com/api/cron.php?action=abandoned-cart&token=YOUR_SHOP_TOKEN"

# Module cron (example: reviews invite job)
curl -s "https://example.com/api/module.php?m=reviews&action=cron&token=YOUR_SHOP_TOKEN"

# Marketplace order sync (Trendyol)
curl -s "https://example.com/api/marketplace.php?action=cron&type=orders&platform=trendyol&token=YOUR_SHOP_TOKEN"

# Marketplace Q&A sync (Hepsiburada), no stock push to marketplace
curl -s "https://example.com/api/marketplace.php?action=cron&type=questions&platform=hepsiburada&send=0&token=YOUR_SHOP_TOKEN"
a
Mehmet Sancak@admin Yönetici
5 gün önce#30
Yeni Modül Oluştur

Modül, modules/{name}/ altında yaşayan bağımsız bir PHP sınıfıdır. Modüller tema dosyalarını değiştirmeden çalışır — tüm şablonlar modül klasöründe kalır.

Yapay zeka destekli geliştirme:
Tam geliştirici kılavuzunu indirip herhangi bir yapay zeka asistanına (ChatGPT, Claude, Cursor vb.) yükleyin:

github.com/bera65/frisay/blob/main/modules/MODULE_DEVELOPER_GUIDE.md

Yapay zeka bu dosyayı okuduktan sonra modül mimarisini, adlandırma kurallarını, API kalıplarını, güvenlik gereksinimlerini ve yardımcı sınıfları anlar — böylece modülünüzü sade dille tarif edip çalışan kodu çok daha hızlı üretebilirsiniz.

Bir Modül Ne Yapabilir?

  • Yönetim paneli yapılandırma ekranı (adminPage())
  • Görüntüleme kancaları ile vitrin HTML enjeksiyonu — bkz. Kanca Listesi
  • JSON API uç noktaları (api/{action}.php)
  • $routes ile özel mağaza sayfaları
  • Ödeme yöntemi entegrasyonu (ödeme)
  • install.sql / uninstall.sql ile veritabanı tabloları

Modül Dosya Şeması

modules/{name}/
  {name}.php                          ← Main class (REQUIRED)
  logo.png                            ← Admin module list icon
  install.sql                         ← Install SQL (optional)
  uninstall.sql                       ← Uninstall SQL (optional)
  assets/
    templates/
      admin/
        admin.tpl                     ← Admin configure page
      front/
        {hook_name}.tpl               ← Storefront hook output
    css/
      front.css                       ← Storefront styles
      admin.css                       ← Admin styles
    js/
      front.js                        ← Storefront scripts
      admin.js                        ← Admin scripts
    img/                              ← Images
  api/
    {action}.php                      ← API endpoint files
  front/
    {page}.php                        ← Custom store route file
        

Adlandırma Kuralları (Kritik)

ÖğeKuralÖrnek
Klasör adıKüçük harf, tire kullanılabilirmy-module
Ana dosya{name}/{name}.phpmodules/my-module/my-module.php
PHP sınıfıPascalCase + Modulemy-module → MyModuleModule
Yönetim URL'siAdmin::url() + ADMIN_URI ileAdmin::url('module-my-module')
API URL'siModül yönlendiricisi ile/api/module.php?m=my-module&action=save
$name özelliğiKlasör adıyla birebir eşleşmelipublic string $name = 'my-module';

ModuleBase — Temel Özellikler

ÖzellikAmaç
$displayHooksDesteklenen kancalar: hook_name => description
$defaultDisplayHooksinstall() sırasında otomatik atanan kancalar
$apiActionsaction => api/file.php eşlemesi
$routesslug => front/page.php özel mağaza sayfaları
$frontStylesheets / $frontScriptsassets/ altındaki vitrin CSS/JS dosya adları. Boş = hiçbir şey yüklenmez (dosyaları açıkça listelemelisiniz veya head.assets kullanın)
$adminStylesheets / $adminScriptsYalnızca modül yönetim yapılandırma sayfasındaki varlıklar
$isPaymenttrue → ödeme adımında ödeme yöntemi olarak kaydeder
$paymentMethodIdorders.payment_method içinde saklanan değer
$paysBeforeOrdertrue → sipariş oluşturulmadan önce ödeme (sanal POS)
Varlık yükleme (v2.5.0+): Boş $frontStylesheets / $frontScripts artık assets/css veya assets/js içindeki her dosyayı otomatik yüklemez. İhtiyacınız olan her dosyayı bildirin, örn. ['front.css'].

renderFrontTemplate — Önemli Kural

Değişkenleri doğrudan global Smarty'ye atamak yerine her zaman $this->renderFrontTemplate('hook_name', $vars) kullanın. Bu, izole bir alt şablonda render eder ve $isLoggedIn veya $cart gibi global değişkenleri kirletmez.

  • Şablon yolu: assets/templates/front/{name}.tpl
  • HTML dizesi döndürür — temada {$hooks.footer nofilter} ile çıktılanır

Yönetim Yapılandırması

  • URL: Admin::url('module-{name}') — asla /admin/ yolunu sabit yazmayın (yol config/env.php içindeki ADMIN_URI'den gelir)
  • Şablon: assets/templates/admin/admin.tpl
  • Yönetim görüntüleme kancaları: admin_* kancaları için renderAdminDisplayHook($hook, $context) uygulayın — bkz. Kanca Listesi
  • İsteğe bağlı kenar çubuğu bağlantısı: boot() içinde $this->registerAdminMenuLink('Label', 'catalog', 95)
  • Tüm POST formları $adminToken değerini hash_equals() ile doğrulamak zorundadır

API Uç Noktaları

  • URL: POST /api/module.php?m={name}&action={action}
  • Vitrin API'leri $_SESSION['csrf_token'] doğrulamalıdır — header.tpl içindeki global JS csrfToken kullanın
  • Vitrin AJAX'ında CSRF jetonu olarak yönetim veya cron jetonu kullanmayın
  • /modules/{name}/api/*.php dosyalarına doğrudan erişim engellenir (403) — her zaman api/module.php üzerinden yönlendirin
  • Cron işleri: 'cron' => 'api/cron.php' olarak kaydedin ve /api/module.php?m={name}&action=cron&token=... kullanın

Kurulumdan Sonra

  1. Gerekli dosyalarla modules/{name}/ klasörünü oluşturun
  2. Yönetim → Modüller sayfasına gidin — modül listede görünür
  3. Kur'a tıklayın — defaultDisplayHooks otomatik atanır
  4. Gerekirse modül detay sayfasında kanca atamalarını ayarlayın
  5. Kurulumdan sonra modül varsayılan olarak aktiftir

Güvenlik Kontrol Listesi

  • Dosya koruması: if (!defined('IN_SCRIPT') && !defined('IN_ADMIN')) exit;
  • Yönetim formları: hash_equals($adminToken, $postToken)
  • Mağaza API: oturumdaki csrfToken doğrulayın
  • SQL: her zaman DB::execute($sql, [$param]) ile hazırlanmış ifadeler kullanın
  • Kullanıcı girdisi: trim, strip_tags, Smarty |escape
  • Kanca şablonlarında satır içi <script> kullanmayın — assets/js/ + data-api-url kullanın
  • Tema veya çekirdek dosyalarını değiştirmeyin

Referans Modüller

ModülNe öğrenilir
whatsappBasit alt bilgi kancası + SQL
newsletterAPI + alt bilgi formu + CSRF kalıbı
reviewsÜrün sekmeleri + API + teslimat sonrası davet cron
questionÜrün sekmeleri + giriş gerektiren API + bot koruması
sliderYönetim CRUD + görsel yükleme
bankwireÖdeme + sipariş onay kancası
sanalpospaysBeforeOrder + front route
recaptchaform.captcha.validate + auth/contact görüntüleme kancaları
alertproduct.updated + order.placed + stok gelince formu
abandoned-cartcart.changed takibi + hatırlatma cron
facebook-pixelhead.top / footer / product_detail takibi
instagram-galleryhome_bottom görüntüleme kancası
export-exceladmin_header yönetim görüntüleme kancası
product-setÜrün setleri + product.updated
PHP 7.4 uyumluluğu: match, str_starts_with(), adlandırılmış argümanlar veya birleşik tipler kullanmayın. Bunun yerine switch ve strpos() kullanın.
PHPKopyala
<?php

if (!defined('IN_SCRIPT') && !defined('IN_ADMIN')) {
	exit;
}

require_once dirname(__DIR__, 2) . '/core/ModuleBase.php';

class MyModuleModule extends ModuleBase
{
	// ── Identity (REQUIRED) ───────────────────────────────
	public string $name = 'my-module';        // must match folder name
	public string $title = 'My Module';
	public string $version = '1.0.0';
	public string $description = 'Short description';
	public string $author = 'FriSay';

	// ── Display hooks ─────────────────────────────────────
	public array $displayHooks = [
		'footer' => 'Adds HTML to the footer area',
	];
	public array $defaultDisplayHooks = ['footer'];

	// ── CSS/JS (empty = load nothing — list files explicitly) ─
	public array $frontStylesheets = ['front.css'];
	public array $frontScripts = [];
	public array $adminStylesheets = ['admin.css'];
	public array $adminScripts = [];

	// ── API endpoints ─────────────────────────────────────
	public array $apiActions = [
		'save' => 'api/save.php',
	];

	// ── Custom store routes: site.com/{slug} ────────────
	public array $routes = [
		// 'my-page' => 'front/page.php',
	];

	// ── REQUIRED: install / uninstall ─────────────────────
	public function install(): bool
	{
		return $this->runSqlFile('install.sql');
		// No database table: return true;
	}

	public function uninstall(): bool
	{
		return $this->runSqlFile('uninstall.sql');
	}

	// ── Optional: runs when module is loaded ──────────────
	public function boot(): void
	{
		Module::registerHook('order.placed', function (array $order): void {
			// Run after order is created
		});
	}

	// ── Admin configure page (Admin::url('module-my-module')) ────
	public function adminPage(): void
	{
		global $smarty, $adminToken;

		$flash = '';

		if (Tools::isSubmit('saveMyModule')) {
			$postToken = (string) Tools::getValue('token');

			if (hash_equals($adminToken, $postToken)) {
				Settings::set('MY_MODULE_SETTING', trim((string) Tools::getValue('setting')));
				$flash = 'Saved';
			} else {
				$flash = 'Invalid request';
			}
		}

		$smarty->assign([
			'setting' => Settings::get('MY_MODULE_SETTING'),
			'flash'   => $flash,
		]);
	}

	// ── Storefront hook output ────────────────────────────
	public function renderDisplayHook(string $hook, array $context = []): ?string
	{
		if ($hook !== 'footer') {
			return null;
		}

		$html = $this->renderFrontTemplate('footer', [
			'message' => Settings::get('MY_MODULE_SETTING'),
		]);

		return $html !== '' ? $html : null;
	}
}
admin.tpl (Smarty)Kopyala
{* assets/templates/admin/admin.tpl *}

{if $flash}
<div class="alert alert-info">{$flash|escape}</div>
{/if}

<form method="post" class="admin-panel p-3" style="max-width:400px">
	<input type="hidden" name="saveMyModule" value="1">
	<input type="hidden" name="token" value="{$adminToken}">

	<label class="form-label">Setting value</label>
	<input type="text" name="setting" class="form-control" value="{$setting|escape}">

	<button type="submit" class="btn btn-dark mt-3">Save</button>
</form>
api/save.php — Vitrin API kalıbıKopyala
<?php

if (!defined('IN_SCRIPT')) {
	exit;
}

header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
	http_response_code(405);
	echo json_encode(['success' => false, 'message' => 'Method not allowed']);
	exit;
}

// Store CSRF — use global csrfToken in JS, NOT admin/cron tokens
$token = Tools::getValue('token') ?: ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? '');

if (!hash_equals($_SESSION['csrf_token'] ?? '', (string) $token)) {
	http_response_code(403);
	echo json_encode(['success' => false, 'message' => 'Invalid request']);
	exit;
}

$result = MyModuleModule::doSomething((string) Tools::getValue('field'));
echo json_encode($result);
front.js — Vitrinden AJAX çağrısıKopyala
// csrfToken is defined in header.tpl — do not hardcode tokens in templates
$(document).on('submit', '.my-module-form', function (e) {
	e.preventDefault();
	var $form = $(this);
	$.ajax({
		url: $form.data('api-url'),
		method: 'POST',
		dataType: 'json',
		data: {
			token: typeof csrfToken !== 'undefined' ? csrfToken : '',
			field: $.trim($form.find('[name="field"]').val())
		}
	});
});
Ödeme modülü (havale / banka transferi tipi)Kopyala
<?php

public bool $isPayment = true;
public string $paymentMethodId = 'bank_transfer';
public string $paymentMethodLabel = 'Bank Transfer';
public bool $paysBeforeOrder = false;

// order_payment.tpl — radio value must match $paymentMethodId
public function processPayment(array $order): array
{
	return [
		'success'  => true,
		'redirect' => '',
		'message'  => '',
	];
}
Yapay zeka istem şablonu — ChatGPT / Claude / Cursor'a yapıştırınKopyala
FriSay e-commerce project — write a module.

Rules: follow ALL rules in MODULE_DEVELOPER_GUIDE.md
PHP 7.4 compatible. Extend ModuleBase. Do NOT modify theme or core files.

Module info:
- name (slug): {my-module}
- title: {Display Name}
- description: {what it does}

Features:
- Display hooks: {footer, product_tab, ...}
- API actions: {action => description}
- Payment module: {yes/no}
- Database tables: {schema if any}
- Admin settings: {Settings keys or table fields}

Files to generate:
1. modules/{name}/{name}.php
2. install.sql / uninstall.sql (if needed)
3. assets/templates/admin/admin.tpl
4. assets/templates/front/{hook}.tpl (one per hook)
5. assets/css/, assets/js/ (if needed)
6. api/{action}.php (if needed)
7. front/{page}.php (if route needed)

Reference modules: whatsapp, newsletter, reviews, question, bankwire, sanalpos
Yardımcı sınıflar — yaygın kullanımKopyala
<?php

// Settings (use UPPERCASE keys with module prefix)
Settings::get('DOMAIN');          // site URL — NOT 'domain'
Settings::get('SITE_NAME');
Settings::set('MY_MODULE_KEY', 'value');

// Database
DB::getRowSafe('table', 'id = ?', [$id]);
DB::insert('table', ['col' => 'value']);
DB::update('table', ['col' => 'v'], 'id = :where_id', ['where_id' => $id]);
DB::execute('DELETE FROM table WHERE id = ?', [$id]);

// Store data
$product = Product::getById($idProduct);   // includes 'url' field
$images  = Product::getImages($idProduct);
$cart    = Cart::getSummary();
$isFav   = Favorite::isFavorite($idProduct);

// Customer
Customer::isLoggedIn();
Customer::getId();
Customer::getCurrent();

// Tools
Tools::displayPrice(99.90);       // ₺99,90
Tools::createSlug('ana sayfa');   // ana-sayfa
Tools::maskName('John Smith');    // J** S****

// Admin URL
Admin::url('module-my-module');   // https://site.com/admin/module-my-module

// Pagination
$pagination = Pagination::build($total, $page, 30, Admin::url('module-my-module'));

// Mail
Mail::send($to, $subject, $bodyHtml);
a
Mehmet Sancak@admin Yönetici
5 gün önce#31
Kanca Listesi

Modül sistemi iki tür kanca sağlar: olay kancaları (PHP geri çağrıları) ve görüntüleme kancaları (Smarty şablon enjeksiyon noktaları). Katalog kaynağı: core/Module.php içindeki Module::HOOKS, getHookCatalog() ve getDisplayHookCatalog().

Olay kancaları belirli anlarda PHP kodu çalıştırır (ör. sipariş verildiğinde).
Görüntüleme kancaları mağaza / yönetim şablonlarına {$hooks.*} veya {$adminHooks.*} ile HTML basar.

Olay Kancaları

Dinleyicileri modülünüzün boot() yönteminde Module::registerHook() ile kaydedin. Yalnızca Module::HOOKS listesinde yer alan kancalar kabul edilir.

Kanca AdıNe Zaman TetiklenirArgümanlar
smarty.assignModule::bootstrap() sırasında — tüm etkin modüller yüklendikten sonra$smarty örneği
head.assetsÖn yüz CSS/JS varlıkları Module::getHeadAssets() ile toplanırkencss ve js anahtarlı &$assets dizisi
footer.htmlEski alt bilgi HTML enjeksiyonu (bunun yerine görüntüleme kancalarını tercih edin)—
admin.menuYönetim kenar çubuğu menüsü oluşturulurken (registerAdminMenuLink veya registerHook)&$items menü öğeleri dizisi
order.placedYeni bir sipariş başarıyla oluşturulduktan sonra (ödeme / POS)Sipariş veri dizisi
order.updatedSipariş güncellendiğinde (yönetim / API / durum değişikliği)$order, önceki durum / bağlam ekleri
product.updatedÜrün kaydedildiğinde (yönetim, Web API, hızlı stok, toplu araçlar)$idProduct, $product, $isNew
cart.changedSepet içeriği değiştikten sonra (ekle / güncelle / kaldır)Cart::getSummary() sepet özet dizisi
form.captcha.validateForm gönderiminde CAPTCHA kontrolü (Captcha::validate())$form adı, &$error dizesi
product.filter.sqlKatalog ürün SQL'i çalışmadan önce — modüller SQL / parametreleri değiştirebilir&$sql, &$params, filtre bağlam dizisi
catalog.filter.contextAyrılmış katalog filtre bağlam kancası (HOOKS içinde kayıtlı)Bağlam yükü (çağıranlar tarafından tetiklendiğinde)

Görüntüleme Kancaları (Ön Yüz)

Yönetimde modül başına atanır ve module_display_hooks içinde saklanır. Çıktı Smarty'de {$hooks.hook_name} olarak kullanılabilir (noktalı adlar iç içe geçer, örn. {$hooks.head.top}).

Kanca AdıKonumSmarty Değişkeni
footerMağaza alt bilgisi{$hooks.footer}
headerÜst çubuk / üst bilgi{$hooks.header}
main_menuAna kategori menüsü{$hooks.main_menu}
mobile_menuMobil çekmece menüsü{$hooks.mobile_menu}
head.top<head> içinde (üst){$hooks.head.top}
homeAna sayfa gövdesi{$hooks.home}
home_sliderAna sayfa üst slayt{$hooks.home_slider}
home_promo_sliderAna sayfa promosyon / kampanya slaydı{$hooks.home_promo_slider}
home_bottomAna sayfa alt bölümü{$hooks.home_bottom}
catalog_filtersKategori / katalog filtreleri{$hooks.catalog_filters}
productÜrün listesi bağlamı (id_product gerekir){$hooks.product}
product_detailÜrün detay sayfası{$hooks.product_detail}
product_tabÜrün sekme düğmesi{$hooks.product_tab}
product_tab_contentÜrün sekme içerik paneli{$hooks.product_tab_content}
product_infÜrün detay bilgi bloğu{$hooks.product_inf}
order_paymentÖdeme adımı{$hooks.order_payment}
order_confirmationSipariş onay sayfası{$hooks.order_confirmation}
auth_socialGiriş / kayıt — sosyal düğmeler{$hooks.auth_social}
contact_formİletişim formu — CAPTCHA / ek alanlar{$hooks.contact_form}
auth_loginGiriş formu — CAPTCHA{$hooks.auth_login}
auth_registerKayıt formu — CAPTCHA{$hooks.auth_register}

Görüntüleme Kancaları (Yönetim)

Yönetim kancaları {$adminHooks.*} kullanır (Module::renderAdminHooks() ile). admin_ ile başlayan kancalar için modülünüzde renderAdminDisplayHook() uygulayın.

Kanca AdıKonumSmarty Değişkeni
admin_loginYönetim giriş formu — CAPTCHA{$adminHooks.admin_login}
admin_product_buttonÜrün düzenleme — Kaydet yanında{$adminHooks.admin_product_button}
admin_order_detailYönetim sipariş detayı{$adminHooks.admin_order_detail}
admin_headerYönetim içerik üstü (tüm sayfalar){$adminHooks.admin_header}
admin_footerYönetim alt bilgisi (tüm sayfalar){$adminHooks.admin_footer}
admin_dashboard_topKontrol paneli — üst{$adminHooks.admin_dashboard_top}
admin_dashboard_kpiKontrol paneli — KPI kartlarının altı{$adminHooks.admin_dashboard_kpi}
admin_dashboard_main_leftKontrol paneli — sol sütun{$adminHooks.admin_dashboard_main_left}
admin_dashboard_main_rightKontrol paneli — sağ sütun{$adminHooks.admin_dashboard_main_right}
admin_dashboard_bottomKontrol paneli — sayfa altı{$adminHooks.admin_dashboard_bottom}
Ertelenmiş kancalar (Module::refreshHook($smarty, $hookName, $context) veya yönetim render ile tembel yüklenen): product, product_tab, product_tab_content, product_inf, order_payment, order_confirmation, auth_social, admin_product_button, admin_order_detail, admin_header, admin_footer ve tüm admin_dashboard_* kancaları.

Modülünüzde Görüntüleme Kancalarını Bildirme

Modül sınıfınızda hangi görüntüleme kancalarının desteklendiğini ve kurulumda varsayılan olarak hangilerinin etkinleştirileceğini tanımlayın:

  • $displayHooks — kanca adı => açıklama (yönetimde gösterilir)
  • $defaultDisplayHooks — install() sırasında otomatik atanan kancalar
  • renderDisplayHook($hook, $context) — ön yüz HTML
  • renderAdminDisplayHook($hook, $context) — admin_* kancaları için yönetim HTML

Yönetim Üzerinden Kanca Atama

Kanca atamaları Module::setDisplayHooks($moduleName, $hookNames) ile kaydedilir. Yalnızca hem $displayHooks hem de global görüntüleme kancası kataloğunda listelenen kancalar kabul edilir.

PHPKopyala
<?php

// ── Event hooks in boot() ───────────────────────────────────────
public function boot(): void
{
    Module::registerHook('order.placed', function (array $order): void {
        Logger::info('Order placed: ' . ($order['id_order'] ?? ''));
    });

    Module::registerHook('order.updated', function (array $order, $oldStatus = null): void {
        // status / cargo / content edits
    });

    Module::registerHook('product.updated', function (int $idProduct, $product = null, $isNew = false): void {
        // sync external catalog, clear caches, etc.
    });

    Module::registerHook('cart.changed', function (array $cart): void {
        // abandoned-cart tracking, analytics
    });

    Module::registerHook('form.captcha.validate', function (string $form, string &$error): void {
        // set $error when CAPTCHA fails
    });

    Module::registerHook('smarty.assign', function ($smarty): void {
        if ($smarty) {
            $smarty->assign('myModuleEnabled', true);
        }
    });

    Module::registerHook('head.assets', function (array &$assets): void {
        $assets['css'][] = 'https://cdn.example.com/extra.css';
    });
}

// ── Display hooks: declare + render ────────────────────────────
public array $displayHooks = [
    'footer'         => 'Footer block',
    'product_detail' => 'Product detail section',
    'auth_login'     => 'Login CAPTCHA',
];

public array $defaultDisplayHooks = ['footer'];

public function renderDisplayHook(string $hook, array $context = []): ?string
{
    return match ($hook) {
        'footer' => $this->renderFrontTemplate('footer', [
            'message' => Settings::get('MY_MODULE_TEXT'),
        ]),
        'product_detail' => $this->renderFrontTemplate('product_detail', [
            'id_product' => $context['id_product'] ?? 0,
        ]),
        default => null,
    };
}
footer.tpl (Görüntüleme Kancası Örneği)Kopyala
{* assets/templates/front/footer.tpl *}

<div class="my-module-footer">
    {if $message}
        <p>{$message|escape}</p>
    {/if}
</div>
Ürün sayfasında ertelenmiş kancayı yenilemeKopyala
<?php

// Call from product detail controller after $smarty is ready:
Module::refreshHook($smarty, 'product_detail', [
    'id_product' => (int) $product['id_product'],
]);

// Smarty template:
// {$hooks.product_detail}
Yönetim görüntüleme kancası örneğiKopyala
<?php

public array $displayHooks = [
    'admin_order_detail' => 'Extra block on order detail',
    'admin_dashboard_top' => 'Dashboard banner',
];

public function renderAdminDisplayHook(string $hook, array $context = []): ?string
{
    return match ($hook) {
        'admin_order_detail' => $this->renderAdminTemplate('order-detail', $context),
        'admin_dashboard_top' => $this->renderAdminTemplate('dashboard-top', $context),
        default => null,
    };
}
Modül sınıfında görüntüleme kancalarını kaydetmeKopyala
<?php

// Minimum setup inside {name}.php:

public array $displayHooks = [
    'footer' => 'Shown in store footer',
];

public array $defaultDisplayHooks = ['footer'];

public function renderDisplayHook(string $hook, array $context = []): ?string
{
    if ($hook !== 'footer') {
        return null;
    }

    return $this->renderFrontTemplate('footer', $context);
}
a
Mehmet Sancak@admin Yönetici
5 gün önce#32
Sabitler ve Değişkenler

Yaygın vitrin global'leri: denetleyicilerde/modüllerde PHP sütununu, tema şablonlarında Smarty (TPL) sütununu kullanın. Boş hücreler eşleşen karşılık olmadığını gösterir.

Çoğu Smarty değişkeni config/settings.php içinde atanır. Sayfa alanları (pageName, pageTitle, …) Page::add()'ten gelir. Ayar anahtarları veritabanında Settings::get() / Settings::set() ile tutulur.

Site ve ayarlar

PHPSmarty (TPL)Açıklama
Settings::get('SITE_NAME'){$siteName}Mağaza / marka adı
Settings::get('DOMAIN') veya $domain{$domain}Site temel URL'si (yapılandırmadaki sondaki eğik çizgi stiliyle)
Settings::get('FOLDER'){$rootDir}Kurulum klasör yolu segmenti (alt klasör kurulumları)
Settings::get('THEME'){$activeTheme}Aktif tema klasör adı
Settings::get('SHOP_TOKEN')Cron / modül API jetonu (TPL'de asla açığa çıkarmayın)
Settings::get('CONTACT_EMAIL'){$contactEmail}Herkese açık iletişim e-postası
Settings::get('CONTACT_PHONE'){$contactPhone}Görüntülenen telefon
Settings::get('CONTACT_PHONE_TEL'){$contactPhoneTel}tel: bağlantıları için telefon
Settings::get('CONTACT_ADDRESS'){$contactAddress}Sokak adresi
Settings::get('CONTACT_CITY'){$contactCity}Şehir
Settings::get('CONTACT_COUNTRY'){$addressCountry}Ülke
Settings::get('POSTAL_CODE'){$postalCode}Posta / ZIP kodu
Settings::get('LATITUDE'){$latitude}Harita enlemi
Settings::get('LONGITUDE'){$longitude}Harita boylamı
Settings::get('OPEN_HOUR'){$openHour}Açılış saati
Settings::get('CLOSE_HOUR'){$closeHour}Kapanış saati
Settings::getFooterDescription(){$footerDescription}Alt bilgi hakkımızda metni
Settings::get('FACEBOOK_LINK'){$facebookLink} / {$socialLinks.facebook}Facebook URL'si
Settings::get('INSTAGRAM_LINK'){$instagramLink} / {$socialLinks.instagram}Instagram URL'si
Settings::get('X_LINK'){$xLink} / {$socialLinks.x}X (Twitter) URL'si
Settings::get('YOUTUBE_LINK'){$youtubeLink}YouTube URL'si
Settings::get('LINKEDIN_LINK'){$linkedinLink}LinkedIn URL'si
Settings::get('PINTEREST_LINK'){$pinterestLink}Pinterest URL'si
Settings::get('TIKTOK_LINK'){$tiktokLink}TikTok URL'si
Settings::get('SITE_VISIBILITY')örn. members_only vitrin kapısı
Settings::get('MEMBER_APPROVAL')manual = bekleyen üye hesapları
Settings::get('DEMO_MODE')Demo kilidi (riskli yönetim işlemlerini engeller)

Sayfa bağlamı

PHPSmarty (TPL)Açıklama
Page::add('home', $title, …){$pageName}Geçerli sayfa anahtarı (örn. home, product, cart)
Page::add() 2. argümanı{$pageTitle}Belge / SEO başlığı
Page::add() 5. argümanı{$pageDesc}Meta açıklama
Page::add() 3. / 4. argümanları{$css} / {$js}Sayfa başına ek CSS/JS dosya adları
{$year}Geçerli yıl (alt bilgi telif hakkı)
{$time} / {$minute}Önbellek kırma zaman damgaları

Müşteri, sepet ve oturum

PHPSmarty (TPL)Açıklama
Customer::isLoggedIn(){$isLoggedIn}Müşteri oturumunun var olup olmadığı
Customer::getCurrent() (tipik){$customer}Giriş yapmış müşteri dizisi / nesnesi
Cart::getSummary() (tipik){$cart}Sepet özeti (öğeler, toplamlar, adet)
$_SESSION['csrf_token']{$token}CSRF jetonu — JS genellikle başlıktan csrfToken okur
{$saveToken}Eski saatlik jeton (API'ler için CSRF tercih edin)
{$favoriteCount}İstek listesi / favori sayısı
{$notificationCount}Müşteri bildirim rozet sayısı
{$headerNotifications}Üst bilgi bildirim listesi
{$cartI18n} / {$cartI18nJson}Sepet arayüzü çeviri dizeleri (JS-güvenli JSON)

Yollar ve varlıklar

PHPSmarty (TPL)Açıklama
_BASE_DIR_{$base_dir}Dosya sistemi / temel dizin sabiti
_THEME_BASE_DIR_{$tpl_dir}Aktif tema şablon dizini
_THEME_CSS_DIR_{$css_dir}Tema CSS URL yolu
_THEME_JS_DIR_{$js_dir}Tema JS URL yolu
_THEME_IMG_DIR_{$img_dir}Tema görselleri URL yolu
_BASE_IMG_DIR_{$base_img}Ortak / ürün görselleri temeli
_BASE_JS_DIR_{$base_js}Ortak JS temeli
_THEME_REEL_DIR_{$tRealDir}Tema gerçek dosya sistemi yolu
Performance::versionedUrl($url){'css/app.css'|asset_url}Önbellek kıran varlık URL'si (?v=…)
SiteAssets::resolveLogoUrl('header'){$siteLogos.header}Logo URL'leri (header, bar, footer)
Theme::getColors($theme){$themeColors}Tema renk değişkenleri dizisi
{$themeOptions}Tema seçenek bayrakları / yapılandırma
Module::… (toplu){$moduleAssets.css} / {$moduleAssets.js}Aktif modül ön yüz CSS/JS URL listeleri

Katalog, dil ve para birimi

PHPSmarty (TPL)Açıklama
{$menuCategories}Üst bilgi / menü kategori ağacı
Cms::getFooterLinks(){$cmsFooterLinks}Alt bilgide bağlı CMS sayfaları
Lang::getAvailable(){$shopLanguages}Etkin vitrin dilleri
Lang::getDefault(){$defaultLang}Varsayılan dil kodu
$_SESSION['selectLang']{$selectLang}Geçerli dil kodu
Lang::getSwitcherList(){$langSwitcher}Dil değiştirici girdileri
Currency::getDisplayCurrency(){$displayCurrency}Müşteri görüntüleme para birimi
Currency::getShopCurrency(){$shopCurrencyCode}Mağaza temel para birimi kodu
Tools::displayPrice($price)Geçerli görüntüleme para birimi için fiyat biçimlendirme
translate('Key'){'Key'|translate}Vitrin i18n dizesi
Cargo::getDisplayHints(){$freeShippingMin} / {$shippingFee}Ücretsiz kargo eşiği ve kargo ücreti ipuçları

Kancalar ve modüller

PHPSmarty (TPL)Açıklama
Module::getRenderedDisplayHooks(){$hooks}Tüm görüntüleme kancası HTML'i (örn. {$hooks.footer})
Module::refreshHook($smarty, 'product_detail', $ctx){$hooks.product_detail}Geçerli sayfada ertelenmiş bir kancayı doldur
Module::renderAdminHooks([…]){$adminHooks.admin_header}Yönetim paneli görüntüleme kancaları
{$newsletterApiUrl}Varsayılan bülten abonelik API URL'si
Module::registerHook('order.placed', $cb)Olay dinleyicisi (TPL değişkeni yok)

Yönetim ve ortam (yalnızca PHP)

PHPSmarty (TPL)Açıklama
Admin::url('orders'){$adminUrl} (yönetim şablonları)config/env.php içindeki ADMIN_URI kullanan yönetim URL'si
$_SESSION['admin_csrf_token'] / $adminToken{$adminToken}Yönetim CSRF jetonu
adminT('Key'){'Key'|adminT}Yönetim paneli çevirisi
FShop::VERSIONÇekirdek sürüm dizesi (yönetim alt bilgisi)
config/env.php → ADMIN_URIHerkese açık yönetim yolu (klasör admin/ olarak kalır)
config/env.php → DB_*, REWRITE_BASEVeritabanı ve rewrite temeli — şablonlar için değil
Modül şablonları: {$isLoggedIn} veya {$cart} gibi global'lerin üzerine yazmamak için $this->renderFrontTemplate('hook', $vars) tercih edin. Üst Smarty değişkenleri modül TPL içinde yine de okunabilir.
a
Mehmet Sancak@admin Yönetici
5 gün önce#33
Tema Oluştur

FriSay mağaza temaları proje kökündeki templates/ altında yer alır. Referans temalar arasında default, fyazilim, blue, restoran, nova ve shopmore (mobil öncelikli) bulunur. Kategori filtreleri çekirdek CatalogFilter kullanır (modül gerekmez).

Hızlı Başlangıç

  1. Bir referans tema klasörünü kopyalayın (örn. templates/shopmore veya templates/default).
  2. Aynı templates/ dizinine yapıştırın.
  3. Kopyayı tema adınıza yeniden adlandırın, örn. fashion.
  4. Yalnızca dosya içeriklerini düzenleyin — dosya veya klasörleri yeniden adlandırmayın.
  5. Temayı Yönetim → Temalar üzerinden etkinleştirin.
Örnek:
templates/default/ → kopyala → templates/fashion/
Önemli kurallar:
  • Tüm dosya ve klasör adlarını default ile birebir aynı tutun.
  • Yalnızca .tpl, .css ve .js dosyalarının içeriğini değiştirin.
  • Temanız mutlaka header.tpl içermelidir; aksi halde tema listesinde görünmez.
  • Tema adlarında küçük harf, harf, rakam, tire veya alt çizgi kullanın (örn. fashion, my-shop).

Tema Klasör Yapısı

templates/fashion/
  header.tpl              ← Main layout header (required)
  footer.tpl              ← Main layout footer
  home.tpl                ← Home page
  product.tpl             ← Product detail page
  productList.tpl         ← Product list partial
  productGrid.tpl         ← Product grid partial
  catalog.tpl             ← Category / catalog page
  category.tpl
  brand.tpl
  cart.tpl
  checkout.tpl
  checkout-success.tpl
  search.tpl
  login.tpl
  register.tpl
  hesabim.tpl
  favoriler.tpl
  siparis.tpl
  siparislerim.tpl
  sifremi-unuttum.tpl
  sifre-sifirla.tpl
  contact.tpl
  cms.tpl
  special.tpl
  truck.tpl
  404.tpl
  css/
    bootstrap.min.css     ← Do not rename
    app.css               ← Global styles — edit freely
    colors.css            ← Theme color variables (also editable in Admin)
    home.css
    product.css
    cart.css
    checkout.css
    auth.css
  js/
    jquery-3.2.1.min.js   ← Do not rename
    bootstrap.min.js
    popper.min.js
    app.js                ← Global scripts — edit freely
    home.js
    product.js
    account.js
  img/                    ← Theme images (favicon, placeholders, etc.)
  plugin/                 ← Reusable partial templates
    cart.tpl
    pagination.tpl
    headerTools.tpl
    catalogToolbar.tpl
    slide.tpl
    schema-jsonld.tpl
    left.tpl
  cms/                    ← CMS page layouts
    hakkimizda.tpl
    gizlilik.tpl
    iade-degisim.tpl
    mesafeli-satis.tpl
    odeme-kargo.tpl
        

Ne Düzenlenir

Dosya türüAmaçYeniden adlandırılabilir mi?
.tplHTML yapısı ve Smarty işaretlemesi — sayfa düzeni ve tasarımı kontrol ederHayır
css/*.cssRenkler, boşluklar, tipografi, duyarlı düzenHayır
js/*.jsÖn yüz etkileşimleri (sepet, ürün, hesap vb.)Hayır
css/colors.cssCSS değişkenleri (--brand-primary vb.) — her kurala dokunmadan hızlı marka renkleriHayır
img/Görselleri değiştirin; şablonlarda referans varsa dosya adlarını koruyunAdları korumak tercih edilir

Temel Şablon Dosyaları

DosyaAçıklama
header.tplBelge başı, CSS/JS dahil etmeleri, gezinme, sayfa gövdesini açar
footer.tplAlt bilgi bağlantıları, betikler, sayfayı kapatır — {$hooks.footer} çıktılar
home.tplAna sayfa bölümleri, öne çıkan ürünler, slaytlar
product.tplÜrün detay sayfası — sekmeler, galeri, sepete ekle
catalog.tpl / category.tplÜrün listeleme sayfaları
checkout.tplÖdeme akışı ve ödeme kancaları ({$hooks.order_payment})
plugin/productList.tplBirden fazla sayfada kullanılan ortak ürün kartı listesi

Şablonlarda Smarty Değişkenleri

Tam PHP ↔ Smarty referansına bakın: Sabitler ve Değişkenler.

  • {$domain} — site temel URL'si
  • {$css_dir} / {$js_dir} / {$img_dir} — tema varlık yolları
  • {$siteName}, {$pageName}, {$pageTitle}, {$pageDesc}
  • {$hooks.footer}, {$hooks.home_bottom} vb. — modül görüntüleme kancaları
  • {$moduleAssets.css} / {$moduleAssets.js} — modül varlıkları
  • {'path/file.css'|asset_url} — sürümlemeli varlık URL'si (önbellek güvenli)

Temanızı Etkinleştirme

  1. Yönetim → Temalar sayfasına gidin.
  2. Açılır listeden temanızı seçin (örn. fashion).
  3. Temayı Kaydet'e tıklayın — bu THEME ayarını günceller.
  4. İsteğe bağlı olarak aynı ekranda renkleri ayarlayın (css/colors.css dosyasına yazar).
  5. Kaydetmeden önizleme: {$domain}?theme_preview=fashion

Geliştirme İpuçları

  • Büyük CSS dosyalarını yeniden yazmadan önce marka renkleri için css/colors.css ile başlayın.
  • Önce header.tpl ve footer.tpl düzenleyin — her sayfayı etkilerler.
  • Kısmi şablonlar için {include file='./plugin/cart.tpl'} kullanın — include yollarını değiştirmeyin.
  • Sayfa başına CSS: denetleyiciler $css ayarlayabilir (örn. home.css) — header.tpl içinde otomatik yüklenir.
  • Büyük şablon değişikliklerinden sonra güncellemeler görünmezse Smarty önbelleğini temizleyin.
PHPKopyala
<?php

// Step 1 — Copy theme folder (command line example)
// cp -r templates/default templates/fashion

// Step 2 — Theme is auto-discovered when header.tpl exists:
// Theme::discover() scans templates/* folders (except admin)

// Step 3 — Activate programmatically (optional):
Theme::setActiveTheme('fashion');

// Step 4 — Per-page CSS in a controller:
$smarty->assign('css', 'home.css');   // loads templates/fashion/css/home.css
$smarty->display('home.tpl');
colors.css (Tema Değişkenleri)Kopyala
{* templates/fashion/css/colors.css — brand colors (editable in Admin → Themes) *}

:root {
    --brand-primary: #1a1a1a;
    --brand-accent: #d6001c;
    --surface: #ffffff;
    --text-primary: #1a1a1a;
    --footer-bg: #0c0c0c;
}
header.tpl — varlık dahil etmeleri (dosyaları yeniden adlandırmayın)Kopyala
<link rel="stylesheet" href="{$css_dir}bootstrap.min.css" />
<link rel="stylesheet" href="{$css_dir}app.css?v={$minute}" />
<link rel="stylesheet" href="{$css_dir}colors.css?v={$minute}" />
{if $css}
<link rel="stylesheet" href="{$css_dir}{$css}?v={$minute}" />
{/if}
<script src="{$js_dir}jquery-3.2.1.min.js"></script>
home.tpl — örnek bölüm düzenlemesiKopyala
<section class="section-premium home-category-block">
    <div class="section-head">
        <h2 class="section-title">Best Sellers</h2>
        <p class="section-subtitle">Discover our most popular products</p>
    </div>
    {include file='./productList.tpl' products=$featuredProducts}
</section>

{* Module display hooks *}
{$hooks.home}
app.css — örnek stil geçersiz kılmaKopyala
/* Use CSS variables from colors.css */
.section-title {
    color: var(--brand-primary);
    font-weight: 600;
}

.btn-primary {
    background: var(--brand-accent);
    border-color: var(--brand-accent);
}

.perks-strip .perk {
    border-radius: 12px;
    background: var(--surface-soft);
}

Konu açmak veya yanıt yazmak için giriş yapmalısınız.

Bu tartışmaya yanıt yazmak ve etkileşimde bulunmak için lütfen hesabınıza giriş yapın.

Giriş Yap