SMMFor

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

DosyaAdresGörevi
layout.liquid—Her temalı sayfayı saran iskelet. Sayfa içeriği {{ content_for_layout | raw }} ile yerleşir. Zorunlu.
home.liquid/trAna sayfa. Zorunlu.
hakkimizda.liquid/tr/hakkimizdaHer {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_darkPanel adı, adresi, logolar
site.locale, site.localesGeçerli dil ve paneldeki diller
site.support_email, site.telegramDestek e-postası ve Telegram bağlantısı
user.logged_inZiyaretçi giriş yapmış mı
user.email, user.name, user.balanceGiriş yapmışsa; bakiye USD sayı olarak
nav.headerMenü öğeleri: { label, href } listesi
catalog.groupsHizmet grupları: { name, slug, platform, services (adet), categories: [{ name }] }
catalog.service_countToplam satıştaki hizmet sayısı
blog.postsSon yazılar: { title, excerpt, cover, url, date }
page.template, page.localeÇizilen dosyanın adı ve dil
content_for_layoutYalnı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ÖrnekSonuç
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 | raw kullanın.
  • Şablonlar diske ve internete erişemez; yalnızca temanın kendi dosyalarını render edebilir.
  • 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 ve javascript: bağlantıları çalışmaz; olayları addEventListener ile 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ışı

  1. Taslağı kaydet: siteye dokunmaz.
  2. Önizle: taslağı yeni sekmede ?theme_preview=1 ile açar. Taslağı yalnızca siz (admin) görürsünüz.
  3. Yayınla: taslağı canlı sürüm yapar ve geçmişe ekler (son 20 sürüm saklanır).
  4. "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.
  5. Ö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

BelirtiNeden / çö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: _xParça dosyası yok ya da adı farklı; render içinde .liquid uzantısı yazmayın.
Buton tıklayınca bir şey olmuyorSatır içi onclick engellenir; addEventListener kullanın.
Değişiklik sitede görünmüyorYayı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 panelDosya adı ayrılmış bir adresle çakışıyor; başka bir ad seçin.