# Menüler ve Navigasyon

https://dev.wisecp.com/tr/menuler-ve-navigasyon

Navigasyon, operatörün panelde düzenlediği veridir. Tema hazır ağaçları alıp gösterir ve diğer bütün adresleri yazılı bir yol yerine bir rota anahtarından kurar.

## Genel Bakış

Menüde ne olacağına tema karar vermez. Operatör ağaçları panelde kurar. Platform her düğümün adresini çözer ve view'a hazır dizi verir. Temaya ait olan markup'tır: açılır menü nasıl görünür, mobil çekmece nerede durur, hangi düğüm ikon hak eder.

Aynı kural temanın kendi yazdığı bağlantılar için de geçerlidir. "Giriş" ya da "Sepet" bağlantısı bir yolla değil **rota anahtarıyla** adreslenir. Rota yolları dile göre çevrilir ve yeniden adlandırılabilir. Yazılı bir yol ikinci dilde, sonra ilk yeniden adlandırmada kırılır.

## Yapı

### Müşteri Sayfasına Ulaşan Ağaçlar

- **$header_menu**: Genel üst menü. Düğümler alt öğe (açılır menü) ya da operatörün yazdığı bir markup paneli (mega menü) taşıyabilir.
- **$footer_menu**: Altbilgi. Üst seviyesi kolonlardır, her düğümün alt öğeleri o kolonun bağlantılarıdır. Üst menüden bir seviye derin okuyun.
- **$mobile_menu**: Çekmece. Operatör ayrı bir ağaç kurmadıysa üst menü ağacına düşer; tema onu her koşulda gösterebilir.
- **Diğer tipler**: Panel ayrıca bir kenar ağacı (`sidebar`) yönetir. Müşteri paketinde yoktur; ihtiyacı olan view onu temanın kanca dosyasında ister. Müşteri paneli menüsü bir menü ağacı değildir: her tema onu açık özelliklerden ve müşteri sayfası olan eklentilerden kurar, `ui:client.subnav.items` ona öğe ekler. Eski `clientArea` grubunu hiçbir tema göstermez.

### Bir Düğümün Biçimi

```php
$node = [
    'id'     => 12,
    'parent' => 0,
    'icon'   => 'bi bi-hdd-rack',      // sınıf dizesidir, adres değil
    'target' => 1,                      // 1 yeni sekmede açar
    'page'   => 'category/551',         // panelin sayfa tanımlayıcısı, aşağıda zaten çözülmüş
    'title'  => 'Hosting',              // AKTİF dilde
    'link'   => 'https://example.com/hosting',   // BOŞ olabilir: yalnız başlık olan düğüm
    'extra'  => [
        'desc'  => 'Paylaşımlı ve bayi planları',  // açılır menü satırında ikinci satır
        // Rozet. İki renk de panelin renk seçicilerinden gelir; yani baştaki diyeziyle
        // birer onaltılık dize olarak gelir ve doğrudan bir style özniteliğine girer.
        'tag'   => ['name' => 'Yeni', 'color' => '#RRGGBB', 'text_color' => '#RRGGBB', 'icon' => 'bi bi-stars'],
        'mega'  => '<div class="mega">…</div>',  // operatörün yazdığı markup, bağlantıları çözülmüş
    ],
    'children' => [ /* aynı biçim, özyinelemeli */ ],
];
```

Adres view onu görmeden çözülür. Panel sayfasına bağlı bir düğüm bitmiş bağlantıyı `link` alanında taşır; hiçbir şablon tanımlayıcıyı kendisi çevirmez.

## Adım Adım

### Üst Menü Ağacını Basın

1. Üst seviyeyi dolaşın ve düğümün taşıdığına göre dallanın: alt öğe varsa açılır menü, mega panel varsa ham markup, ikisi de yoksa düz öğe.
2. Adresi koruyun. Düğüm, bağlantısı olmayan bir başlık olabilir. Özniteliği yalnız `link` doluyken basın.
3. Mega paneli escape etmeden basın. Operatörün yazdığı HTML'dir ve motor varsayılan olarak escape eder; aksi hâlde etiketler ekranda görünür.
4. Listeyi navigasyon enjeksiyon noktasıyla kapatın; bir modül parçayı düzenlemeden öğe ekleyebilir. Üst menü artık operatörün kurduğu her menüye dayanır.

### Altbilgi Ağacını Basın

1. Üst seviyeyi kolon olarak dolaşın ve her düğümün başlığını kolon başlığı olarak basın.
2. O düğümün alt öğelerini kolonun bağlantıları olarak dolaşın; aynı boş adres korumasıyla.
3. Kolonlardan sonra altbilgi enjeksiyon noktasını koyun. Artık operatör kolon eklediğinde altbilgi şablon değişmeden büyür.

### Temanın Kendi Yazdığı Sayfaları Adresleyin

1. Platform sayfaları için bağlantı fonksiyonunu **rota anahtarıyla** kullanın: sepet, giriş, hesap özeti, destek talebi formu.
2. Rota parametre alıyorsa konumsal parametreleri desenin bildirdiği sırada geçin.
3. Operatörün panelde seçtiği bir kayda bağlanıyorsanız (içerik sayfası, kategori) sayfa biçimini kullanın; menü sisteminin sakladığı tanımlayıcıyı alır.
4. Sorgu dizesini asla elle birleştirmeyin. Sayfayı açın ve adresin dil değişimini atlattığını doğrulayın; anahtarın amacı budur.

### Temanın Sunmadığı Sayfalara Giden Bağlantıları Gizleyin

1. Temanızın uygulamadığı rota anahtarlarını manifestin meta bloğunda listeleyin. Platform o adreslere yarım sayfa yerine bulunamadı cevabı verir.
2. Aynı listeyi temanın kanca dosyasından şablonlara anahtarlı harita olarak verin. Şablon sandbox'ında dizi arama fonksiyonu yoktur; bir koşulun okuyabileceği şey haritadır.
3. Oraya götüren her bağlantıyı bu koşulla sarın. Kapalı bir rotanın görünür bağlantısı, ziyaretçinin sizden önce bulacağı bir çıkmazdır.

## Referans

### Menüler Yardımcısı

```php
// $type: 'header' | 'footer' | 'mobile' | 'sidebar' (ilk üçü her sayfada yüklenir)
// $parent: tüm ağaç için 0, ya da altından başlanacak düğüm kimliği
// $lang: boş bırakmak aktif dil demektir
public static function tree(string $type = 'header', int $parent = 0, string $lang = ''): array;

// Operatörün yazdığı markup içindeki {link page='...'} / {link route='...'} yer tutucularını
// çözer. Düğümün mega paneline zaten uygulanır; kendi sakladığınız HTML için siz çağırın.
public static function resolveLinks(string $html): string;
```

- **Önbellek**: Tip ve dil başına tek sorgu, bir saat önbellekli ve istek boyunca hafızada. Panelde kaydetmek temizler; temada yapılacak bir şey yoktur.
- **filter:client.menu**: Tüm ağaç için bir kez, referansla, satırlar ve `type` ile `lang` içeren bir bağlamla çalışır. Temanın, panelin yönetmediği bir düğümü eklediği ya da çıkardığı yer burasıdır. Satırları yerinde düzenleyin; dönüş yoksayılır.
- **Yalnız aktif düğümler**: Devre dışı satırlar ağaca hiç ulaşmaz, bu yüzden şablonun durum kontrolüne ihtiyacı yoktur.

### Bağlantı Fonksiyonu

- **{link route='cart'}**: Bu dilin yoluna çevrilen bir rota anahtarı. Anahtarlar rota dil dosyalarında bildirilir; aynı anahtar her dilde cevap verir.
- **{link route='invoice-detail' p1=$id}**: En fazla beş konumsal parametre; rota desenine sırayla yerleşir. Diğer etiket motorunda bunlar rotadan sonraki argümanlardır.
- **{link page='pages/4'}**: Panel sayfa tanımlayıcısı (içerik sayfası, kategori, ürün grubu); menü sisteminin çözdüğü yolla çözülür.
- **PHP tarafı**: Aynı üç biçim `LinkGenerator::client()`, `LinkGenerator::convert_to_link()` ve sorgu dizesi için `LinkGenerator::wQS()` metotlarıdır.

```php
// $lang: boş bırakmak aktif dil demektir; aynı sayfayı başka dilde kurmak için doldurun.
public static function client($route = '', $params = [], $lang = ''): string;

// Panel tanımlayıcısını ("pages/4", "category/551", "home") bitmiş adrese çevirir.
public static function convert_to_link(string $arg): string;

// Sorgu dizesi ekler. Elle birleştirmeyin: bu metot adresin zaten "?" taşıyıp
// taşımadığını bilir.
public static function wQS(string|bool|null $url, array|string $params = []): string;
```

## Örnek

Üst menü parçası ve ardından bu temanın sunmadığı bir bölümü kapatan kanca dosyası. İki yarım birlikte gösterilir: şablondaki koşul onu besleyen harita olmadan anlamsızdır.

```smarty
<ul class="nav site-nav">
    {foreach $header_menu as $item}
        {if $item.children}
    <li class="nav-item dropdown">
        <a class="nav-link"{if $item.link} href="{$item.link}"{/if}>{$item.title}</a>
        <div class="dropdown-menu">
            {foreach $item.children as $child}
            <a class="dropdown-item"{if $child.link} href="{$child.link}"{/if}{if $child.target} target="_blank" rel="noopener"{/if}>
                <i class="{$child.icon}"></i>
                <span>{$child.title}</span>
                {if $child.extra.desc ?? ''}<span class="item-desc">{$child.extra.desc}</span>{/if}
            </a>
            {/foreach}
        </div>
    </li>
        {elseif $item.extra.mega ?? ''}
    {* Operatörün yazdığı markup: ham basılır, yoksa etiketlerin kendisi sayfada görünür. *}
    <li class="nav-item dropdown">
        <a class="nav-link"{if $item.link} href="{$item.link}"{/if}>{$item.title}</a>
        <div class="dropdown-menu">{$item.extra.mega nofilter}</div>
    </li>
        {else}
    <li class="nav-item"><a class="nav-link"{if $item.link} href="{$item.link}"{/if}>{$item.title}</a></li>
        {/if}
    {/foreach}

    {* Bu temanın kapattığı bir bölüm: harita hooks.php'den, rota anahtarından gelir. *}
    {if !$route_off.affiliate}
    <li class="nav-item"><a class="nav-link" href="{link route='affiliate'}">{lang key='nav_affiliate'}</a></li>
    {/if}

    {hook name='ui:client.nav.items'}
</ul>

<a class="btn" href="{link route='cart'}">{lang key='nav_cart'}</a>
<a class="btn" href="{link route='invoice-detail' p1=$latest_invoice_id}">{lang key='nav_last_invoice'}</a>
```

```php
Hook::add("filter:template.variables", 1, function ($template, $data) {

    // Liste değil anahtarlı harita: şablon sandbox'ında in_array() yoktur, koşul
    // yalnız {if !$route_off.affiliate} diye sorabilir.
    $data["route_off"] = array_fill_keys(Theme::active()->meta()["disabled_routes"] ?? [], true);

    return $data;
});

/*
 * Panelin yönetmediği bir düğüm. Referansla: ağaç yerinde değiştirilir ve bağlam
 * hangi ağaç olduğunu söyler, böylece bir üst menü kuralı altbilgiye dokunmaz.
 */
Hook::add("filter:client.menu", 10, function (&$rows, $ctx) {
    if (($ctx["type"] ?? '') !== 'header') return;

    $rows[] = [
        'id'       => 0,
        'parent'   => 0,
        'icon'     => 'bi bi-life-preserver',
        'target'   => 0,
        'page'     => '',
        'title'    => Theme::active()->lang('nav_status'),
        'link'     => LinkGenerator::client('contact'),
        'extra'    => [],
        'children' => [],
    ];
});
```

## Tuzaklar

> **Düğümün adresi boş olabilir**
> 
> Yalnız açılır menü açan bir üst öğe ya da bir altbilgi kolon başlığı hiçbir adres taşımaz. Özniteliği koşulsuz basmak boş bir adres üretir; tarayıcı onu mevcut sayfaya çözer ve ekran okuyucu hiçbir yere gitmeyen bir bağlantı olarak okur.

> **Yazılı yol, ikinci dilde kırık yoldur**
> 
> Rota yolları çevrilir ve operatör onları yeniden adlandırabilir. Platform sayfalarını rota anahtarıyla, içeriği sayfa tanımlayıcısıyla adresleyin; temanın yazabileceği tek yol, slug'ı tanımı gereği adres olan kendi dosya tabanlı sayfalarıdır.

> **Menü tablolarını temadan okumayın**
> 
> Ağaçlar kurulmuş, çözülmüş, aktif satırlara süzülmüş ve dil başına önbelleklenmiş olarak gelir. Şablondaki bir sorgu ödenmiş işi tekrarlar ve diğer bütün dinleyicilerin dayandığı kancayı atlar.

> **Çekmece her zaman kendi ağacı değildir**
> 
> Mobil menü kurulmamışsa çekmece üst menü ağacını alır. Düz liste varsayan bir çekmece, açılır menünün alt öğelerini üst seviye satır olarak gösterir; orada da alt öğeleri ele alın.

## İlgili Makaleler

- [Şablon Değişkenleri](https://dev.wisecp.com/tr/sablon-degiskenleri)
- [Tema Kancaları ve Çıktı Filtreleri](https://dev.wisecp.com/tr/tema-kancalari-ve-cikti-filtreleri)
- [Bağlantı ve Rota Kurma](https://dev.wisecp.com/tr/baglanti-ve-rota-kurma)
- [Tema Çevirisi](https://dev.wisecp.com/tr/tema-cevirisi)
- [Sayfa Ekranları](https://dev.wisecp.com/tr/sayfa-yuzeyleri)
