Template View Files Reference
This documentation contains a detailed analysis of all template files in the public/templates/basic/views/ directory. Each file is described along with its purpose, special features, and usage examples.
Main Layout and Base Templates
layouts/theme.twig.php
Main Layout Template - Master template that wraps all page content
Features:
- HTML5 document structure and responsive meta tags
- SEO optimization and Open Graph integration
- Webpack bundle integration
- JavaScript configuration injection
- Theme support for CSS custom properties
- Sidebar cart offcanvas integration
<main>
{{ render_header() }}
{{ content_for_layout | raw }} {# IMPORTANT: Page content coming from the backend is placed here #}
{% set footer_url = theme_config('footer_url') %}
{% if footer_url %}
{{ render_page(footer_url) }}
{% endif %}
</main>
content_for_layout Special Note:
The {{ content_for_layout | raw }} variable is one of the most critical parts of the template system. This variable:
- Places dynamic content coming from the backend into the layout template
- Each page (index.twig.php, product.twig.php, login.twig.php, etc.) produces its own content and that content is assigned to the
content_for_layoutvariable. - The
rawfilter ensures that the HTML content is rendered as-is, without being escaped. - The layout template (theme.twig.php) acts as a frame; the actual content is inserted into this placeholder.
- For example: when the
/product/123URL is called, the backend processes theproduct.twig.phptemplate and sends the result to the layout ascontent_for_layout.
Workflow:
- The backend controller renders a page template (e.g.: product.twig.php)
- The rendered content is assigned to the
content_for_layoutvariable. - The layout template (theme.twig.php) is loaded.
- The page content is displayed in place of
{{ content_for_layout | raw }}. - This way, every page uses the same header, footer, and general structure.
open_graph.twig.php
Social Media Meta Tags - Dynamic Open Graph tags
Features:
- Product-specific Open Graph tags
- Stock status integration
- Brand and category metadata
- Fallback to general website metadata
{% 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
Homepage Template - Homepage with modular widget system
Features:
- Webpack bundle loading
- Custom widget placeholders
- Modular widget includes (sliders, categories, products)
{{ 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' %}
IMPORTANT NOTE - CMS Priority:
If a page named "index" has been created in the CMS:
- The content of the "index" page in the CMS takes priority.
- The
index.twig.phptemplate is disabled. - CMS content is placed directly into the
theme.twig.phplayout via thecontent_for_layoutvariable - Widgets and custom content are managed from the CMS editor.
- This way, the homepage content can be updated without making code changes.
Template Priority Order:
- If an "index" page is defined in the CMS → CMS content is used.
- If there is no "index" page in the CMS → the
index.twig.phptemplate is used.
Header Variants
header.twig.php
Standard Header - Basic header with two-section layout
Features:
- Multi-language support and flag display
- User authentication states (logged in/out)
- Category navigation with dropdown menus
- Search functionality
- Shopping cart integration
- Sticky header option
<div class="header-sec-one">
<!-- Logo, language selection, user actions -->
<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">
<!-- Navigation and search -->
<nav class="navbar">
{% for category in categories %}
<a href="{{ category.url }}">{{ category.name }}</a>
{% endfor %}
</nav>
</div>
header_ella.twig.php
Alternative Header - With full-width navigation
Features:
- Language selection dropdown
- Horizontal category navigation
- User account dropdown
- Search with typewriter effect
<div class="language">
<div class="dropdown">
<button class="dropdown-toggle">
<img src="{{ ('flags/' ~ locale ~ '.png') | image }}">
</button>
</div>
</div>
<nav class="row">
<!-- Logo, navigation, user buttons -->
</nav>
header_fox.twig.php
Advanced Header - With mega menu and promotional banner
Features:
- Top promotional carousel
- Mega menu with image support
- Collapsible search functionality
- Account sidebar
<div class="mega">
<div class="listBox">
<!-- Category lists -->
{% 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">
<!-- Category images -->
<img src="{{ category.featured_image }}" alt="{{ category.name }}">
</div>
</div>
header_helen.twig.php
Three-Layer Header - With vertical hierarchy
Features:
- Top promotional banner
- Logo and search in the middle section
- Bottom navigation bar
<div class="top">
<!-- Promotional carousel -->
</div>
<div class="medium">
<!-- Logo and search -->
</div>
<div class="bottom">
<!-- Navigation -->
</div>
header_mobile.twig.php
Mobile Header - Optimized with offcanvas navigation
Features:
- Hamburger menu with offcanvas
- Collapsible search
- Mobile-friendly layout
- Accordion category menu
<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>
Product Templates
📚 Related Documentation: For all available fields and properties in the product object, see the Product Data Fields documentation.
_product_card.twig.php
Product Card Component - Reusable product card used in listings
Features:
- Lazy loading images
- Favorites functionality
- Variant selection with thumbnails
- Add to cart form
- Measure selection (packaging units)
- Price display with discount support
<div class="product pnlurun-item product-card-body" id="divUrunKutu_{{ product.id }}">
<div class="pro card">
{# Favorites button for logged-in users #}
{% 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 %}
{# Product image and link #}
<a href="{{ product.url }}" title="{{ product.title }}">
<img data-src="{{ product.med_image }}" class="mainImg lazyload"
src="{{ product.min_image }}" alt="{{ product.title }}" />
</a>
{# Variants #}
<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>
{# Add to cart form #}
{% 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
Product Detail Page - Comprehensive product display template
Features:
- Product gallery with zoom functionality
- Variant selection with image switching
- Video support with modal
- Add to cart form with quantity controls
- Product attributes display
- Related products section
- Image modal for full-screen viewing
<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>
{# Product gallery #}
<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 support #}
{% 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
Category/Search Results List - Filterable product list
Features:
- Responsive filter panel (desktop/mobile)
- Sorting options dropdown
- Infinite scroll pagination
- Grid layout with product cards
- Mobile offcanvas filters
{# Filters and sorting #}
<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>
{# Product list #}
<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>
{# Loading indicator for infinite scroll #}
<div id="loading" class="text-center" style="display: none;">
<div class="spinner-border"></div>
</div>
</div>
</div>
Customer Management Templates
customers/login.twig.php
User Login Form - Authentication template
Features:
- Login support with email/customer code
- Password field with autocomplete
- Responsive form layout
- Links for registration and password recovery
<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
User Registration Form - Comprehensive registration template
Features:
- Company/personal information form
- Country/city selection with AJAX
- Conditional fields based on configuration
- Custom field integration
- reCAPTCHA support
- Terms and conditions checkbox
<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>
{# Custom fields #}
{% 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
Dynamic Custom Fields - Customizable fields for the registration form
Features:
- Multiple field types (input, textarea, select, checkbox, file, datepicker)
- Dynamic field generation from configuration
- Conditionally required fields
{% 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 %}
Order Management Templates
orders/index.twig.php
Order History - User's order list
Features:
- Order display in table format
- Order status and amounts
- Shipping information
- Pagination support
- Links to order details
<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>
{# Pagination #}
{% if orders.pagination %}
{{ orders.pagination | raw }}
{% endif %}
</div>
orders/detail.twig.php
Order Detail - Individual order view
Features:
- Order information table
- Excel export functionality
- Photo export feature
- Reorder functionality
- Order HTML content display
<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>
{# Photo export modal #}
{% include 'orders/_photo_export_modal.twig.php' %}
Widget Templates
widgets/brands_slider.twig.php
Brand Carousel - Brand display on the homepage
Features:
- Swiffy slider integration
- Configurable display settings
- Navigation and indicators
- Responsive design
{% 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
Category Grid - Category showcase on the homepage
Features:
- Configurable category grid of up to 4 items
- Color customization
- Featured category with subcategories
{% 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
Latest Products - Recently added products on the homepage
Features:
- Reusing the product card template
- 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 - Social media integration
Features:
- Instagram API integration
- Follow button
- Responsive photo grid
{% 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 %}
Helper Templates
filters.twig.php
Product Filtering Interface - Filtering on category pages
Features:
- Accordion-style filter groups
- Search within filters
- Checkbox-style selection
- URL-based filtering
<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
Empty State Template - When no results are found
Features:
- Company logo display
- "No products" message
- Return to homepage button
<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>
Partial Templates
partial/product/add_to_cart.twig.php
Add to Cart Form - Reusable cart form
Features:
- Quantity controls
- Measure/packaging selection
- Favorites button integration
- Sale disabled state
- Requirement for non-logged-in users
{% 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 }}">
{# Measure selection #}
{% 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 %}
Core Technical Features
Multi-Language Support
All templates provide translation support via the {{ 'girisyap' | t }} filter:
{{ 'merhaba_dunya' | t }}
{{ 'hosgeldin_mesaji' | translate }}
Responsive Design
Responsive structure with Bootstrap 5 classes:
<div class="row row-cols-2 row-cols-md-4 g-2">
<div class="col">
<!-- Content -->
</div>
</div>
Lazy Loading
Image lazy loading for performance optimization:
<img data-src="{{ product.med_image }}"
src="{{ product.min_image }}"
class="lazyload"
alt="{{ product.title }}">
Webpack Integration
Webpack bundle system for asset management:
{{ webpack_bundle('layout') }}
{{ webpack_bundle('product') }}
{{ webpack_bundle_header() }}
Theme Configuration
Dynamic theme settings:
{% if theme_config('header_style') == 'modern' %}
{% include 'header_modern.twig.php' %}
{% endif %}
User State Management
Conditional rendering:
{% if is_logged %}
{{ 'hosgeldin' | t }} {{ user.name }}!
{% else %}
<a href="{{ 'login' | url }}">{{ 'giris_yap' | t }}</a>
{% endif %}
This comprehensive reference describes in detail the purpose, features, and usage of each file so that frontend developers can work effectively with the template system.
JavaScript-Interactive CSS Classes
This section contains CSS classes used exclusively by JavaScript. These classes are used for event listeners, DOM manipulation, or library integrations. Classes used for styling purposes only are not included in this list.
Variant Selection & Image Management
productThumbSelector
JavaScript Function: Click event handler for variant selection. Toggles the selectedThumb class when a variant is selected, and updates the product image and price.
Files: 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 Function: Added/removed by JavaScript to mark the selected variant.
Files: product.js, product_detail.js
// product.js
selected.classList.remove("selectedThumb"); // Remove from previous
el.classList.add("selectedThumb"); // Add to new
productVariantSelect
JavaScript Function: Click handler for variant selection on the product detail page. Switches gallery images.
Files: 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 Function: Main product image - the src attribute is updated, fade animation class is added/removed.
Files: 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 Function: Preloads variant images on mouseenter event.
Files: product.js
<div class="product pnlurun-item product-card-body" id="divUrunKutu_{{ product.id }}">
<!-- Product card content -->
</div>
// product.js
on(document, "mouseenter", ".product-card-body", function (e) {
const variantImages = this.querySelectorAll('.productThumbSelector img');
// Preload variant images
});
urungorselleri
JavaScript Function: Changes the main image when a gallery thumbnail is clicked.
Files: 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); // Change the main image
});
gallery-item
JavaScript Function: Gallery images dynamically created by JavaScript.
Files: product_detail.js
// product_detail.js
img.classList.add("w-100", "h-100", "object-fit-cover", "gallery-item");
gallery-main-item
JavaScript Function: Main gallery image - src is updated when the variant changes.
Files: product_detail.js
// product_detail.js
galleryMainItem.src = mainImg;
galleryMainItem.dataset.medSrc = mainImg;
pnl_urun_galeri
JavaScript Function: Gallery container - content is cleared and refilled when the variant changes.
Files: product_detail.js
// product_detail.js
var gallery = document.querySelector(".pnl_urun_galeri");
gallery.innerHTML = ""; // Clear
gallery.appendChild(galleryContainer); // Add new content
zoom
JavaScript Function: Image zoom with jQuery zoom plugin. Re-initialized when the image changes.
Files: 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, // Reinitialize zoom with new image
});
Modal & Video
product-image-clickable
JavaScript Function: Displays the product image in large size in a modal when clicked.
Files: 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 Function: Image inside the modal - src is updated via JavaScript.
Files: product_detail.js
// product_detail.js
modalImage.src = fullImageUrl;
product-video-btn
JavaScript Function: Opens the video modal and loads the video URL.
Files: 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 Function: Video thumbnail shows video on hover, selects on click.
Files: product.js
// product.js
$(".videoSelector").hover(function () {
mainVid.show(); // Show video on hover
}).click(function () {
selector.toggleClass("selectedThumb");
});
Cart & Quantity Controls
frm-add-to-cart
JavaScript Function: Form submit event handler, adds or updates the product in the cart.
Files: 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 Function: Quantity increase button, increases the product quantity on click.
Files: 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); // Increase quantity
});
btn-qty-decrease
JavaScript Function: Quantity decrease button, decreases the product quantity on click.
Files: 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); // Decrease quantity
});
Measure/Package Selection
pc-measure-box
JavaScript Function: Measure selection in the product card - selects the radio button on click, updates the quantity input.
Files: 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 Function: Added/removed by JavaScript to mark the active measure box.
Files: product.js
// product.js
subMeasureBoxes.forEach(function (subBox) {
subBox.classList.remove("pc-active");
});
box.classList.add("pc-active");
measure-box
JavaScript Function: Measure selection on the detail page - becomes active on click.
Files: 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 Function: Measure selection button triggers click event.
Files: product.js, product_detail.js
// product.js
const selectButton = box.querySelector(".select-btn");
selectButton.addEventListener("click", function (e) {
radioButton.checked = true;
});
Favorites
btn-add-to-favorites
JavaScript Function: Adds/removes the product from favorites.
Files: 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); // Add to favorites
});
Navigation & Menus
pnlSidebarCart
JavaScript Function: Renders the cart content on the Bootstrap offcanvas show event.
Files: layout.js
// layout.js
pnlSidebarCart.addEventListener("show.bs.offcanvas", function () {
renderSidebarCart(); // Load cart content
});
Filtering & Listing
urunlistesi
JavaScript Function: Container for the infinite scroll library - new products are appended here.
Files: 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 Function: Product card appended by infinite scroll.
Files: list.js
<div class="pnlurun-item">
{% include '_product_card.twig.php' %}
</div>
// list.js
let infScroll = new InfiniteScroll(elem, {
append: ".pnlurun-item" // New products are appended here
});
filter-search
JavaScript Function: Keyup event handler for searching within filters.
Files: 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 Function: Filter item is shown/hidden based on search results.
Files: 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 = ''; // Show
} else {
item.style.display = 'none'; // Hide
}
});
}
Price Display
price
JavaScript Function: Price display element - innerHTML is updated when the variant changes.
Files: 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 Function: Alternative currency price is updated when the variant changes.
Files: product.js, product_detail.js
// product.js
alternate_price.innerHTML = selector.dataset.alternatePrice;
Lazy Loading
lazyload
JavaScript Function: Used by the LazySizes library to load images when they enter the viewport.
Files: All template files
<img class="lazyload"
data-src="{{ product.med_image }}"
src="{{ product.min_image }}"
alt="{{ product.title }}">
Custom Container Selectors
pro / card
JavaScript Function: Used with closest() to find the product container.
Files: product.js
// product.js
var pnlContainer = selector.closest(".pro") || selector.closest(".card");
Important Data Attributes
Critical data attributes for JavaScript functionality:
{# Product Data Attributes #}
<div class="product-card-body"
data-product-id="{{ product.id }}"
data-urunid="{{ product.id }}">
</div>
{# Variant 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>
{# Quantity 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 }}">
{# Gallery Data Attributes #}
<div class="productVariantSelect"
data-galeri_index="{{ iiVariant }}"
data-varyantid="{{ variant.id }}">
</div>
{# Filter Data Attributes #}
<a class="filters" data-search="{{ filter.label }}">
{{ filter.label }}
</a>
JavaScript Function Summary
| Class Name | JavaScript Function | Event Type | File |
|---|---|---|---|
productThumbSelector | Variant selection, image/price update | click | product.js |
selectedThumb | Selected state marking | classList | product.js |
productVariantSelect | Detail page variant selection | click | product_detail.js |
mainImg | Main image update | src, classList | product.js |
product-card-body | Variant image preload | mouseenter | product.js |
urungorselleri | Gallery thumbnail selection | click | product_detail.js |
product-image-clickable | Image modal open | click | product_detail.js |
product-video-btn | Video modal open | click | product.js |
frm-add-to-cart | Add to cart | submit | product.js |
btn-qty-increase | Quantity increase | click | product_shared.js |
btn-qty-decrease | Quantity decrease | click | product_shared.js |
pc-measure-box | Measure selection | click | product.js |
pc-active | Active measure marking | classList | product.js |
measure-box | Detail measure selection | click | product_detail.js |
btn-add-to-favorites | Add/remove from favorites | click | product.js |
pnlSidebarCart | Cart 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 | Filter search | keyup | list.js |
filters | Filter show/hide | classList toggle | list.js |
zoom | Image zoom | plugin init | product_detail.js |
price | Price update | innerHTML | product.js |
alternate-price | Alternate price update | innerHTML | product.js |
lazyload | Lazy loading | library | LazySizes |
pro / card | Container selector | closest() | product.js |
These classes are used for all JavaScript interactions in the SerB2B system. When adding new features, use these classes or create new ones following a similar naming convention.