İçeriğe geç

Menü, widget ve görünüm

Bir tema yalnızca şablon değil, yöneticinin kod yazmadan şekillendirebileceği bir yüzey de sunmalıdır: hangi menü nerede görünür, hangi kutular yan çubukta olur, marka renkleri ne olur. Bu sayfa bunların nasıl bağlandığını anlatır.

Menü konumları

Menüleri Studio → Menü Yönetimi'nde kurarsınız; konum, bir menünün temada nerede çizileceğini söyler. Tema konumlarını theme.json içinde bildirir:

{
    "menu_locations": {
        "main_header": "Ana başlık",
        "footer": "Alt bilgi",
        "footer_legal": "Yasal bağlantılar"
    }
}

Yönetici bir menüyü bu konumlardan birine atar. Şablonda iki yoldan çizersiniz:

{# 1. Hazır işaretleme: rel, target, ikon ve CSS sınıfları dahil #}
{{ cp_menu_location('main_header') }}

{# 2. Kendi işaretlemeniz: öğe ağacı #}
<nav aria-label="Ana menü">
    <ul>
    {% for item in cp_menu_location_items('main_header') %}
        <li>
            <a href="{{ item.url }}"{{ item.openInNewTab ? ' target="_blank" rel="noopener"' : '' }}>{{ item.label }}</a>
            {% if item.children %}
                <ul>{% for child in item.children %}<li><a href="{{ child.url }}">{{ child.label }}</a></li>{% endfor %}</ul>
            {% endif %}
        </li>
    {% endfor %}
    </ul>
</nav>

Öğe alanları: label, url, openInNewTab, children (iç içe aynı biçimde). Konuma menü atanmamışsa öğe listesi boştur; boş durumu şablonda zarifçe işleyin.

Modüller de konum bildirebilir (MenuLocationProviderInterface); bunlar temanın konumlarının yanında yöneticinin seçim listesinde görünür. Konum kimlikleri kararlı olmalıdır: yeniden adlandırmak mevcut atamayı koparır.

Widget alanları

Widget, sayfada bir alana (yan çubuk, alt bilgi sütunu) yerleştirilen içerik parçasıdır ("Son yazılar", "Özel HTML", "Etiket bulutu"). Yönetici Studio → Widget'tan alanlara widget ekler ve sıralar.

Şablonda alanı çizmek:

<aside class="sidebar">
    {{ cp_widget_area('blog_sidebar') }}
</aside>

cp_widget_area Widget modülü kapalıysa boş dize döner; widget modülü olmayan bir sitede tema yine çizilir. Alan bildirilmiş olmalıdır, yoksa Studio'da görünmez (bir modül ya da tema WidgetAreaProviderInterface ile alanlarını bildirir).

Kendi widget türünüzü yazmak

Bir modül WidgetTypeInterface uygulayarak yeni bir widget türü ekler; Widget modülü onu toplar, Studio'da sunar ve çizer. Çekirdek tür sınıfını import etmez; Widget modülü olmayan sitede tür sessizce kullanılmaz.

final class RecentNotesWidget implements WidgetTypeInterface
{
    public function id(): string { return 'notes.recent'; }
    public function label(): string { return 'notes.widget.recent'; }
    public function description(): string { return 'notes.widget.recent_help'; }
    public function icon(): string { return 'heroicons:pencil-square'; }
    public function group(): string { return 'content'; }

    public function fields(): array
    {
        return [
            WidgetField::text('title', 'notes.widget.title', 'Son notlar'),
            WidgetField::number('limit', 'notes.widget.limit', 5, 1, 20),
            WidgetField::checkbox('show_dates', 'notes.widget.dates', true),
        ];
    }

    public function render(array $settings, WidgetRenderContext $context): string
    {
        // Çıktıyı kaçışlayın: widget HTML'i güvenli kabul edilir.
        return '<div class="widget">…</div>';
    }
}

Alan türleri: text, textarea, html, number, checkbox, url, select. Bir alanı translatable() yaparsanız her dil için ayrı değer girilir. Tür autoconfigure ile otomatik toplanır.

Marka ve renkler

Yönetici AACP → Görünüm → Tema seçenekleri ekranından siteye logo, favicon, sosyal paylaşım görseli, renkler ve ölçüler seçer. Tema bunları şablonda şöyle alır:

<link rel="icon" href="{{ cp_appearance().favicon }}">
<img src="{{ cp_appearance().logo }}" alt="{{ 'website.title'|trans }}" height="{{ cp_appearance().metrics.logo_height }}">
<style{{ csp_nonce_attr() }}>{{ cp_appearance_css() }}</style>

cp_appearance_css() yöneticinin kaydettiği renkleri :root içinde CSS değişkenleri olarak yazar. Boş bırakılan renk temanın varsayılanında kalır; kaydedilen her renk yalnızca o bir değişkeni ezer. Bu yüzden temanızın CSS'i bu değişkenleri kullanmalıdır:

.btn-primary { background: var(--cp-primary); color: var(--cp-white); }
a { color: var(--cp-accent); }

Değişken sözleşmesi

Grup Değişkenler (varsayılan)
Vurgu --cp-primary (#4A7C9B), --cp-primary-dark, --cp-primary-light, --cp-accent (#4AADE4), --cp-accent-hover, --cp-gold
Yüzey --cp-dark, --cp-darker, --cp-light, --cp-lighter, --cp-white
Metin --cp-text, --cp-text-secondary, --cp-text-muted, --cp-border
Durum --cp-success, --cp-danger

Ölçüler: logo_height (32 px; 16-160), logo_width (0 = otomatik), site_width (1200 px; 960-1680), navbar_height (64 px; 48-120).

Koyu/açık tema yazıyorsanız kendi değişkenlerinizi (--gh-* gibi) tanımlayıp --cp-* değişkenlerini onlara yönlendirebilirsiniz; Githeme bu yolu izler.

Yazı tipleri

AACP → Görünüm → Yazı tipleri ekranından yönetici gövde, başlık, kod ve serif yazı tiplerini (ve H1-H3 için ayrı) seçer. Seçilen yazı tipleri sunucuya yerel indirilir; bir CDN çağrılmaz (gizlilik ve CSP). Sonuç tek bir CSS dosyasıdır:

{% set cpFonts = cp_font_stylesheet() %}
{% if cpFonts %}<link rel="stylesheet" href="{{ cpFonts }}">{% endif %}

Bu bağlantıyı temanızın CSS'inden sonra koyun: :root bloğu temanın varsayılan yığınlarını ezer. Yönetici bir yazı tipi kurmadıysa cp_font_stylesheet() boştur ve tema varsayılanları geçerlidir.

Çerez onayı

Çerez onayı yönetici ayarıyla (consent.enabled) açılır. Temanın yapması gereken iki şey:

{{ cp_consent_mode() }}       {# <head> içinde, diğer her betikten önce: Google Consent Mode v2 varsayılanları #}
{{ cp_cookie_consent() }}     {# gövde sonunda: onay çubuğu #}

Onay gerektiren betikleri type="text/plain" ve data-cp-consent ile yazın; yalnızca ilgili kategori onaylanınca çalışır:

<script type="text/plain" data-cp-consent="analytics" src="/js/sayac.js"></script>

Kategoriler analytics ve marketing'dir; zorunlu çerezler her zaman izinlidir. data-cp-consent-open taşıyan bir bağlantı ya da düğme, tercihleri yeniden açar.

Medya seçici metinleri

Studio dışındaki bir şablonda medya seçici kullanacaksanız (ör. ön yüzde profil görseli yükleme), seçicinin çeviri metinlerini bir JSON bloğuyla geçin:

<script type="application/json" id="cp-media-picker-i18n">{{ {
    title: 'media.picker.title'|trans,
    close: 'media.picker.close'|trans,
    loading: 'media.picker.loading'|trans,
    uploadFailed: 'media.picker.upload_failed'|trans,
    listFailed: 'media.picker.list_failed'|trans,
}|json_encode|raw }}</script>
Son güncelleme: 13.10.2026