Kod teması (Liquid)
Sitenizi kendi HTML, CSS ve JavaScript kodunuzla yazın; dosya yapısı, değişkenler, filtreler, güvenlik kuralları ve eksiksiz bir örnek tema.
Ne zaman kullanılır
Hazır tasarımlar ve sayfa oluşturucu çoğu panel için yeterlidir. Vitrininizi piksel piksel kendiniz tasarlamak istiyorsanız Admin → Kod teması ile sitenin ana sayfasını ve kendi sayfalarınızı Liquid şablonlarıyla yazabilirsiniz.
Kod teması yalnızca vitrin sayfalarını değiştirir. Sipariş, ödeme, giriş/kayıt, müşteri paneli ve hizmetler sayfası her zaman olduğu gibi çalışır. Tema CSS değişkenleri, özel CSS'iniz ve özel kodunuz kod temalı sayfalarda da yüklenir.
Dosyalar
| Dosya | Adres | Görevi |
|---|---|---|
layout.liquid | — | Her temalı sayfayı saran iskelet. Sayfa içeriği {{ content_for_layout | raw }} ile yerleşir. Zorunlu. |
home.liquid | /tr | Ana sayfa. Zorunlu. |
hakkimizda.liquid | /tr/hakkimizda | Her {ad}.liquid dosyası kendi adresinde yayınlanır |
_kart.liquid | — | Alt çizgiyle başlayan dosyalar parçadır; adresi yoktur, {% render '_kart' %} ile kullanılır |
Kurallar:
- Dosya adı: küçük harf, rakam ve tire; parçalar için başta
_; en fazla 42 karakter +.liquid. - En fazla 40 dosya, dosya başına en fazla 100 KB.
- Ayrılmış adresler (
admin,dashboard,login,register,services,blog,api,api-docs,order,media… ) sayfa dosyası olamaz. - Ayrı CSS/JS/görsel dosyası yüklenmez: CSS'i
<style>, JavaScript'i<script>olarak yazın; görselleri Medya kütüphanesine yükleyip/media/...adresiyle kullanın. - Kaydederken her dosya ayrıştırılır; sözdizimi hatası varsa dosya adı ve hatanın ilk satırı gösterilir.
Değişkenler
| Değişken | İçerik |
|---|---|
site.name, site.url, site.logo, site.logo_dark | Panel adı, adresi, logolar |
site.locale, site.locales | Geçerli dil ve paneldeki diller |
site.support_email, site.telegram | Destek e-postası ve Telegram bağlantısı |
user.logged_in | Ziyaretçi giriş yapmış mı |
user.email, user.name, user.balance | Giriş yapmışsa; bakiye USD sayı olarak |
nav.header | Menü öğeleri: { label, href } listesi |
catalog.groups | Hizmet grupları: { name, slug, platform, services (adet), categories: [{ name }] } |
catalog.service_count | Toplam satıştaki hizmet sayısı |
blog.posts | Son yazılar: { title, excerpt, cover, url, date } |
page.template, page.locale | Çizilen dosyanın adı ve dil |
content_for_layout | Yalnızca layout.liquid içinde: sayfanın çizilmiş içeriği |
Tanımsız bir değişken boş yazılır, hata vermez.
Filtreler
Liquid'in bütün yerleşik filtreleri (date, upcase, truncate, where, sort…) ve etiketleri (if, for, assign, capture, render…) kullanılabilir. SMMFor üç filtre ekler:
| Filtre | Örnek | Sonuç |
|---|---|---|
t | {{ 'nav.services' | t }} | Panelin çeviri metni (ziyaretçinin dilinde). Anahtar yoksa anahtarın kendisi yazılır. |
url | {{ '/services' | url }} | Dil önekli adres: /tr/services. https:// adresleri olduğu gibi kalır. |
money | {{ user.balance | money }} | USD tutarı biçimlendirir: $12.50 |
Bilinmeyen bir filtre hatadır (yazım hatalarını yakalamak için).
Güvenlik kuralları
{{ }}çıktıları HTML olarak kaçışlanır. Güvendiğiniz HTML'i olduğu gibi basmak için| rawkullanın.- Şablonlar diske ve internete erişemez; yalnızca temanın kendi dosyalarını
renderedebilir. - Her sayfa için süre (250 ms) ve bellek sınırı vardır.
<script>etiketlerinize sitenin güvenlik anahtarı (nonce) otomatik eklenir; harici scriptler de bunlar üzerinden yüklenebilir.onclick="..."gibi satır içi olay öznitelikleri vejavascript:bağlantıları çalışmaz; olaylarıaddEventListenerile bağlayın.- Yayınlama ve etkinleştirme 2FA kodunuzu (yoksa admin şifrenizi) ister, çünkü tema sitenizde script çalıştırabilir.
- Bir sayfada hata olursa site çökmez; o sayfanın yerine hata mesajı görünür.
Yayınlama akışı
- Taslağı kaydet: siteye dokunmaz.
- Önizle: taslağı yeni sekmede
?theme_preview=1ile açar. Taslağı yalnızca siz (admin) görürsünüz. - Yayınla: taslağı canlı sürüm yapar ve geçmişe ekler (son 20 sürüm saklanır).
- "Sitemde kod temasını kullan" kutusunu işaretleyin. Tema yalnızca yayınlanmış ve etkin olduğunda gösterilir. Kapattığınızda site hemen blok sayfalarınıza/tasarımınıza döner.
- Önceki sürüme dön: geçmişteki bir sürümü taslağa yükler; yayınlayana kadar sitede bir şey değişmez.
Yayınlanan tema 60 saniyeye kadar önbellekte kalabilir.
Eksiksiz örnek tema
Aşağıdaki dört dosya; menü, giriş durumuna göre butonlar, platform kartları, blog yazıları, SSS ve hakkımızda sayfası olan çalışan bir temadır. Renkler tema değişkenlerinden geldiği için Görünüm'deki renk ayarlarınız bu temada da geçerlidir.
layout.liquid
<div class="ct">
<header class="ct-header">
<a class="ct-brand" href="{{ '/' | url }}">
{% if site.logo != blank %}<img src="{{ site.logo }}" alt="{{ site.name }}" height="32">{% else %}{{ site.name }}{% endif %}
</a>
<nav class="ct-nav">
{% for item in nav.header %}<a href="{{ item.href }}">{{ item.label }}</a>{% endfor %}
<a href="{{ '/services' | url }}">{{ 'nav.services' | t }}</a>
<a href="{{ '/hakkimizda' | url }}">Hakkımızda</a>
</nav>
<div class="ct-actions">
{% if user.logged_in %}
<span class="ct-balance">{{ user.balance | money }}</span>
<a class="ct-btn" href="{{ '/dashboard/new-order' | url }}">{{ 'nav.dashboard' | t }}</a>
{% else %}
<a href="{{ '/login' | url }}">{{ 'nav.login' | t }}</a>
<a class="ct-btn" href="{{ '/register' | url }}">{{ 'nav.register' | t }}</a>
{% endif %}
</div>
<button class="ct-burger" type="button" aria-label="Menü">☰</button>
</header>
<main>{{ content_for_layout | raw }}</main>
<footer class="ct-footer">
<span>© {{ 'now' | date: '%Y' }} {{ site.name }}</span>
{% if site.support_email != blank %}<a href="mailto:{{ site.support_email }}">{{ site.support_email }}</a>{% endif %}
{% if site.telegram != blank %}<a href="{{ site.telegram }}">Telegram</a>{% endif %}
</footer>
</div>
<style>
.ct { max-width: 1160px; margin: 0 auto; padding: 20px 16px; color: var(--on-surface); }
.ct-header { display: flex; align-items: center; gap: 20px; padding: 10px 0 28px; }
.ct-brand { font: 800 20px/1 var(--font-family-display); display: flex; align-items: center; }
.ct-nav { display: flex; gap: 18px; margin-left: 12px; }
.ct-nav a, .ct-actions a { color: var(--on-surface-variant); font-weight: 600; }
.ct-nav a:hover { color: var(--primary); }
.ct-actions { margin-left: auto; display: flex; align-items: center; gap: 14px; }
.ct-balance { font-weight: 700; color: var(--primary); }
.ct-btn { background: var(--brand-solid); color: var(--on-brand) !important; padding: 10px 18px; border-radius: var(--radius-3xl); font-weight: 700; }
.ct-burger { display: none; margin-left: auto; font-size: 22px; background: none; border: 0; color: inherit; }
.ct-card { background: var(--surface-container-lowest); border: 1px solid var(--outline-variant); border-radius: var(--radius-2xl); padding: 20px; }
.ct-footer { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 72px; padding-top: 24px; border-top: 1px solid var(--outline-variant); color: var(--on-surface-variant); font-size: 14px; }
@media (max-width: 760px) {
.ct-nav, .ct-actions { display: none; }
.ct-burger { display: block; }
.ct.open .ct-nav, .ct.open .ct-actions { display: flex; flex-direction: column; align-items: flex-start; width: 100%; margin: 0; }
.ct-header { flex-wrap: wrap; }
}
</style>
<script>
// Satır içi onclick çalışmaz; olayları addEventListener ile bağlayın.
document.querySelector(".ct-burger")?.addEventListener("click", () => {
document.querySelector(".ct")?.classList.toggle("open");
});
</script>
home.liquid
<section class="hero">
<p class="eyebrow">{{ catalog.service_count }} hizmet · 7/24 destek</p>
<h1>{{ site.name }} ile hesaplarınızı büyütün</h1>
<p class="lead">{{ 'landing.lead' | t }}</p>
<div class="cta">
<a class="ct-btn" href="{{ '/dashboard/new-order' | url }}">{{ 'landing.ctaPrimary' | t }}</a>
<a href="{{ '/services' | url }}">Fiyat listesi →</a>
</div>
</section>
{% render '_platforms', catalog: catalog %}
{% if blog.posts.size > 0 %}
<h2 class="title">Blogdan</h2>
<div class="grid">
{% for p in blog.posts limit: 3 %}
<a class="ct-card" href="{{ p.url }}">
{% if p.cover != blank %}<img src="{{ p.cover }}" alt="" loading="lazy">{% endif %}
<strong>{{ p.title }}</strong>
<p>{{ p.excerpt | truncate: 120 }}</p>
</a>
{% endfor %}
</div>
{% endif %}
<h2 class="title">Sık sorulanlar</h2>
<details class="ct-card"><summary>Sipariş ne zaman başlar?</summary><p>Çoğu hizmet birkaç dakika içinde başlar.</p></details>
<details class="ct-card"><summary>Ödeme yöntemleri neler?</summary><p>Kart, kripto ve havale ile bakiye yükleyebilirsiniz.</p></details>
<style>
.hero { text-align: center; padding: 56px 0 40px; }
.hero h1 { font: 900 clamp(32px, 6vw, 56px)/1.08 var(--font-family-display); letter-spacing: -0.02em; }
.eyebrow { color: var(--primary); font-weight: 700; text-transform: uppercase; letter-spacing: .12em; font-size: 12px; }
.lead { max-width: 560px; margin: 16px auto 28px; color: var(--on-surface-variant); font-size: 18px; }
.cta { display: flex; gap: 18px; justify-content: center; align-items: center; }
.title { font: 800 26px/1.2 var(--font-family-display); margin: 56px 0 18px; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
.grid img { width: 100%; border-radius: var(--radius-xl); margin-bottom: 10px; }
details.ct-card { margin-bottom: 10px; }
details summary { cursor: pointer; font-weight: 700; }
</style>
_platforms.liquid
<section class="platforms">
{% for group in catalog.groups limit: 8 %}
<a class="ct-card platform" href="{{ '/services' | url }}#{{ group.slug }}">
<strong>{{ group.name }}</strong>
<span>{{ group.services }} hizmet</span>
<small>{% for c in group.categories limit: 3 %}{{ c.name }}{% unless forloop.last %} · {% endunless %}{% endfor %}</small>
</a>
{% endfor %}
</section>
<style>
.platforms { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
.platform { display: flex; flex-direction: column; gap: 4px; transition: transform .15s; }
.platform:hover { transform: translateY(-2px); border-color: var(--primary); }
.platform span { color: var(--primary); font-weight: 700; }
.platform small { color: var(--on-surface-variant); }
</style>
hakkimizda.liquid
<section class="ct-card" style="max-width:760px;margin:24px auto">
<h1 style="font:800 34px/1.15 var(--font-family-display)">Hakkımızda</h1>
<p>{{ site.name }}, sosyal medya hizmetlerini toptan fiyata sunan bir paneldir.</p>
{% if user.logged_in %}
<p>Hoş geldiniz {{ user.name | default: user.email }}! Bakiyeniz: <strong>{{ user.balance | money }}</strong></p>
{% endif %}
</section>
Bu sayfa /tr/hakkimizda adresinde yayınlanır.
Sık yapılan hatalar
| Belirti | Neden / çözüm |
|---|---|
| HTML etiketleri yazı olarak görünüyor | Çıktı kaçışlanıyor. Güvendiğiniz HTML için | raw kullanın. |
undefined filter: ... | Filtre adında yazım hatası; yalnızca Liquid'in filtreleri ve t, url, money vardır. |
Template not found: _x | Parça dosyası yok ya da adı farklı; render içinde .liquid uzantısı yazmayın. |
| Buton tıklayınca bir şey olmuyor | Satır içi onclick engellenir; addEventListener kullanın. |
| Değişiklik sitede görünmüyor | Yayınladınız mı ve "kod temasını kullan" açık mı? Önbellek için 1 dakika bekleyin. |
X: this address is used by the panel | Dosya adı ayrılmış bir adresle çakışıyor; başka bir ad seçin. |