Template View Dosyaları Referansı
Bu dokümantasyon, public/templates/basic/views/ dizinindeki tüm template dosyalarının detaylı analizini içerir. Her dosyanın ne işe yaradığı, özel özellikleri ve kullanım örnekleri ile birlikte açıklanmıştır.
Ana Layout ve Temel Templateler
layouts/theme.twig.php
Ana Layout Template'i - Tüm sayfa içeriklerini saran master template
Özellikler:
- HTML5 doküment yapısı ve responsive meta etiketler
- SEO optimizasyonu ve Open Graph entegrasyonu
- Webpack bundle entegrasyonu
- JavaScript konfigürasyon enjeksiyonu
- CSS özel özellikler için tema desteği
- Sidebar sepet offcanvas entegrasyonu
<main>
{{ render_header() }}
{{ content_for_layout | raw }} {# ÖNEMLİ: Backend'den gelen sayfa içeriği buraya yerleşir #}
{% set footer_url = theme_config('footer_url') %}
{% if footer_url %}
{{ render_page(footer_url) }}
{% endif %}
</main>
content_for_layout Özel Açıklama:
{{ content_for_layout | raw }} değişkeni, template sisteminin en kritik parçalarından biridir. Bu değişken:
- Backend'den gelen dinamik içeriği layout template'ine yerleştirir
- Her sayfa (index.twig.php, product.twig.php, login.twig.php vb.) kendi içeriğini üretir ve bu içerik
content_for_layoutdeğişkenine atanır. rawfiltresi HTML içeriğin escape edilmeden, olduğu gibi render edilmesini sağlar.- Layout template'i (theme.twig.php) bir çerçeve görevi görür, asıl içerik bu placeholder'a yerleştirilir.
- Örneğin:
/product/123URL'si çağrıldığında, backendproduct.twig.phptemplate'ini işler ve sonucucontent_for_layoutolarak layout'a gönderir.
Çalışma Akışı:
- Backend controller bir sayfa template'ini render eder (örn: product.twig.php)
- Render edilen içerik
content_for_layoutdeğişkenine atanır. - Layout template'i (theme.twig.php) yüklenir.
{{ content_for_layout | raw }}yerinde sayfa içeriği görüntülenir.- Böylece her sayfa aynı header, footer ve genel yapıyı kullanır.
open_graph.twig.php
Sosyal Medya Meta Etiketleri - Dinamik Open Graph etiketleri
Özellikler:
- Ürün spesifik Open Graph etiketleri
- Stok durumu entegrasyonu
- Marka ve kategori metadata'sı
- Genel website metadata'sına fallback
{% if request.page_type == 'product' and product is defined %}
<meta property="og:type" content="product">
<meta property="product:availability" content="{{ stock_status }}">
<meta property="product:brand" content="{{ product.brand }}">
{% endif %}
index.twig.php
Ana Sayfa Template'i - Modüler widget sistemi ile homepage
Özellikler:
- Webpack bundle yükleme
- Özel widget placeholder'ları
- Modüler widget include'ları (slider'lar, kategoriler, ürünler)
{{ webpack_bundle('index') }}
{{ ___('page__signin_box') }}
{% include 'widgets/brands_slider.twig.php' %}
{% include 'widgets/manset_slider.twig.php' %}
{% include 'widgets/category_grid.twig.php' %}
{% include 'widgets/last_products.twig.php' %}
ÖNEMLİ NOT - CMS Önceliği:
Eğer CMS'de "index" adında bir sayfa oluşturulmuşsa:
- CMS'deki "index" sayfası içeriği önceliklidir.
index.twig.phptemplate'i devre dışı kalır.- CMS içeriği doğrudan
content_for_layoutdeğişkeni aracılığıylatheme.twig.phplayout'una yerleştirilir - Widget'lar ve özel içerikler CMS editöründen yönetilir.
- Bu sayede kod değişikliği yapmadan ana sayfa içeriği güncellenebilir.
Template Öncelik Sırası:
- CMS'de tanımlı "index" sayfası varsa → CMS içeriği kullanılır.
- CMS'de "index" sayfası yoksa →
index.twig.phptemplate'i kullanılır.
Header Varyantları
header.twig.php
Standart Header - İki bölümlü layout ile temel header
Özellikler:
- Çok dil desteği ve bayrak gösterimi
- Kullanıcı kimlik doğrulama durumları (giriş yapmış/yapmamış)
- Dropdown menüler ile kategori navigasyonu
- Arama işlevselliği
- Alışveriş sepeti entegrasyonu
- Sticky header seçeneği
<div class="header-sec-one">
<!-- Logo, dil seçimi, kullanıcı işlemleri -->
<div class="language">
{% for locale_data in get_locales() %}
<a href="{{ locale_data.url }}">
<img src="{{ ('flags/' ~ locale_data.code ~ '.png') | image }}">
</a>
{% endfor %}
</div>
</div>
<div class="header-sec-two">
<!-- Navigasyon ve arama -->
<nav class="navbar">
{% for category in categories %}
<a href="{{ category.url }}">{{ category.name }}</a>
{% endfor %}
</nav>
</div>
header_ella.twig.php
Alternatif Header - Tam genişlik navigasyon ile
Özellikler:
- Dil seçim dropdown'u
- Yatay kategori navigasyonu
- Kullanıcı hesap dropdown'u
- Typewriter efekti ile arama
<div class="language">
<div class="dropdown">
<button class="dropdown-toggle">
<img src="{{ ('flags/' ~ locale ~ '.png') | image }}">
</button>
</div>
</div>
<nav class="row">
<!-- Logo, navigasyon, kullanıcı butonları -->
</nav>
header_fox.twig.php
Gelişmiş Header - Mega menü ve promosyon banner'ı ile
Özellikler:
- Üst promosyon carousel'ı
- Resim desteği ile mega menü
- Katlanabilir arama işlevselliği
- Hesap sidebar'ı
<div class="mega">
<div class="listBox">
<!-- Kategori listeleri -->
{% for category in categories %}
<div class="category-group">
<h5>{{ category.name }}</h5>
{% for subcategory in category.subcategories %}
<a href="{{ subcategory.url }}">{{ subcategory.name }}</a>
{% endfor %}
</div>
{% endfor %}
</div>
<div class="visualBox">
<!-- Kategori resimleri -->
<img src="{{ category.featured_image }}" alt="{{ category.name }}">
</div>
</div>
header_helen.twig.php
Üç Katmanlı Header - Dikey hiyerarşi ile
Özellikler:
- Üst promosyon banner'ı
- Orta bölümde logo ve arama
- Alt navigasyon çubuğu
<div class="top">
<!-- Promosyon carousel'ı -->
</div>
<div class="medium">
<!-- Logo ve arama -->
</div>
<div class="bottom">
<!-- Navigasyon -->
</div>
header_mobile.twig.php
Mobil Header - Offcanvas navigasyon ile optimize edilmiş
Özellikler:
- Offcanvas ile hamburger menü
- Katlanabilir arama
- Mobil dostu layout
- Akordeon kategori menüsü
<div class="offcanvas offcanvas-start" id="staticBackdrop">
<div class="accordion accordion-flush">
{% for category in categories %}
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" data-bs-target="#flush-collapse{{ loop.index }}">
{{ category.name }}
</button>
</h2>
<div id="flush-collapse{{ loop.index }}" class="accordion-collapse collapse">
{% for subcategory in category.subcategories %}
<a href="{{ subcategory.url }}">{{ subcategory.name }}</a>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
Ürün Templateleri
📚 İlgili Dokümantasyon: Ürün objesinde kullanılabilir tüm alanlar ve özellikler için Ürün Data Alanları dokümantasyonuna bakınız.
_product_card.twig.php
Ürün Kartı Bileşeni - Listelerde kullanılan yeniden kullanılabilir ürün kartı
Özellikler:
- Lazy loading resimler
- Favori işlevselliği
- Thumbnaillar ile varyant seçimi
- Sepete ekleme formu
- Ölçü seçimi (paketleme birimleri)
- İndirim desteği ile fiyat gösterimi
<div class="product pnlurun-item product-card-body" id="divUrunKutu_{{ product.id }}">
<div class="pro card">
{# Giriş yapmış kullanıcılar için favori butonu #}
{% if config('ADD_TO_FAVORITE') and is_logged %}
<button class="fav-icon btn-add-to-favorites" data-urunid="{{ product.id }}">
<i class="bi {% if product.is_favorited %} bi-heart-fill text-danger {% else %} bi-heart {% endif %}"></i>
</button>
{% endif %}
{# Ürün resmi ve linki #}
<a href="{{ product.url }}" title="{{ product.title }}">
<img data-src="{{ product.med_image }}" class="mainImg lazyload"
src="{{ product.min_image }}" alt="{{ product.title }}" />
</a>
{# Varyantlar #}
<div class="product-variant-img-cont">
{% for variant in product.variants %}
<div {{ variant['html-data'] | html_data_attributes }}
class="variant-container {{ loop.first ? 'selectedThumb' : '' }}">
<img data-src="{{ variant['image'] }}" src="{{ variant['image_min'] }}"
class="product-color-img lazyload" alt="{{ variant['name'] }}">
<p class="product-color">{{ variant['name'] ?: ' ' }}</p>
</div>
{% endfor %}
</div>
{# Sepete ekleme formu #}
{% if is_logged and not product.sale_disabled %}
<form action="{{ 'ADD_TO_CART' | route }}" method="post" class="frm-add-to-cart">
<input type="hidden" name="urun_id" value="{{ product.id }}"/>
<input type="hidden" name="renk" class="drUrunRenk{{ product.id }}"
value="{{ product.default_variant_id }}"/>
<div class="d-flex align-items-center justify-content-between">
<div class="count-btns d-flex">
<span class="decrease-btn btn-qty-decrease">
<i class="bi bi-dash"></i>
</span>
<input class="count" type="text" name="adet" value="{{ product.package_qty ?: 1 }}">
<span class="increase-btn btn-qty-increase">
<i class="bi bi-plus"></i>
</span>
</div>
<button type="submit" class="cart basket-btn addtocartbtn">
<i class="bi bi-cart-plus"></i>
</button>
</div>
</form>
{% endif %}
</div>
</div>
product.twig.php
Ürün Detay Sayfası - Kapsamlı ürün görüntüleme template'i
Özellikler:
- Zoom işlevselliği ile ürün galerisi
- Resim değiştirme ile varyant seçimi
- Modal ile video desteği
- Miktar kontrolleri ile sepete ekleme formu
- Ürün özellikleri gösterimi
- Benzer ürünler bölümü
- Tam ekran görüntüleme için resim modal'ı
<div class="renkkategori d-flex gap-2">
{% for variant in product.variants_with_gallery %}
<div class="productVariantSelect" data-galeri_index="{{ iiVariant }}">
<img src="{{ variant.image_thumb }}" />
<p>{{ variant.name }}</p>
</div>
{% endfor %}
</div>
{# Ürün galerisi #}
<div class="product-gallery">
<div class="main-image">
<img id="mainProductImage" src="{{ product.main_image }}" data-zoom="{{ product.large_image }}">
</div>
<div class="thumbnail-gallery">
{% for image in product.gallery %}
<img src="{{ image.thumb }}" data-main="{{ image.large }}" class="gallery-thumb">
{% endfor %}
</div>
</div>
{# Video desteği #}
{% if product.video_url %}
<div class="product-video">
<button type="button" data-bs-toggle="modal" data-bs-target="#videoModal">
<i class="bi bi-play-circle"></i> {{ 'video_izle' | t }}
</button>
</div>
{% endif %}
product_list.twig.php
Kategori/Arama Sonuç Listesi - Filtrelenebilir ürün listesi
Özellikler:
- Responsive filtre paneli (masaüstü/mobil)
- Sıralama seçenekleri dropdown'u
- Infinite scroll sayfalama
- Ürün kartları ile grid layout
- Mobil offcanvas filtreler
{# Filtreler ve sıralama #}
<div class="row">
<div class="col-md-3">
{% include 'filters.twig.php' %}
</div>
<div class="col-md-9">
<div class="sorting-options">
<select id="sort-products">
<option value="name">{{ 'isme_gore_sirala' | t }}</option>
<option value="price_asc">{{ 'fiyat_artan' | t }}</option>
<option value="price_desc">{{ 'fiyat_azalan' | t }}</option>
</select>
</div>
{# Ürün listesi #}
<div class="row row-cols-2 row-cols-md-4 urunlistesi">
{% for product in products.getData %}
{% include '_product_card.twig.php' with {'product': product} %}
{% endfor %}
</div>
{# Infinite scroll için loading #}
<div id="loading" class="text-center" style="display: none;">
<div class="spinner-border"></div>
</div>
</div>
</div>
Müşteri Yönetimi Templateleri
customers/login.twig.php
Kullanıcı Giriş Formu - Kimlik doğrulama template'i
Özellikler:
- Email/müşteri kodu ile giriş desteği
- Otomatik tamamlama ile şifre alanı
- Responsive form layout'u
- Kayıt olma ve şifre kurtarma linkleri
<form id="frmLogin" action="{{ 'LOGIN' | route }}" method="post">
<div class="form-group">
<label for="email">{{ 'email_veya_musteri_kodu' | t }}</label>
<input type="email" name="email" id="email" autocomplete="username" required
placeholder="{{ 'email_giriniz' | t }}">
</div>
<div class="form-group">
<label for="password">{{ 'sifre' | t }}</label>
<input type="password" name="sifre" id="password" autocomplete="current-password" required
placeholder="{{ 'sifre_giriniz' | t }}">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">{{ 'giris_yap' | t }}</button>
<a href="{{ 'register' | url }}">{{ 'kayit_ol' | t }}</a>
<a href="{{ 'forgot_password' | url }}">{{ 'sifremi_unuttum' | t }}</a>
</div>
</form>
customers/register.twig.php
Kullanıcı Kayıt Formu - Kapsamlı kayıt template'i
Özellikler:
- Firma/kişisel bilgi formu
- AJAX ile ülke/şehir seçimi
- Konfigürasyona dayalı koşullu alanlar
- Özel alan entegrasyonu
- reCAPTCHA desteği
- Şartlar ve koşullar onay kutusu
<form id="frmRegister" action="{{ 'REGISTER' | route }}" method="post">
<div class="row">
<div class="col-md-6">
<label for="firma">{{ 'firma_adi' | t }}</label>
<input type="text" name="firma" id="firma" required>
</div>
<div class="col-md-6">
<label for="mail">{{ 'email' | t }}</label>
<input type="email" name="mail" id="mail" required>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="ulke">{{ 'ulke' | t }}</label>
<select name="ulke" id="ulke" class="ulkeSecim" required>
<option value="">{{ 'ulke_seciniz' | t }}</option>
{% for ulke in ulkeler %}
<option value="{{ ulke.Id }}">{{ ulke.UlkeAdi }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-6">
<label for="sehir">{{ 'sehir' | t }}</label>
<select name="sehir" id="sehir" class="sehirSecim" required>
<option value="">{{ 'once_ulke_seciniz' | t }}</option>
</select>
</div>
</div>
{# Özel alanlar #}
{% include 'customers/register_customs.twig.php' %}
{# reCAPTCHA #}
{% if config('RECAPTCHA_SITE_KEY') %}
<div class="g-recaptcha" data-sitekey="{{ config('RECAPTCHA_SITE_KEY') }}"></div>
{% endif %}
<div class="form-check">
<input type="checkbox" name="terms" id="terms" required>
<label for="terms">{{ 'sartlari_kabul_ediyorum' | t }}</label>
</div>
<button type="submit" class="btn btn-primary">{{ 'kayit_ol' | t }}</button>
</form>
customers/register_customs.twig.php
Dinamik Özel Alanlar - Kayıt formu için özelleştirilebilir alanlar
Özellikler:
- Çoklu alan tipleri (input, textarea, select, checkbox, file, datepicker)
- Konfigürasyondan dinamik alan üretimi
- Koşullu zorunlu alanlar
{% for key_name, field_data in custom_fields %}
<div class="form-group">
<label for="custom_field_{{ key_name }}">{{ field_data.label }}</label>
{% if field_data.type == 'input' %}
<input type="text" name="custom_field_{{ key_name }}" id="custom_field_{{ key_name }}"
{{ field_data.required ? 'required' : '' }}
placeholder="{{ field_data.placeholder }}">
{% elseif field_data.type == 'textarea' %}
<textarea name="custom_field_{{ key_name }}" id="custom_field_{{ key_name }}"
{{ field_data.required ? 'required' : '' }}
placeholder="{{ field_data.placeholder }}"></textarea>
{% elseif field_data.type == 'select' %}
<select name="custom_field_{{ key_name }}" id="custom_field_{{ key_name }}"
{{ field_data.required ? 'required' : '' }}>
<option value="">{{ 'seciniz' | t }}</option>
{% for option in field_data.options %}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
{% elseif field_data.type == 'checkbox' %}
<div class="form-check">
<input type="checkbox" name="custom_field_{{ key_name }}" value="1"
id="custom_field_{{ key_name }}" {{ field_data.required ? 'required' : '' }}>
<label for="custom_field_{{ key_name }}">{{ field_data.label }}</label>
</div>
{% elseif field_data.type == 'file' %}
<input type="file" name="custom_field_{{ key_name }}" id="custom_field_{{ key_name }}"
{{ field_data.required ? 'required' : '' }}
accept="{{ field_data.accept }}">
{% elseif field_data.type == 'datepicker' %}
<input type="date" name="custom_field_{{ key_name }}" id="custom_field_{{ key_name }}"
{{ field_data.required ? 'required' : '' }}>
{% endif %}
</div>
{% endfor %}
Sipariş Yönetimi Templateleri
orders/index.twig.php
Sipariş Geçmişi - Kullanıcının sipariş listesi
Özellikler:
- Tablo formatında sipariş gösterimi
- Sipariş durumu ve tutarlar
- Kargo bilgileri
- Sayfalama desteği
- Sipariş detaylarına linkler
<div class="orders-table-container">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{{ 'tarih' | t }}</th>
<th>{{ 'siparis_no' | t }}</th>
<th>{{ 'tutar' | t }}</th>
<th>{{ 'durum' | t }}</th>
<th>{{ 'kargo' | t }}</th>
<th>{{ 'islemler' | t }}</th>
</tr>
</thead>
<tbody>
{% for order in orders.data %}
<tr>
<td>{{ order.short_date }}</td>
<td>{{ order.order_number }}</td>
<td>{{ order.amount_text }}</td>
<td>
<span class="badge badge-{{ order.status_class }}">
{{ order.status_text }}
</span>
</td>
<td>{{ order.shipping_info }}</td>
<td>
<a href="{{ order.detail_url }}" class="btn btn-sm btn-outline-primary">
{{ 'detay' | t }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{# Sayfalama #}
{% if orders.pagination %}
{{ orders.pagination | raw }}
{% endif %}
</div>
orders/detail.twig.php
Sipariş Detayı - Bireysel sipariş görüntüleme
Özellikler:
- Sipariş bilgi tablosu
- Excel export işlevselliği
- Fotoğraf export özelliği
- Tekrar sipariş işlevselliği
- Sipariş HTML içerik gösterimi
<div class="order-detail-header">
<h2>{{ 'siparis_detayi' | t }} - {{ order.order_number }}</h2>
<div class="order-actions">
<a href="{{ order.excel_export_url }}" class="btn btn-success">
<i class="bi bi-file-excel"></i> {{ 'excel_indir' | t }}
</a>
<button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#photoExportModal">
<i class="bi bi-download"></i> {{ 'urun_fotograflarini_indir' | t }}
</button>
<button type="button" class="btn btn-primary" onclick="reorderProducts({{ order.id }})">
<i class="bi bi-arrow-repeat"></i> {{ 'tekrar_siparis_ver' | t }}
</button>
</div>
</div>
<div class="order-info-table">
<table class="table">
<tr>
<td>{{ 'siparis_tarihi' | t }}</td>
<td>{{ order.created_date }}</td>
</tr>
<tr>
<td>{{ 'durum' | t }}</td>
<td>{{ order.status_text }}</td>
</tr>
<tr>
<td>{{ 'toplam_tutar' | t }}</td>
<td>{{ order.total_amount_text }}</td>
</tr>
</table>
</div>
<div class="pnl-order-detail">
{{ order.order_html | raw }}
</div>
{# Fotoğraf export modal'ı #}
{% include 'orders/_photo_export_modal.twig.php' %}
Widget Templateleri
widgets/brands_slider.twig.php
Marka Carousel'ı - Ana sayfada marka gösterimi
Özellikler:
- Swiffy slider entegrasyonu
- Konfigüre edilebilir görüntüleme ayarları
- Navigasyon ve göstergeler
- Responsive tasarım
{% set brands_banner = get_banner('brands_slider') %}
{% if brands_banner and theme_config('brands_slider_active') %}
<div class="container mt-5" data-widget="brands-slider">
<h3 class="text-center">{{ 'markalar' | t }}</h3>
<div class="swiffy-slider {{ theme_config('brands_slider_settings') }}">
<ul class="slider-container">
{% for slide in brands_banner.slide_items %}
<li class="brand-container">
{% if slide.link %}
<a href="{{ slide.link }}" target="_blank">
{% endif %}
<img src="{{ slide.image }}" alt="{{ slide.title }}" class="brand-logo">
{% if slide.link %}
</a>
{% endif %}
</li>
{% endfor %}
</ul>
<button type="button" class="slider-nav" aria-label="Go left">
<i class="bi bi-chevron-left"></i>
</button>
<button type="button" class="slider-nav slider-nav-next" aria-label="Go right">
<i class="bi bi-chevron-right"></i>
</button>
<div class="slider-indicators">
{% for slide in brands_banner.slide_items %}
<button class="{{ loop.first ? 'active' : '' }}" aria-label="Go to slide {{ loop.index }}"></button>
{% endfor %}
</div>
</div>
</div>
{% endif %}
widgets/category_grid.twig.php
Kategori Grid'i - Ana sayfada kategori vitrine edimi
Özellikler:
- 4'e kadar konfigüre edilebilir kategori grid'i
- Renk özelleştirmesi
- Alt kategoriler ile öne çıkan kategori
{% for ii in 1..4 %}
{% if theme_config('category_grid_slider_' ~ ii ~ '_active') %}
{% set grid_category = theme_config('category_grid_slider_' ~ ii ~ '_category') %}
{% set grid_color = theme_config('category_grid_slider_' ~ ii ~ '_color') %}
<div class="category-grid-{{ ii }}" style="background-color: {{ grid_color }};">
<div class="container">
<div class="row">
<div class="col-md-8">
<h3>{{ grid_category.name }}</h3>
<div class="subcategories">
{% for subcategory in grid_category.subcategories %}
<a href="{{ subcategory.url }}" class="subcategory-link">
{{ subcategory.name }}
</a>
{% endfor %}
</div>
</div>
<div class="col-md-4">
<img src="{{ grid_category.featured_image }}" alt="{{ grid_category.name }}" class="category-featured-image">
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
widgets/last_products.twig.php
Son Ürünler - Ana sayfada son eklenen ürünler
Özellikler:
- Ürün kartı template'ini yeniden kullanma
- Responsive grid layout
{% set last_products = get_last_products() %}
{% if last_products %}
<div class="container mt-5" data-widget="last-products">
<h3 class="text-center">{{ 'son_eklenenler' | t }}</h3>
<div class="row row-cols-md-4 row-cols-2 g-1">
{% for product in last_products %}
{{ include('_product_card.twig.php', {'product': product}) }}
{% endfor %}
</div>
</div>
{% endif %}
widgets/instagram.twig.php
Instagram Feed - Sosyal medya entegrasyonu
Özellikler:
- Instagram API entegrasyonu
- Takip butonu
- Responsive fotoğraf grid'i
{% if theme_config('module_instagram') and theme_config('module_instagram_token') %}
<div class="container mt-5" data-widget="instagram">
<h3 class="text-center">{{ 'instagram' | t }}</h3>
<div id="instagram-feed1" class="instagram_feed"
data-token="{{ theme_config('module_instagram_token') }}"
data-count="{{ theme_config('module_instagram_count') ?: 6 }}">
</div>
<div class="text-center mt-3">
<a href="{{ config('SITE_INSTAGRAM_LINK') }}" target="_blank" class="btn btn-primary">
<i class="bi bi-instagram"></i> {{ 'takip_et' | t }}
</a>
</div>
</div>
{% endif %}
Yardımcı Templateler
filters.twig.php
Ürün Filtreleme Arayüzü - Kategori sayfalarında filtreleme
Özellikler:
- Akordeon stil filtre grupları
- Filtre içinde arama
- Checkbox stil seçim
- URL tabanlı filtreleme
<div class="accordion accordion-filter" id="accordionFilter">
{% for group in filters %}
<div class="accordion-item">
<h2 class="accordion-header" id="heading{{ loop.index }}">
<button class="accordion-button {{ loop.first ? '' : 'collapsed' }}"
data-bs-toggle="collapse" data-bs-target="#collapse{{ loop.index }}">
{{ group.name }}
</button>
</h2>
<div id="collapse{{ loop.index }}"
class="accordion-collapse collapse {{ loop.first ? 'show' : '' }}">
<div class="accordion-body">
{% if group.filters|length > 5 %}
<input type="text" class="filter-search form-control mb-2"
placeholder="{{ 'filtrele' | t }}" />
{% endif %}
<div class="filter-options">
{% for filter in group.filters %}
<div class="filter-option">
<a href="{{ filter.url }}" class="filter-link {{ filter.selected ? 'active' : '' }}">
<span class="filter-checkbox">
{% if filter.selected %}
<i class="bi bi-check-square"></i>
{% else %}
<i class="bi bi-square"></i>
{% endif %}
</span>
{{ filter.label }}
<small class="text-muted">({{ filter.count }})</small>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
no_records.twig.php
Boş Durum Template'i - Sonuç bulunamadığında
Özellikler:
- Şirket logosu gösterimi
- "Ürün yok" mesajı
- Ana sayfaya dönüş butonu
<div class="no-records-container text-center py-5">
<div class="mb-4">
<img src="{{ config('LOGO_URL') }}" alt="{{ config('FIRMA_ISIM') }}" class="company-logo">
</div>
<h4 class="mb-3">{{ 'kategori_urun_yok' | t }}</h4>
<p class="text-muted mb-4">{{ 'aradiginiz_kriterlere_uygun_urun_bulunamadi' | t }}</p>
<a href="{{ base_url }}" class="btn btn-primary">
<i class="bi bi-house"></i> {{ 'ana_sayfaya_don' | t }}
</a>
</div>
Kısmi Templateler (Partial)
partial/product/add_to_cart.twig.php
Sepete Ekleme Formu - Yeniden kullanılabilir sepet formu
Özellikler:
- Miktar kontrolleri
- Ölçü/paketleme seçimi
- Favori butonu entegrasyonu
- Satış devre dışı durumu
- Giriş yapmamış kullanıcılar için gereklilik
{% if is_logged and not product.sale_disabled %}
<form action="{{ 'ADD_TO_CART' | route }}" method="post" class="add-to-cart-form">
<input type="hidden" name="urun_id" value="{{ product.id }}">
<input type="hidden" name="renk" value="{{ product.default_variant_id }}">
{# Ölçü seçimi #}
{% if product.measures %}
<div class="measure-selection mb-3">
<label>{{ 'olcu' | t }}</label>
<select name="olcu" class="form-control">
{% for measure in product.measures %}
<option value="{{ measure.id }}">{{ measure.name }}</option>
{% endfor %}
</select>
</div>
{% endif %}
<div class="quantity-controls d-flex align-items-center mb-3">
<div class="count-btns d-flex">
<span class="decrease-btn btn-qty-decrease" data-package-qty="{{ product.package_qty }}">
<i class="bi bi-dash"></i>
</span>
<input class="count form-control" type="number" name="adet"
value="{{ product.package_qty ?: 1 }}" min="1" step="{{ product.package_qty ?: 1 }}">
<span class="increase-btn btn-qty-increase" data-package-qty="{{ product.package_qty }}">
<i class="bi bi-plus"></i>
</span>
</div>
</div>
<div class="cart-actions">
<button type="submit" class="btn btn-primary add-to-cart-btn">
<i class="bi bi-cart-plus"></i> {{ 'sepete_ekle' | t }}
</button>
{% if config('ADD_TO_FAVORITE') %}
<button type="button" class="btn btn-outline-secondary btn-add-to-favorites" data-urunid="{{ product.id }}">
<i class="bi {% if product.is_favorited %} bi-heart-fill {% else %} bi-heart {% endif %}"></i>
</button>
{% endif %}
</div>
</form>
{% else %}
{% if not is_logged %}
<div class="login-required text-center p-3">
<p>{{ 'siparis_vermek_icin_giris_yapin' | t }}</p>
<a href="{{ 'login' | url }}" class="btn btn-primary">{{ 'giris_yap' | t }}</a>
</div>
{% else %}
<div class="sale-disabled text-center p-3">
<p>{{ 'bu_urun_satis_disi' | t }}</p>
</div>
{% endif %}
{% endif %}
Temel Teknik Özellikler
Çok Dil Desteği
Tüm templateler {{ 'girisyap' | t }} filtresi ile çeviri desteği sağlar:
{{ 'merhaba_dunya' | t }}
{{ 'hosgeldin_mesaji' | translate }}
Responsive Tasarım
Bootstrap 5 sınıfları ile responsive yapı:
<div class="row row-cols-2 row-cols-md-4 g-2">
<div class="col">
<!-- İçerik -->
</div>
</div>
Lazy Loading
Performans optimizasyonu için resim lazy loading:
<img data-src="{{ product.med_image }}"
src="{{ product.min_image }}"
class="lazyload"
alt="{{ product.title }}">
Webpack Entegrasyonu
Varlık yönetimi için webpack bundle sistemi:
{{ webpack_bundle('layout') }}
{{ webpack_bundle('product') }}
{{ webpack_bundle_header() }}
Tema Konfigürasyonu
Dinamik tema ayarları:
{% if theme_config('header_style') == 'modern' %}
{% include 'header_modern.twig.php' %}
{% endif %}
Kullanıcı Durumu Yönetimi
Koşullu rendering:
{% if is_logged %}
{{ 'hosgeldin' | t }} {{ user.name }}!
{% else %}
<a href="{{ 'login' | url }}">{{ 'giris_yap' | t }}</a>
{% endif %}
Bu kapsamlı referans, frontend geliştiricilerin template sistemiyle etkili şekilde çalışabilmesi için her dosyanın amacını, özelliklerini ve kullanım şeklini detaylı olarak açıklamaktadır.
JavaScript Etkileşimli CSS Classları
Bu bölüm, sadece JavaScript tarafından kullanılan CSS classlarını içerir. Bu classlar event listenerlar, DOM manipülasyonu veya kütüphane entegrasyonları için kullanılır. Sadece stil amaçlı classlar bu listeye dahil edilmemiştir.
Varyant Seçimi & Görsel Yönetimi
productThumbSelector
JavaScript İşlevi: Varyant seçimi için click event handler. Varyant seçildiğinde selectedThumb class'ını toggle eder, ürün görselini ve fiyatını günceller.
Dosyalar: product.js, product_detail.js
<div class="variant-container position-relative productThumbSelector {{ loop.first ? 'selectedThumb' : '' }}"
data-urunid="{{ product.id }}"
data-min-src="{{ variant.image_min }}"
data-med-src="{{ variant.image_thumb }}">
<img class="product-color-img card-img-top lazyload" data-src="{{ variant.image_min }}">
</div>
// product.js
on(document, "click", ".productThumbSelector", function (e) {
el.classList.toggle("selectedThumb");
renkInput.value = el.dataset.renk;
price.innerHTML = selector.dataset.price;
});
selectedThumb
JavaScript İşlevi: Seçili varyantı işaretlemek için JavaScript tarafından eklenir/kaldırılır.
Dosyalar: product.js, product_detail.js
// product.js
selected.classList.remove("selectedThumb"); // Öncekinden kaldır
el.classList.add("selectedThumb"); // Yeniye ekle
productVariantSelect
JavaScript İşlevi: Ürün detay sayfasında varyant seçimi için click handler. Galeri görsellerini değiştirir.
Dosyalar: product_detail.js
<div class="renk-img-container productVariantSelect flex-shrink-0"
data-urunid="{{ product.id }}"
data-varyantid="{{ variant.id }}"
data-galeri_index="{{ iiVariant }}">
<img class="lazyload" data-src="{{ variant.image_min }}">
</div>
// product_detail.js
on(document, "click", ".productVariantSelect", function (e) {
this.classList.toggle("selectedThumb");
getGallery(this.dataset.galeri_index, photo);
});
mainImg
JavaScript İşlevi: Ana ürün görseli - src attribute'ü güncellenir, fade animasyon class'ı eklenir/kaldırılır.
Dosyalar: product.js, product_detail.js
<img class="mainImg lazyload"
data-src="{{ product.med_image }}"
src="{{ product.min_image }}">
// product.js
pnlMainImg.classList.add('fade-transition');
pnlMainImg.src = medPhoto;
setTimeout(() => pnlMainImg.classList.remove('fade-transition'), 50);
product-card-body
JavaScript İşlevi: Mouseenter event ile varyant görsellerini preload eder.
Dosyalar: product.js
<div class="product pnlurun-item product-card-body" id="divUrunKutu_{{ product.id }}">
<!-- Ürün kartı içeriği -->
</div>
// product.js
on(document, "mouseenter", ".product-card-body", function (e) {
const variantImages = this.querySelectorAll('.productThumbSelector img');
// Varyant görsellerini preload et
});
urungorselleri
JavaScript İşlevi: Galeri thumbnail'ına tıklandığında ana görseli değiştirir.
Dosyalar: product_detail.js
<div class="urungorselleri d-flex gap-2">
{% for image in product.gallery %}
<div class="imgs-container">
<img class="gallery-item" src="{{ image.thumb }}">
</div>
{% endfor %}
</div>
// product_detail.js
on(document, "click", ".urungorselleri", function (e) {
changeImages(this); // Ana görseli değiştir
});
gallery-item
JavaScript İşlevi: JavaScript tarafından dinamik olarak oluşturulan galeri görselleri.
Dosyalar: product_detail.js
// product_detail.js
img.classList.add("w-100", "h-100", "object-fit-cover", "gallery-item");
gallery-main-item
JavaScript İşlevi: Ana galeri görseli - varyant değiştiğinde src güncellenir.
Dosyalar: product_detail.js
// product_detail.js
galleryMainItem.src = mainImg;
galleryMainItem.dataset.medSrc = mainImg;
pnl_urun_galeri
JavaScript İşlevi: Galeri container'ı varyant değiştiğinde içeriği temizlenip yeniden doldurulur.
Dosyalar: product_detail.js
// product_detail.js
var gallery = document.querySelector(".pnl_urun_galeri");
gallery.innerHTML = ""; // Temizle
gallery.appendChild(galleryContainer); // Yeni içerik ekle
zoom
JavaScript İşlevi: jQuery zoom plugin'i ile görsel yakınlaştırma. Görsel değiştiğinde yeniden initialize edilir.
Dosyalar: product_detail.js
<figure class="zoom" style="background-image: url('{{ product.large_image }}')">
<img src="{{ product.image }}">
</figure>
// product_detail.js
$('.zoom').trigger('zoom.destroy').zoom({
url: photo, // Yeni görsel ile zoom'u yeniden başlat
});
Modal & Video
product-image-clickable
JavaScript İşlevi: Tıklandığında ürün görselini modal'da büyük boyutta gösterir.
Dosyalar: product_detail.js
<img class="mainImg product-image-clickable" data-src="{{ product.image }}">
// product_detail.js
on(document, "click", ".product-image-clickable", function (e) {
let fullImageUrl = this.dataset.src || this.src;
modalImage.src = fullImageUrl;
modal.show();
});
product-modal-image
JavaScript İşlevi: Modal içindeki görsel, src JavaScript ile güncellenir.
Dosyalar: product_detail.js
// product_detail.js
modalImage.src = fullImageUrl;
product-video-btn
JavaScript İşlevi: Video modal'ını açar, video URL'ini yükler.
Dosyalar: product.js, index.js
<button class="product-video-btn" data-video-url="{{ product.video }}">
<i class="bi bi-play-circle"></i>
</button>
// product.js
on(document, "click", ".product-video-btn", function (e) {
const videoUrl = this.getAttribute('data-video-url');
videoSource.src = videoUrl;
bsModal.show();
});
videoSelector
JavaScript İşlevi: Video thumbnail'ı hover ile video gösterir, click ile seçer.
Dosyalar: product.js
// product.js
$(".videoSelector").hover(function () {
mainVid.show(); // Hover'da videoyu göster
}).click(function () {
selector.toggleClass("selectedThumb");
});
Sepet & Miktar Kontrolleri
frm-add-to-cart
JavaScript İşlevi: Form submit event handler, ürünü sepete ekler veya günceller.
Dosyalar: product.js, product_shared.js
<form class="frm-add-to-cart" method="post" action="{{ 'ADD_TO_CART' | route }}">
<input type="hidden" name="urun_id" value="{{ product.id }}">
<input type="hidden" name="renk" value="{{ product.default_variant_id }}">
<button type="submit" class="addtocartbtn">Sepete Ekle</button>
</form>
// product.js
on(document, "submit", ".frm-add-to-cart", function (e) {
addToCart(this, afterAddToCart);
});
btn-qty-increase
JavaScript İşlevi: Miktar artırma butonu, click ile ürün miktarını artırır.
Dosyalar: product_shared.js
<span class="increase-btn btn-qty-increase">
<i data-lucide="plus"></i>
</span>
// product_shared.js
on(document, "click", ".btn-qty-increase", function (e) {
updateCount(this, false); // Miktarı artır
});
btn-qty-decrease
JavaScript İşlevi: Miktar azaltma butonu, click ile ürün miktarını azaltır.
Dosyalar: product_shared.js
<span class="decrease-btn btn-qty-decrease">
<i data-lucide="minus"></i>
</span>
// product_shared.js
on(document, "click", ".btn-qty-decrease", function (e) {
updateCount(this, true); // Miktarı azalt
});
Ölçü/Paket Seçimi
pc-measure-box
JavaScript İşlevi: Ürün kartında ölçü seçimi, click ile radio button'ı seçer, miktar input'unu günceller.
Dosyalar: product.js
<div class="pc-measure-box mb-1 me-1">
<p class="pc-measure-title">{{ measure.name }}</p>
<button class="pc-select-btn">{{ 'sec' | t }}</button>
</div>
// product.js
selectButton.addEventListener("click", function (e) {
radioButton.checked = true;
box.classList.add("pc-active");
updatePackageQty(radioButton);
});
pc-active
JavaScript İşlevi: Aktif ölçü kutusunu işaretlemek için JavaScript tarafından eklenir/kaldırılır.
Dosyalar: product.js
// product.js
subMeasureBoxes.forEach(function (subBox) {
subBox.classList.remove("pc-active");
});
box.classList.add("pc-active");
measure-box
JavaScript İşlevi: Detay sayfasında ölçü seçimi, click ile aktif hale gelir.
Dosyalar: product_detail.js
<div class="measure-box" data-measure-id="{{ measure.id }}">
<p class="measure-title">{{ measure.name }}</p>
<button class="measure-select-btn">{{ 'sec' | t }}</button>
</div>
// product_detail.js
box.addEventListener("click", function (e) {
radioButton.checked = true;
measureBoxes.forEach(box => box.classList.remove("active"));
box.classList.add("active");
});
select-btn
JavaScript İşlevi: Ölçü seçim butonu click event triggerlar.
Dosyalar: product.js, product_detail.js
// product.js
const selectButton = box.querySelector(".select-btn");
selectButton.addEventListener("click", function (e) {
radioButton.checked = true;
});
Favoriler
btn-add-to-favorites
JavaScript İşlevi: Ürünü favorilere ekler/çıkarır.
Dosyalar: product.js
<button class="btn-add-to-favorites border-0 bg-transparent"
data-urunid="{{ product.id }}">
<i data-lucide="heart" class="icon-favorite"></i>
</button>
// product.js
on(document, "click", ".btn-add-to-favorites", function (e) {
addToFavorite(this); // Favorilere ekle
});
Navigasyon & Menüler
pnlSidebarCart
JavaScript İşlevi: Bootstrap offcanvas show event'inde sepet içeriğini render eder.
Dosyalar: layout.js
// layout.js
pnlSidebarCart.addEventListener("show.bs.offcanvas", function () {
renderSidebarCart(); // Sepet içeriğini yükle
});
Filtreleme & Liste
urunlistesi
JavaScript İşlevi: Infinite scroll kütüphanesi için container, yeni ürünler buraya eklenir.
Dosyalar: list.js
<div class="row row-cols-2 row-cols-md-3 urunlistesi">
{% for product in products %}
{% include '_product_card.twig.php' %}
{% endfor %}
</div>
// list.js
var elem = document.querySelector(".urunlistesi");
let infScroll = new InfiniteScroll(elem, {
append: ".pnlurun-item"
});
pnlurun-item
JavaScript İşlevi: Infinite scroll tarafından append edilen ürün kartı.
Dosyalar: list.js
<div class="pnlurun-item">
{% include '_product_card.twig.php' %}
</div>
// list.js
let infScroll = new InfiniteScroll(elem, {
append: ".pnlurun-item" // Yeni ürünler buraya eklenir
});
filter-search
JavaScript İşlevi: Filtre içinde arama için keyup event handler.
Dosyalar: list.js
<input class="filter-input filter-search form-control"
placeholder="{{ 'ara' | t }}">
// list.js
filter_inputs.forEach((input) => {
input.addEventListener("keyup", filterList);
});
filters
JavaScript İşlevi: Filtre item'ı arama sonucuna göre gösterilir/gizlenir.
Dosyalar: list.js
<a class="filters text-decoration-none"
href="{{ filter.url }}"
data-search="{{ filter.label }}">
{{ filter.label }}
</a>
// list.js
function filterList() {
list.forEach((item) => {
if (text.includes(filter)) {
item.style.display = ''; // Göster
} else {
item.style.display = 'none'; // Gizle
}
});
}
Fiyat Gösterimi
price
JavaScript İşlevi: Fiyat gösterim elemanı innerHTML varyant değiştiğinde güncellenir.
Dosyalar: product.js, product_detail.js
<h4 class="price">{{ product.first_variant_price_text }}</h4>
// product.js
var price = document.querySelector(".product-card-body .price");
price.innerHTML = selector.dataset.price;
alternate-price
JavaScript İşlevi: Alternatif para birimi fiyatı varyant değiştiğinde güncellenir.
Dosyalar: product.js, product_detail.js
// product.js
alternate_price.innerHTML = selector.dataset.alternatePrice;
Lazy Loading
lazyload
JavaScript İşlevi: LazySizes kütüphanesi tarafından kullanılır ve viewport'a girdiğinde görselleri yükler.
Dosyalar: Tüm template dosyaları
<img class="lazyload"
data-src="{{ product.med_image }}"
src="{{ product.min_image }}"
alt="{{ product.title }}">
Özel Container Seçicileri
pro / card
JavaScript İşlevi: Ürün container'ı bulmak için closest() ile kullanılır.
Dosyalar: product.js
// product.js
var pnlContainer = selector.closest(".pro") || selector.closest(".card");
Önemli Data Attribute'leri
JavaScript işlevselliği için kritik data attribute'leri:
{# Ürün Data Attributes #}
<div class="product-card-body"
data-product-id="{{ product.id }}"
data-urunid="{{ product.id }}">
</div>
{# Varyant Data Attributes #}
<div class="productThumbSelector"
data-renk="{{ variant.id }}"
data-min-src="{{ variant.image_min }}"
data-med-src="{{ variant.image_thumb }}"
data-price="{{ variant.price | price_with_currency }}"
data-alternate-price="{{ variant.alternate_price }}">
</div>
{# Miktar Data Attributes #}
<input class="count"
data-min-qty="{{ product.minimum_buy_qty }}"
data-max-qty="{{ product.maximum_buy_qty }}"
data-package-qty="{{ product.package_qty }}">
{# Lazy Load Data Attributes #}
<img class="lazyload"
data-src="{{ product.med_image }}"
data-min-src="{{ product.min_image }}"
data-med-src="{{ product.med_image }}">
{# Galeri Data Attributes #}
<div class="productVariantSelect"
data-galeri_index="{{ iiVariant }}"
data-varyantid="{{ variant.id }}">
</div>
{# Filtre Data Attributes #}
<a class="filters" data-search="{{ filter.label }}">
{{ filter.label }}
</a>
JavaScript İşlev Özeti
| Class Adı | JavaScript İşlevi | Event Tipi | Dosya |
|---|---|---|---|
productThumbSelector | Varyant seçimi, görsel/fiyat güncelleme | click | product.js |
selectedThumb | Seçili durum işaretleme | classList | product.js |
productVariantSelect | Detay sayfası varyant seçimi | click | product_detail.js |
mainImg | Ana görsel güncelleme | src, classList | product.js |
product-card-body | Varyant görselleri preload | mouseenter | product.js |
urungorselleri | Galeri thumbnail seçimi | click | product_detail.js |
product-image-clickable | Görsel modal açma | click | product_detail.js |
product-video-btn | Video modal açma | click | product.js |
frm-add-to-cart | Sepete ekleme | submit | product.js |
btn-qty-increase | Miktar artırma | click | product_shared.js |
btn-qty-decrease | Miktar azaltma | click | product_shared.js |
pc-measure-box | Ölçü seçimi | click | product.js |
pc-active | Aktif ölçü işaretleme | classList | product.js |
measure-box | Detay ölçü seçimi | click | product_detail.js |
btn-add-to-favorites | Favorilere ekleme/çıkarma | click | product.js |
pnlSidebarCart | Sepet offcanvas render | bootstrap event | layout.js |
urunlistesi | Infinite scroll container | plugin init | list.js |
pnlurun-item | Infinite scroll append | plugin append | list.js |
filter-search | Filtre arama | keyup | list.js |
filters | Filtre göster/gizle | classList toggle | list.js |
zoom | Görsel zoom | plugin init | product_detail.js |
price | Fiyat güncelleme | innerHTML | product.js |
alternate-price | Alternatif fiyat güncelleme | innerHTML | product.js |
lazyload | Lazy loading | library | LazySizes |
pro / card | Container seçici | closest() | product.js |
Bu classlar SerB2B sistemindeki tüm JavaScript etkileşimleri için kullanılır. Yeni özellik eklerken bu classları kullanın veya benzer naming convention ile yeni classlar oluşturun.