Multi-Tenant Tema Sistemi - SEO, Dark Mode, Leonardo AI, Modul Path'ler
t-{id} = Tenant temasi. Sadece ozel dosyalar burada.
simple = Fallback (mevcut, zaten var). t-{id}'de yoksa buradan alir.
Ornek: t-3/homepage.blade.php var → onu kullan, t-3/blog/show.blade.php yok → simple'dan al
resources/views/themes/ | +-- simple/ ← FALLBACK (mevcut, dokunma) | +-- layouts/ | | +-- app.blade.php | | +-- header.blade.php | | +-- footer.blade.php | +-- homepage.blade.php | +-- ... | +-- t-1001/ ← Muzibu override | +-- homepage.blade.php | +-- config.json | +-- t-2/ ← Ixtif override | +-- homepage.blade.php | +-- config.json | +-- t-3/ ← Panjur Tenant +-- homepage.blade.php ← Ozel anasayfa (STANDALONE) +-- config.json ← Renkler +-- (blog/, page/ yok → simple'dan gelir)
ONEMLI: Modul view'lari AYRI konumda! Asagidaki "Modul View Path'leri" bolumune bak.
SEO etiketleri, Google'in sitenizi anlamasini saglar. Title, description, Open Graph (sosyal medya paylasimlari), Twitter Cards ve Schema.org (zengin sonuclar) hepsini otomatik olusturur.
<!-- head icine ekle -->
<x-seo-meta />
<!-- Otomatik olusturulanlar: -->
<title>Sayfa Basligi</title>
<meta name="description" content="...">
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">
<link rel="canonical" href="...">
<meta property="og:title" content="...">
<meta property="og:description" content="...">
<meta property="og:image" content="...">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">{Schema.org JSON-LD}</script>
resources/views/components/seo-meta.blade.php ← Component app/View/Components/SeoMeta.php ← Class
Temel:
title - Sayfa basligidescription - Aciklamarobots - Index/noindexcanonical_url - Kanonik URLauthor - Yazar (E-E-A-T)Sosyal Medya:
og_title - Facebook basligiog_image - Paylasilacak gorseltwitter_card - Twitter kartitwitter_image - Twitter gorseliKullanici tercihini hatirlar. Sistem tercihine gore otomatik baslar, sonra kullanici degistirebilir. Sayfa yenilenince FOUC (yanip sonme) olmaz.
<script>
// Dark mode FOUC prevention - CRITICAL: head icinde olmali!
if (localStorage.getItem('darkMode') === 'true' ||
(!localStorage.getItem('darkMode') &&
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
</script>
tailwind.config = {
darkMode: 'class', // class bazli - 'media' degil!
theme: {
extend: { ... }
}
}
<button
x-data="{
dark: localStorage.getItem('darkMode') === 'true' ||
(!localStorage.getItem('darkMode') &&
document.documentElement.classList.contains('dark'))
}"
@click="
dark = !dark;
localStorage.setItem('darkMode', dark);
document.documentElement.classList.toggle('dark', dark)
"
class="..."
>
<i :class="dark ? 'fa-sun' : 'fa-moon'" class="fas"></i>
</button>
<!-- Tailwind dark: prefix kullan -->
<div class="bg-white dark:bg-slate-900 text-gray-900 dark:text-white">
<p class="text-gray-600 dark:text-gray-300">Icerik</p>
</div>
<!-- Gradient ornegi -->
<section class="bg-gradient-to-br from-slate-50 to-slate-100
dark:from-slate-900 dark:to-slate-800">
...
</section>
Leonardo AI ile gorsel uretip, Spatie Media Library'ye ekleyip, sayfalarda kullanabilirsin. Hero, hizmetler, sayfalar icin ozel gorseller olustur.
Prompt Ornekleri:
# Hero Background Professional shutter repair service, Turkish style building facade, orange aluminum shutters being installed, technician working, modern urban setting, Istanbul cityscape background, photorealistic, high quality, 16:9 aspect ratio # Service Card Motorized roller shutter system, remote control operation, modern smart home integration, clean product photography, white background, professional lighting, 4:3 aspect ratio # About Page Professional Turkish craftsman installing window shutters, 30 years experience, trustworthy appearance, workshop background with tools, warm lighting
# Leonardo'dan indirdikten sonra: scp gorsel.jpg sunucu:/tmp/ # Storage'a tasi: sudo cp /tmp/gorsel.jpg /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/ sudo chown tuufi.com_:psaserv /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg sudo chmod 644 /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg
$tenant = \App\Models\Tenant::find(3); tenancy()->initialize($tenant); // Ornek: Page'e gorsel ekle $page = \Modules\Page\App\Models\Page::find(2); $page->addMedia('/var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg') ->preservingOriginal() ->toMediaCollection('cover'); // Service'e gorsel ekle $service = \Modules\Service\App\Models\Service::find(1); $service->addMedia('/tmp/panjur-tamiri.jpg') ->preservingOriginal() ->toMediaCollection('cover');
{{-- Direkt media URL --}} <img src="{{ $service->getFirstMediaUrl('cover') }}" alt="..."> {{-- Thumbmaker ile (optimize) --}} <img src="{{ thumb($service->getFirstMedia('cover'), 800, 600) }}" alt="..."> {{-- WebP format ile --}} <img src="{{ thumb($service->getFirstMedia('cover'), 800, 600, ['format' => 'webp']) }}" alt="...">
Her modul (Page, Service, Blog) kendi view dosyalarini kendi klasorunde tutar. Ana resources/views degil, Modules klasoru icinde!
Modules/Page/resources/views/themes/ | +-- simple/ ← Fallback | +-- homepage.blade.php | +-- page/ | +-- show.blade.php | +-- ixtif/ ← Ixtif ozel | +-- homepage.blade.php | +-- muzibu/ ← Muzibu ozel | +-- homepage.blade.php | +-- t-3/ ← Panjur ozel +-- homepage.blade.php (STANDALONE - extends yok)
Modules/Service/resources/views/themes/ | +-- simple/ ← Fallback | +-- service/ | +-- index.blade.php ← Hizmet listesi | +-- show.blade.php ← Hizmet detay | +-- t-3/ ← Panjur icin ozel istersen +-- service/ +-- index.blade.php +-- show.blade.php
Modules/Blog/resources/views/themes/
|
+-- simple/ ← Fallback
+-- blog/
+-- index.blade.php
+-- show.blade.php
t-3 Tenant icin arama sirasi: 1. Modules/Page/resources/views/themes/t-3/homepage.blade.php ✓ BULUNDU 2. Modules/Page/resources/views/themes/simple/homepage.blade.php (fallback) Service detay icin: 1. Modules/Service/resources/views/themes/t-3/service/show.blade.php ✗ YOK 2. Modules/Service/resources/views/themes/simple/service/show.blade.php ✓ KULLANILIR
<x-seo-meta />fa-light ikonlarassets/libs/fontawesome-pro@7.1.0/darkMode: 'class'data-aos="fade-up"data-aos-delay="100"setting('key') - Tenant ayarlarithumb($media, w, h) - Gorsel optimizecdn($url) - CDN URLHata: priority_score, seo_score kolonlari yok
Cozum:
ALTER TABLE tenant_xxx.seo_settings ADD COLUMN priority_score INT DEFAULT 5, ADD COLUMN seo_score INT DEFAULT 0;
Hata: Stancl\Tenancy vs App\Models\Tenant
Cozum:
// YANLIS: $tenant = Tenant::find(3); // DOGRU: $tenant = \App\Models\Tenant::find(3); tenancy()->initialize($tenant);
Hata: Cok satirli string'lerde parse error
Cozum:
# PHP dosyasina yaz, tinker ile calistir:
php artisan tinker /tmp/script.php
Durum: /sayfa/hakkimizda ve /hizmetler/xxx 404 donuyor
Olasi Nedenler:
Kontrol Et:
php artisan route:list --path=sayfa php artisan route:cache && php artisan route:clear
Durum: t-3/homepage.blade.php standalone (tam HTML), ixtif extends kullaniyor
Avantaj: Bagimsizlik, tam kontrol
Dezavantaj: Header/footer degisirse manuel guncelleme gerekir