Multi-Tenant Tema Sistemi - SEO, Dark Mode, Leonardo AI, Media Olusturma
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/ | +-- homepage.blade.php | +-- t-1001/ ← Muzibu +-- t-2/ ← Ixtif +-- t-3/ ← Panjur +-- homepage.blade.php (STANDALONE)
ONEMLI: Modul view'lari AYRI konumda! "Modul View Path'leri" bolumune bak.
SEO etiketleri, Google'in sitenizi anlamasini saglar. Title, description, Open Graph, Twitter Cards ve Schema.org otomatik olusturur.
<!-- head icine ekle -->
<x-seo-meta />
<!-- Otomatik uretir: -->
<title>Sayfa Basligi</title>
<meta name="description" content="...">
<meta property="og:title" content="...">
<script type="application/ld+json">{Schema.org}</script>
resources/views/components/seo-meta.blade.php ← Component app/View/Components/SeoMeta.php ← Class
<script>
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!
}
<button x-data="{ dark: ... }"
@click="dark = !dark; localStorage.setItem('darkMode', dark);
document.documentElement.classList.toggle('dark', dark)">
<i :class="dark ? 'fa-sun' : 'fa-moon'"></i>
</button>
Leonardo AI API ile otomatik gorsel uretimi. Service, Page, Blog gibi modeller icin hero gorseli olusturur ve Spatie Media Library'ye ekler.
// Kullanim - Otomatik queue'ya gonder generate_ai_cover($model, 'Baslik', 'type'); // Ornekler: generate_ai_cover($service, $service->title, 'service'); generate_ai_cover($page, $page->title, 'page'); generate_ai_cover($blog, $blog->title, 'blog'); // Dosya: Modules/MediaManagement/helpers.php
// LeonardoAIService direkt kullanim $leonardo = app(\App\Services\Media\LeonardoAIService::class); $imageData = $leonardo->generateFromPrompt($prompt, [ 'width' => 1472, 'height' => 832, 'style' => 'stock_photo', // cinematic, dynamic, hdr, vibrant... ]); if ($imageData && !empty($imageData['url'])) { $model->addMediaFromUrl($imageData['url']) ->usingFileName('hero.jpg') ->withCustomProperties([ 'ai_generated' => true, 'prompt' => $prompt, ]) ->toMediaCollection('hero'); } // Dosya: app/Services/Media/LeonardoAIService.php
// /tmp/generate-images.php <?php $tenant = \App\Models\Tenant::find(3); tenancy()->initialize($tenant); $leonardo = app(\App\Services\Media\LeonardoAIService::class); // Tutarli renk paleti icin ortak stil $colorStyle = ", professional photography, warm orange and cool gray color palette, modern industrial aesthetic, 4k quality"; $prompts = [ 1 => 'Technician repairing shutter mechanism' . $colorStyle, 2 => 'Modern motorized roller shutter' . $colorStyle, // ... ]; foreach ($prompts as $id => $prompt) { $service = \Modules\Service\App\Models\Service::find($id); if ($service->hasMedia('hero')) continue; // Skip if exists $imageData = $leonardo->generateFromPrompt($prompt, [ 'width' => 1472, 'height' => 832, 'style' => 'stock_photo' ]); if ($imageData) { $service->addMediaFromUrl($imageData['url']) ->toMediaCollection('hero'); } sleep(5); // Rate limit } // Calistir: php artisan tinker /tmp/generate-images.php
cinematic - Sinematikstock_photo - Stok Fotodynamic - Dinamikhdr - HDRvibrant - Canlimoody - Atmosferik# .env dosyasinda: LEONARDO_API_KEY=your-api-key-here # config/services.php: 'leonardo' => [ 'api_key' => env('LEONARDO_API_KEY'), ],
Her modul (Page, Service, Blog) kendi view dosyalarini kendi klasorunde tutar. Ana resources/views degil, Modules klasoru icinde!
Modules/Page/resources/views/themes/ +-- simple/homepage.blade.php ← Fallback +-- ixtif/homepage.blade.php +-- t-3/homepage.blade.php ← Panjur Modules/Service/resources/views/themes/ +-- simple/service/index.blade.php +-- simple/service/show.blade.php Modules/Blog/resources/views/themes/ +-- simple/blog/index.blade.php +-- simple/blog/show.blade.php
<x-seo-meta />fa-light ikonlarsetting('key')thumb($media, w, h)Tinker'da tenant context'i baslatirken dogru model kullan:
// YANLIS: Tenant::find(3); // YANLIS: \Stancl\Tenancy\Database\Models\Tenant::find(3); // DOGRU: $tenant = \App\Models\Tenant::find(3); tenancy()->initialize($tenant);
Service/Page modulu 404 donuyorsa module_tenants tablosunda atama eksik olabilir:
// Central DB'de calistir: INSERT INTO module_tenants (module_id, tenant_id, is_active, created_at, updated_at) VALUES (27, 3, true, NOW(), NOW()); // module_id: modules tablosundan Service = 27, Page = 12 // tenant_id: tenants tablosundan
Cok satirli string'lerde parse error olursa:
// PHP dosyasina yaz: /tmp/script.php // Tinker ile calistir: php artisan tinker /tmp/script.php