Tema Kancaları ve Çıktı Filtreleri
Tema, aldığı veriyi ve ürettiği markup'ı kendi dosyasından değiştirir. Hiçbir controller ya da çekirdek şablonu düzenlenmez.
Genel Bakış
Her tema bir hooks.php taşıyabilir. Dosya, ilk sayfa oluşmadan önce bir kez include edilir; temayla taşınır ve temayla silinir.
Veri dinleyicileri view'a ulaşanı değiştirir: bu temanın her sayfada ihtiyaç duyduğu bir değişken, bir menü ağacı, bitmiş HTML. Markup noktaları ters yönde çalışır: tema onları açar, modül de içine enjekte eder.
Yapı
Nerede Durur
İki Aile
| Aile | Tema şudur | Mekanizma | Dönüş |
|---|---|---|---|
| Veri (filtre) | dinleyici | kanca dosyasında Hook::add() | Dönüşle değişir ya da referansla değiştirilir |
| Markup (enjeksiyon) | yayıncı | yerleşim ve parçalarda {hook name='...'} | Dizeler birleştirilir, ham gösterilir |
Referans
Kanca API'si
// $priority: küçük olan önce çalışır; çakışma artırılarak çözülür, dinleyici asla düşürülmez.
// $properties: bir closure ya da ['class' => 'X', 'method' => 'y'] ya da ['class' => 'X', 'method::static' => 'y'].
public static function add($name, $priority, $properties = []): void;
// Değer kopyasıyla. Dinleyici başına bir giriş döner; markup noktası bunları birleştirir.
public static function run($name, ...$args): array;
// Referansla. HER argüman referansla geçer, bu yüzden her biri düz bir değişken olmalıdır.
public static function runRefs($name, &...$args): array;
Değişken Filtresi
Bir temanın her sayfaya değişken eklediği tek nokta. Her şablon için çalışır; bir kısmını hedefleyen dinleyici yolu sınar.
Çıktı Filtresi
Motor işini bitirdikten sonra, tarayıcıya ulaşmadan önceki bitmiş HTML. Her yükü tek tek değiştirecek yeniden yazım burada yapılır.
$view ile ayırt edin.
Markup Noktaları
Yerleşimde {hook name='ui:client.head.css'} yazılır. Kurulu temalar yüz elliden fazlasını açar; taşınması gerekenler aşağıdadır.
| Nokta | Yerleşimdeki konumu | Oraya ne ait | Dönüş |
|---|---|---|---|
ui:client.head.css | head sonu | Stil bağlantıları, stil blokları | Sadece <link> ya da <style> döndürün; görünür markup girmez |
ui:client.head.js | head sonu | Temanın betiğinin kullandığı kütüphane | Sadece <script> döndürün; satır içi ya da src'li |
ui:client.body.begin | body başı | Etiket yöneticisi çerçeveleri, üst bantlar | Herhangi bir HTML dizesi döndürün |
ui:client.body.end | body sonu | Ertelenmiş betikler, sohbet bileşenleri, diyaloglar | Herhangi bir HTML dizesi döndürün |
ui:client.nav.items | Üst menü sonu | Ek bir üst seviye öğe | <li> döndürün, çıplak <a> değil |
ui:client.header.actions | Üst bant aksiyon kümesi | Sepetin yanına bir ikon butonu | .btn.btn-soft.header-icon-btn taşıyan <a> ya da <button> döndürün |
ui:client.user_menu.items | Hesap açılır menüsü | Giriş yapılmış menüde bir satır | .dropdown-item taşıyan <a> döndürün |
ui:client.drawer.items | Mobil çekmece | Menü öğesinin mobil ikizi | .drawer-link taşıyan çıplak <a> döndürün; çevresinde <li> olmaz |
ui:client.content.top | Sayfa içeriği üstü | Site geneli bir duyuru şeridi | Herhangi bir HTML dizesi döndürün |
ui:client.footer.columns | Altbilgi kolonlarından sonra | Ek bir bağlantı kolonu | Tek grid kolonu <div> döndürün; kardeşlerle aynı yapı, <ul>/<li> sarmalayıcı yok |
ui:client.footer.bottom | Altbilgi alt şeridi | Bir rozet, bir sözleşme satırı | Herhangi bir HTML dizesi döndürün |
Diğer Kancalar
| Kanca | Ne zaman | Tema bununla ne yapar |
|---|---|---|
filter:client.theme | Tema adı çözülürken | Host, segment ya da önizleme için farklı tema |
filter:client.menu | Menü ağacı kurulduktan sonra | Panelin yönetmediği düğümü eklemek, çıkarmak, sıralamak |
filter:client.breadcrumb | İz kısaltılmadan önce | İlk kırıntıyı yeniden adlandırmak ya da köklemek |
filter:client.predefined_data | Müşteri veri paketinin sonu | Rota bilinirken bir paket değerini düzeltmek |
filter:client.routes | Rotalar eşleştirilmeden önce | Bu temanın yayımladığı sayfaya kısa adres |
filter:routing.match | Son yönlendirme yedeği | Gerçek bir rotanın sahiplenmediği slug'ı cevaplamak |
gate:client.page_access | Controller kurulmadan önce | Sayfayı kanonik hostuna göndermek ya da reddetmek |
filter:sitemap.links | Site haritası toplanırken | Sayfanın kanonik ilan ettiği adresi yayımlamak |
Örnek
Eksiksiz bir kanca dosyası: tek değişken dinleyicisi, bir çıktı filtresi, bir enjeksiyon.
/*
* Tüm tema için TEK değişken dinleyicisi: view katmanı yalnız SON dönen diziyi
* saklar, ikinci bir kayıt bunun yazdığı her şeyi düşürürdü.
*/
Hook::add("filter:template.variables", 1, function ($template, $data) {
// Şablonun kendi başına okuyamayacağı çekirdek ayarından türetilir.
$data["support_enabled"] = (int) (Config::get("options/ticket-system") ?? 0) === 1;
// Bu temanın 404 döndürdüğü rotalar, anahtarlı harita olarak: sandbox'ta in_array()
// yoktur, bu yüzden şablon {if !$route_off.affiliate} diye sorar.
$data["route_off"] = array_fill_keys(Theme::active()->meta()["disabled_routes"] ?? [], true);
// HER sayfada çalışır, bu yüzden sorgusu olan her şey önbellekten geçer. Anahtar
// para birimini VE dili taşır, çünkü çıktı ikisine birden bağlıdır; biri eksik
// kalırsa bir ziyaretçiye diğerinin kopyası servis edilir.
$data["footer_groups"] = Cache::remember('website',
'acme_footer_' . Money::getUCID() . '_' . Language::selected(), 3600,
fn (): array => Products::groups());
// Sayfaya özel iş ikinci bir kayıt değil, bir yol sınamasının arkasında durur.
if (str_ends_with(str_replace('\\', '/', (string) $template), '/page/pricing.php'))
$data["plans"] = AcmePricing::cards();
return $data; // başka bir şey döndürmek platformun topladığı her anahtarı düşürür
});
/*
* Bitmiş sayfa. Bağlantı üreten her yükü yeniden yazmaktan hem ucuz hem güvenli:
* tek yer, ve bir tanesini bile atlayamaz.
*/
Hook::add('filter:client.page.output', 1, function (&$output, $view, $engine) {
if (str_contains($view, '/')) return; // parçalar belge değildir
$output = str_replace('</body>', '<script src="/assets/acme-widget.js" defer></script></body>', $output);
});
/*
* Veri değil markup: yerleşimin noktaları bir dize alır ve olduğu gibi basar. Burada
* kaydedilir, böylece temanın ek stil dosyası için hiçbir yerleşim dosyası düzenlenmez.
*/
Hook::add("ui:client.head.css", 1, fn (): string =>
'<link rel="stylesheet" href="' . Theme::active()->assetUrl('css/extra.css') . '">');
<head>
{block name=head}{/block}
{hook name='ui:client.head.css'}
{hook name='ui:client.head.js'}
</head>
<body>
{hook name='ui:client.body.begin'}
{* Kanca dosyasının koyduğu bir değer, başka her değişken gibi okunur. *}
{if !$route_off.affiliate}<a href="{link route='affiliate'}">{lang key='nav_affiliate'}</a>{/if}
{block name=content}{/block}
{hook name='ui:client.body.end'}
</body>
Tuzaklar
Hata, ona sebep olan dosyada görünmez: kırılan sayfa, diğer dinleyicinin set ettiği değişkeni okur. Tek gövde tutun, anahtarları oraya ekleyin.
Literal, satır içi dizi, tip dönüşümü, null birleştirmeli okuma ya da fonksiyon dönüşü geçemez; PHP uyarı değil ölümcül hata verir. Bağlamı önce bir değişkene alın.
Dinleyicideki çıplak bir sorgu her sayfa görüntülemesinde çalışır. Veritabanı okumalarını önbelleğe alın; sonuç dile ve para birimine bağlıysa anahtarı ikisiyle kurun.
Dağıtıcı onu yakalar ve devam eder; ölen dinleyici hata bırakmaz, değiştirmesi gereken değer değişmeden gelir. Bir dinleyici hiçbir şey yapmıyorsa kaydından değil içindeki ölümcül hatadan şüphelenin.
Markup noktaları escape etmez; sorumluluk enjekte eden taraftadır. Noktanın döndürdüğü dizeye ziyaretçi girdisi eklemeyin.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.