frotan. Ücretsiz Dene
FRONTEND GELİŞTİRİCİLER İÇİN

Frotan Tema & Komponent Geliştirme

Frotan, çok kiracılı tek bir kod tabanıdır: bir temayı bir kez yazarsın, tüm mağazalarda çalışır. Bu rehber, sıfırdan Frotan temasının nasıl kurulacağını, komponentlerin nasıl tasarlanacağını ve statik / güncellenebilir / müşteriye özel temaların nasıl hazırlanacağını gerçek kodla anlatır.

Depo içi referanslar: temalar/ · bilesenler/ · config/gorunum.php · docs/TEMA-KONTRATI.md

1 Mimari genel bakış

Frotan çok kiracılı bir SaaS'tır: tek kod tabanı, kiracı başına ayrı veritabanı. İstek gelen host'tan (subdomain ya da müşteri özel alan adı) kiracı çözülür; aktif temanın dosyaları basılır.

  • Tema = temalar/{ad}/ klasörü. İçinde en az index.php (sayfa iskeleti) ve tema.json (üst-veri) olur. Klasörü eklemek yeterli — DB kaydı gerekmez, tüm mağazalarda otomatik listelenir.
  • Vitrin modülleri = temalar/{ad}/modul/{sayfa}.php (anasayfa, urunler, urun, kategori, sepet, iletisim…). Router hangi modülü basacağını çözer.
  • Görünüm token'ları = renk/font, CSS değişkenleriyle (var(--renk-*)). Mağaza sahibi panelden değiştirir; tema gömme hex kullanmaz.
  • Komponentler (bileşenler) = bilesenler/{slot}/{varyant}.php. Temadan bağımsız, token tabanlı parçalar (hero, navbar, ürün kartı…). Mağaza sahibi varyant seçer.
  • Stüdyo = mağaza sahibinin panelden renk/font/komponent seçtiği ve (v2) blok-tabanlı sayfa kurduğu görsel editör.
Altın kural: tema iskeleti + görsel kimlik (token) + yer değiştirebilir parçalar. Tema düzeni verir; renkler token'dan gelir; parçalar takılıp çıkar.

2 Hızlı başlangıç — 5 dakikada yeni tema

En küçük çalışır tema iki dosyadır. temalar/ altında yeni klasör aç (ad: küçük harf+rakam, örn. tema9):

temalar/tema9/ — en az
temalar/tema9/
├─ tema.json        # üst-veri (ad, destekler, varsayılanlar)
└─ index.php        # sayfa iskeleti (head + header + <main> + footer)

tema.json (statik, en basit):

temalar/tema9/tema.json
{
  "ad": "Tema 9 - Örnek",
  "aciklama": "Örnek başlangıç teması",
  "versiyon": "1.0.0",
  "yazar": "adiniz"
}

index.php (iskelet — modülü <main> içine basar):

temalar/tema9/index.php
<!doctype html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?php echo e($site_title ?? '') . e($ayarlar['title'] ?? 'Mağaza'); ?></title>
    <?php require_once 'config/gorunum.php'; echo gorunumRootCss($db); // token + font (güncellenebilir tema) ?>
    <link rel="stylesheet" href="<?php echo $dizin_limit . TEMA_YOLU; ?>assets/tailwind.css">
</head>
<body>
    <header><!-- navbar: logo, menü, arama, sepet --></header>
    <main>
        <?php require $modFilePath;  // router seçtiği modül ?>
    </main>
    <footer><!-- iletişim, bağlantılar, telif --></footer>
</body>
</html>

Kaydet → bu tema tüm mağazaların Stüdyo → Temalar listesinde anında görünür. Mağaza sahibi seçip Yayınla'ya basınca aktif olur. Önizleme görseli için temalar/images/tema9.png koy (16:10 önerilir).

Bu haliyle tema statiktir (renk/font/komponent özelleştirmesi yok). Güncellenebilir yapmak için §8'e bak.

3 Önerilen dosya yapısı

tema klasörü — tam
temalar/tema9/
├─ tema.json                 # üst-veri + destek bildirimi
├─ index.php                 # <head> + header + <main>(modül) + footer
├─ modul/                    # sayfa gövdeleri (router '{mod}.php' arar)
│   ├─ anasayfa.php
│   ├─ urunler.php           # ürün listesi
│   ├─ urun.php              # ürün detay (sepete ekle)
│   ├─ kategori.php
│   ├─ sepet.php
│   └─ iletisim.php
├─ layout/                   # ortak parçalar (header, footer, head, product-card…)
│   ├─ head.php
│   ├─ header.php
│   ├─ footer.php
│   └─ product-card.php
└─ assets/
    ├─ tailwind.css          # DERLENMİŞ (derleme/ ile üretilir — KVKK: CDN yok)
    └─ theme.js              # slider, sepet, drawer vb. (opsiyonel)

Router, istenen sayfaya göre TEMA_YOLU . "modul/{mod}.php" dosyasını <main> içinde require eder. Modül yoksa 404.php. Modül dosyalarında hazır değişkenler bulunur: $db (kiracı DB), $ayarlar (mağaza ayarları), $dizin_limit (base URL), $kategoriler, $kampanyalar, $ikonlar vb.

4 tema.json sözleşmesi

Temanın kimliği ve neleri desteklediği burada bildirilir. Tüm alanlar:

AlanTipNe işe yarar
admetinStüdyoda görünen tema adı
aciklamametinKısa tanıtım
versiyon, yazarmetinSürüm / geliştirici
onizlememetinÖnizleme görseli yolu (yoksa temalar/images/{ad}.png)
sirasayıListede sıralama (küçük önce)
gorunumdiziHangi görsel özelleştirmeyi destekler: ["renk","font","ozel_css"]. Boş/yoksa → renk/font kapalı (statik).
bilesendiziHangi slotlarda parça değişimi var: ["navbar","hero","urun-kart",...]. Modüllerde bu slotlar için bilesenDevral kancası olmalı.
varsayilannesneToken varsayılanları: renk_birincil, renk_koyu, renk_zemin, renk_metin, font_baslik, font_metin.
ozeldiziVarsa tema "müşteriye özel"dir (bespoke): yalnız sahibine görünür. İçi subdomain listesi (panelden de atanır). Bkz §8.

Güncellenebilir bir temanın tam örneği:

tema.json — güncellenebilir
{
  "ad": "Tema 9 - Modern",
  "aciklama": "Tailwind tabanlı, renk/font/parça özelleştirmeli modern tema",
  "versiyon": "1.0.0",
  "yazar": "adiniz",
  "onizleme": "assets/images/onizleme.jpg",
  "gorunum": ["renk", "font", "ozel_css"],
  "bilesen": ["navbar", "hero", "urun-kart", "footer", "duyuru-bandi",
              "kategori-vitrin", "yorumlar", "bulten", "guvence"],
  "varsayilan": {
    "renk_birincil": "#2f6bd8",
    "renk_koyu":     "#0e1b3c",
    "renk_zemin":    "#f5f7fb",
    "renk_metin":    "#1f2937",
    "font_baslik":   "Montserrat",
    "font_metin":    "Inter"
  }
}
Bir tema "güncellenebilir" sayılır eğer: bilesen dolu VEYA gorunum içinde renk/font var. Aksi halde statik listelenir.

5 Görünüm token'ları (renk & font)

Mağaza sahibi panelden marka rengi / yazı tipi seçer. Bu, kiracı başına ayrı bir CSS derlemesi GEREKTİRMEZ: tek bir :root bloğu basılır, tema renkleri hep CSS değişkeninden okur. Böylece özelleştirme = 1 küçük <style>.

Temanın <head>'inde

Güncellenebilir tema, head'inde gorunumRootCss($db) çağırır — bu, Google Fonts linkini + :root token'larını + mağazanın özel CSS'ini basar:

temalar/tema9/layout/head.php
<?php require_once 'config/gorunum.php'; echo gorunumRootCss($db); ?>

Üretilen token'lar (tema bunları kullanır):

DeğişkenAnlam
--renk-birincil / --renk-birincil-koyuMarka rengi + hover/koyu türevi (otomatik)
--renk-koyuKontrast blok/şerit zemini
--renk-zemin / --renk-zemin-sicak / --renk-panelSayfa zemini + türevleri
--renk-metinGövde metni
--font-baslik / --font-metinBaşlık / metin yazı tipi

Tema tarafında kullanım

Tailwind config'inde renkler bu değişkenlere bağlanır; HTML'de utility sınıf kullanırsın (gömme hex yok):

tailwind config — renk eşleme
// derleme/tailwind.tema9.config.js
colors: {
  brand: { DEFAULT: 'var(--renk-birincil)', dark: 'var(--renk-birincil-koyu)' },
  navy:  'var(--renk-koyu)',
  cream: { DEFAULT: 'var(--renk-zemin)', warm: 'var(--renk-zemin-sicak)' },
  ink:   'var(--renk-metin)'
},
fontFamily: { sans: ['var(--font-metin)','sans-serif'], serif: ['var(--font-baslik)','serif'] }
HTML — token kullanımı
<button class="bg-brand text-white hover:bg-brand-dark">Sepete Ekle</button>
<!-- ya da doğrudan: -->
<h2 style="color:var(--renk-koyu);font-family:var(--font-baslik),serif">Başlık</h2>
KVKK: Fontlar yerelleştirilebilir (cron/fontlari-yerellestir.php). gorunumRootCss yerel kopya varsa Google'a hiç istek atmaz.

6 Komponent sistemi (bileşen)

Bir komponent (parça) = bilesenler/{slot}/{varyant}.php. Temadan bağımsızdır; yalnız Tailwind utility + görünüm token'larıyla yazılır. Veri sözleşmesini dosya başındaki yorum bildirir. Mağaza sahibi her slot için varyant seçer (gorunum tablosunda bilesen_{slot}).

Üç fonksiyon

FonksiyonNe yapar
bilesen($slot, $veri, $varyant)bilesenler/{slot}/{varyant}.php'yi $veri açılmış halde basar.
bilesenVaryant($slot)Mağazanın o slot için seçtiği varyantı döner ('tema' = temanın kendi parçası).
bilesenDevral($slot, $veri)Tema parçasının en üstünde çağrılır: seçim bir varyantsa onu basıp true döner (tema kendi çıktısını atlar); 'tema' ise false.

Tema modülünde devralma kancası

Temanın kendi parçası, en üstte devralmayı dener. Mağaza farklı varyant seçmişse o basılır; "Temanın Kendisi" seçiliyse aşağıdaki özgün tasarım çalışır:

temalar/tema9/modul/anasayfa.php
<?php
require_once 'bilesenler/bilesen.php';
// $heroVeri: komponentin beklediği veri sözleşmesi
if (!bilesenDevral('hero', $heroVeri)) {
    // seçim 'tema' → temanın kendi hero'su:
    ?>
    <section class="bg-cream"> ... temanın özgün hero'su ... </section>
    <?php
}

Mevcut slotlar ve varyantları config/gorunum.php → gorunumBilesenMeta()'da tanımlı: duyuru-bandi, hero, navbar, urun-kart, footer, kategori-vitrin, yorumlar, bulten, guvence. Her birinin diskteki varyantları bilesenler/{slot}/ altında.

7 Bir komponent nasıl tasarlanır

Örnek: hero slotuna "bolunmus" varyantı ekleyelim (solda metin, sağda görsel).

1) Varyant dosyası

İlk satırda veri sözleşmesini yorumla bildir. Yalnız token + Tailwind kullan. Kök elemana data-bilesen="slot/varyant" koy (Stüdyo önizlemesi bunu bulur):

bilesenler/hero/bolunmus.php
<?php
/**
 * Hero — "bolunmus": solda başlık+açıklama+CTA, sağda görsel.
 * Veri sözleşmesi: $site_adi, $aciklama, $slaytlar[] (resim,baslik,link), $dizin_limit.
 */
if (!isset($site_adi)) return;
$ilk = $slaytlar[0] ?? null;
?>
<section class="bg-[var(--renk-zemin)]" data-bilesen="hero/bolunmus"
         style="font-family:var(--font-metin),sans-serif">
  <div class="mx-auto grid max-w-[1320px] items-center gap-8 px-6 py-16 md:grid-cols-2">
    <div>
      <h1 class="text-4xl font-semibold text-[var(--renk-metin)]"
          style="font-family:var(--font-baslik),serif"><?php echo e($site_adi); ?></h1>
      <p class="mt-4 text-[var(--renk-metin)]/75"><?php echo e($aciklama); ?></p>
      <a href="<?php echo e($ilk['link'] ?? ($dizin_limit.'urunler')); ?>"
         class="mt-7 inline-block rounded-full bg-[var(--renk-birincil)] px-7 py-3
                font-semibold text-white hover:bg-[var(--renk-birincil-koyu)]">Alışverişe Başla</a>
    </div>
    <div class="overflow-hidden rounded-2xl">
      <?php if (!empty($ilk['resim'])) { ?>
        <img src="<?php echo htmlspecialchars($ilk['resim']); ?>" alt="" class="w-full object-cover">
      <?php } else { ?>
        <div class="aspect-[4/3]" style="background:linear-gradient(135deg,var(--renk-birincil),var(--renk-koyu))"></div>
      <?php } ?>
    </div>
  </div>
</section>

2) Stüdyoya tanıt (etiket + mini önizleme)

config/gorunum.php → gorunumBilesenMeta() içinde slot ve varyant etiketini ekle; gorunumMiniOnizleme()'ye küçük şematik çizimi ekle (Stüdyo kartında görünür).

3) Tailwind'i derle

Varyantta daha önce hiç kullanılmamış bir Tailwind sınıfı varsa CSS'i yeniden derle (config zaten bilesenler/** tarar):

derleme
npx -y tailwindcss@3.4.17 -c derleme/tailwind.tema9.config.js \
  -i derleme/tailwind-giris.css -o temalar/tema9/assets/tailwind.css --minify
Bitti: parça, Stüdyo'da o slotun varyant listesinde çıkar; mağaza sahibi seçince bilesenDevral onu basar. Tema kodu değişmez.

Veri gerektiren (ürün/kampanya çeken) komponentler ve bunları Stüdyo v2 bloklarına tanıtma için: §9 ve docs/STUDYO-V2.md.

8 Tema türleri

STATİK   Statik tema

Sabit görünümlü, özelleştirmesiz tema. tema.json'da gorunum ve bilesen yoktur (ya da boş). Renk/font/parça seçimi kapalıdır; Stüdyo "Bu statik bir temadır" der.

  • Ne zaman: piksel-tam, markaya özel, oynanmasını istemediğin tasarımlar.
  • Nasıl: §2'deki iki dosya yeter. Gömme renk/font kullanabilirsin (token zorunlu değil). gorunumRootCss çağırmana gerek yok.
statik tema.json — gorunum/bilesen yok
{ "ad": "Butik Siyah", "aciklama": "Sabit siyah-beyaz butik", "versiyon": "1.0.0" }

GÜNCELLENEBİLİR   Güncellenebilir tema

Mağaza sahibinin renk/font seçtiği ve parça (komponent) değiştirebildiği tema. En çok tercih edileni budur.

Gerekenler (TEMA-KONTRATI):

  1. tema.json'a gorunum: ["renk","font","ozel_css"] ve desteklediğin bilesen slotlarını yaz; varsayilan token'larını ver.
  2. head'de echo gorunumRootCss($db); çağır.
  3. Tema boyunca gömme hex yerine var(--renk-*) / var(--font-*) (ya da bunlara bağlı Tailwind sınıfları) kullan.
  4. Değiştirilebilir olmasını istediğin her parçanın tema dosyasının en üstünde bilesenDevral('{slot}', $veri) kancasını koy.

Böylece mağaza sahibi Stüdyo'dan renk/font ve her slot için varyant seçebilir; yayınlayınca tüm ziyaretçiler görür.

Referans uygulama: temalar/tema3/ (Artisan). Birebir örnek olarak incele.

★ ÖZEL   Müşteriye özel (bespoke) tema

Belirli bir mağazaya özel tasarlanan, yalnız o mağazanın sahibine görünen tema. Başka hiçbir mağaza listede göremez/seçemez.

İki yoldan biriyle "özel" işaretlenir:

  1. Kod ile: tema.json'a "ozel" anahtarını ekle. Varlığı yeter (boş dizi bile) — sahipleri subdomain olarak yazılır:
özel tema.json — "ozel" anahtarı
{
  "ad": "Acme'ye Özel",
  "gorunum": ["renk", "font"],
  "bilesen": ["navbar", "hero", "urun-kart", "footer"],
  "ozel": ["acme"]          // yalnız acme.frotan.com.tr görür/seçebilir
}
  1. Panelden: Süper-admin, Kiracılar / Müşteriler sekmesinden bir temayı bir mağazaya atar (frotan_ana.ozel_temalar). tema.json'a dokunmadan da özel yapılabilir; ikisi birleşir.
  • "ozel" anahtarı olmayan tema herkese açıktır — asla gizlenmez.
  • "ozel" olan ama hiç sahibi atanmamış tema kimseye görünmez (yanlışlıkla sızmaz).
  • Özel tema, güncellenebilir de olabilir (içinde gorunum/bilesen) — sahibi yine renk/parça değiştirir.

İlgili fonksiyonlar: gorunumTemaOzelMi(), gorunumTemaOzelSahipler(), gorunumKuruluTemalar() (özel temalar listelemede sahibi dışındakilere gizlenir).

9 Stüdyo v2 — blok-tabanlı sayfa oluşturucu

Stüdyo v2'de bir sayfa = sıralı blok listesi. Mağaza sahibi blok ekler/çıkarır/sürükler/sıralar; her blok bir komponenttir. Yeni bir komponenti bloklara tanıtmak editör koduna dokunmadan 3 adımdır:

  1. bilesenler/{tur}/{varyant}.php dosyası (token tabanlı — §7 gibi).
  2. config/komponent-kayit.php → komponentDefteri()'ye kayıt + ayar şeması (editör sağ panelini otomatik çizer).
  3. Tailwind'i yeniden derle.
config/komponent-kayit.php — kayıt + şema
'duyuru-kutu' => [
  'ad' => 'Duyuru Kutusu', 'kategori' => 'icerik', 'aile' => 'icerik',
  'ikon' => '<rect x="3" y="5" width="18" height="14" rx="2"/>',
  'aciklama' => 'Vurgulu bilgi kutusu.',
  'varyantlar' => [],                         // çok varyantlıysa ['kutulu','sade']
  'ayarlar' => [
    'baslik' => ['tur'=>'metin',      'etiket'=>'Başlık', 'vars'=>''],
    'metin'  => ['tur'=>'metin-alan', 'etiket'=>'Metin',  'vars'=>''],
  ],
],

Ayar alan türleri: metin, metin-alan, sayi, secim, anahtar, renk, gorsel, baglanti, liste, urun-kaynagi. Fonksiyonel sayfalarda (ürün listesi/detay) işlevsel çekirdek temada kalır; bloklar çevresine eklenir ("çekirdek sabit + çevresi serbest").

Tam rehber: depodaki docs/STUDYO-V2.md — veri modeli (sayfa_duzen), sayfaBas() renderer, veri komponentleri, şablonlar.

10 Tailwind — yerel derleme (KVKK)

Frotan ziyaretçi IP'sini üçüncü tarafa sızdırmaz: cdn.tailwindcss.com kullanılmaz, CSS yerel derlenir. Her tema için bir config:

derleme/tailwind.tema9.config.js
// derleme/tailwind.tema9.config.js
module.exports = {
  content: ['./temalar/tema9/**/*.php', './temalar/tema9/assets/*.js', './bilesenler/**/*.php'],
  theme: { extend: {
    colors: { brand: { DEFAULT:'var(--renk-birincil)', dark:'var(--renk-birincil-koyu)' },
              navy:'var(--renk-koyu)', cream:{ DEFAULT:'var(--renk-zemin)' }, ink:'var(--renk-metin)' },
    fontFamily: { sans:['var(--font-metin)','sans-serif'], serif:['var(--font-baslik)','serif'] }
  } }
};
derleme komutu
npx -y tailwindcss@3.4.17 -c derleme/tailwind.tema9.config.js \
  -i derleme/tailwind-giris.css -o temalar/tema9/assets/tailwind.css --minify

content hem temayı hem bilesenler/**'i tarar → komponent sınıfları da derlemeye girer. Yeni utility sınıfı eklediğinde yeniden derle.

11 Teslim kontrol listesi

  • ✓ temalar/{ad}/ klasörü: index.php + tema.json var.
  • ✓ Önizleme görseli (temalar/images/{ad}.png, 16:10).
  • ✓ Güncellenebilir ise: head'de gorunumRootCss($db), token kullanımı, bilesenDevral kancaları, tema.json'da gorunum+bilesen+varsayilan.
  • ✓ Tailwind derlenmiş (assets/tailwind.css), CDN yok.
  • ✓ Tüm sayfa modülleri (anasayfa, urunler, urun, kategori, sepet, iletisim) + 404.
  • ✓ Mobil uyumlu; görseller loading="lazy".
  • ✓ Test: farklı renk/font + farklı varyant seçildiğinde bozulmuyor (Stüdyo önizleme).
Daha derin referans (depoda): docs/TEMA-KONTRATI.md, docs/EKLEME-REHBERI.md, docs/STUDYO-V2.md ve örnek tema temalar/tema3/.

Sorular için: info@frotan.com.tr