# Flux CMS — Schritt-für-Schritt Setup-Anleitung Diese Anleitung beschreibt die Integration von Flux CMS in ein neues Laravel-Projekt. > **Migrierst du ein bestehendes Projekt?** Dann nutze stattdessen die kompakte **[MIGRATION.md](MIGRATION.md)** Checkliste. ## Voraussetzungen - Laravel 11+ oder 12 - Livewire 4 mit Volt - Flux UI (Free oder Pro) - `spatie/laravel-translatable` (wird vom Package mitgebracht) - `intervention/image` v3 (für Bildoptimierung) - Tailwind CSS v4 - Heroicons (via `blade-ui-kit/blade-heroicons`) - Mehrsprachige `lang/`-Dateien (DE/EN oder andere) --- ## 1. Package installieren ### 1.1 Repository registrieren ```json // composer.json { "repositories": [ { "type": "path", "url": "package/flux-cms/core" } ] } ``` ### 1.2 Dependencies hinzufügen ```bash composer require flux-cms/core:@dev composer require intervention/image ``` ### 1.3 Konfiguration publizieren ```bash php artisan vendor:publish --tag=flux-cms-config ``` ### 1.4 Migrations ausführen ```bash php artisan migrate ``` Dies erstellt folgende Tabellen: - `flux_cms_contents` — Alle Seiteninhalte (Key-Value mit Übersetzungen) - `flux_cms_news_items` — Nachrichteneinträge - `flux_cms_industries` — Branchen-Band - `flux_cms_faqs` — FAQ-Einträge - `flux_cms_downloads` — Downloads (PDFs, etc.) - `flux_cms_linkedin_posts` — LinkedIn-Posts - `flux_cms_media` — Medienbibliothek (Bilder, PDFs) **Hinweis:** Je nach Projekt-Erweiterung können zusätzliche Migrations nötig sein (z.B. für erweiterte Downloads mit Highlights/Checkpoints). --- ## 2. Helper-Funktionen einrichten ### 2.1 Datei erstellen Erstelle `app/helpers.php`: ```php get($key, $replace, $locale); } } if (! function_exists('tcms')) { function tcms(string $key, array $replace = [], ?string $locale = null): string { $text = cms($key, $replace, $locale); return is_string($text) ? $text : (string) $text; } } if (! function_exists('cms_media_url')) { /** * Resolve a CmsContent key (type=image) to a full media URL. * Falls back to asset('assets/images/...') if not found in media library. */ function cms_media_url(string $key, string $profile = ''): string { $filename = cms($key); if (! $filename || ! is_string($filename) || $filename === $key) { $fallback = str_replace('.', '/', $key); return asset('assets/images/' . basename($fallback)); } return media_url($filename, $profile); } } if (! function_exists('media_url')) { /** * Resolve a CmsMedia filename to its full storage URL. * Uses in-memory cache to avoid repeated DB queries. */ function media_url(?string $filename, string $profile = ''): string { if (! $filename || $filename === '') { return ''; } static $resolved = []; $cacheKey = $filename . '|' . $profile; if (isset($resolved[$cacheKey])) { return $resolved[$cacheKey]; } $media = CmsMedia::where('filename', $filename)->first(); if (! $media) { $resolved[$cacheKey] = asset('assets/images/' . $filename); return $resolved[$cacheKey]; } if ($profile && $media->hasConversion($profile)) { $resolved[$cacheKey] = $media->getConversionUrl($profile); } else { $resolved[$cacheKey] = $media->getUrl(); } return $resolved[$cacheKey]; } } ``` ### 2.2 Autoload registrieren ```json // composer.json → autoload { "autoload": { "files": ["app/helpers.php"] } } ``` ```bash composer dump-autoload ``` --- ## 3. Admin-Oberfläche einrichten ### 3.1 Layout erstellen Kopiere `core/resources/views/admin-reference/layout-cms.blade.php` nach `resources/views/components/layouts/cms.blade.php`. Passe die Sidebar-Navigation an: - Branding/Logo - Navigationspunkte: Dashboard, Inhalte, Medienbibliothek, News, Industries, Downloads, Team, FAQs, LinkedIn - Benutzer-Menü **Wichtig:** Das Layout muss `` enthalten für die Benachrichtigungen. ### 3.2 Admin Views kopieren ```bash mkdir -p resources/views/livewire/admin/cms/ cp package/flux-cms/core/resources/views/admin-reference/cms/*.blade.php \ resources/views/livewire/admin/cms/ ``` | View | Datei | Beschreibung | |------|-------|-------------| | Dashboard | `dashboard-index.blade.php` | Übersicht mit Statistiken | | Inhalte | `content-index.blade.php` | Haupteditor (Text/HTML/Image/JSON) | | Medienbibliothek | `media-index.blade.php` | Zentrale Medienverwaltung (Grid+Liste) | | News | `news-index.blade.php` | CRUD mit MediaPicker für Bild + PDF | | Industries | `industries-index.blade.php` | CRUD mit Sortierung | | FAQs | `faqs-index.blade.php` | CRUD nach Kategorien | | LinkedIn | `linkedin-index.blade.php` | CRUD mit MediaPicker | | Downloads | `downloads-index.blade.php` | CRUD für Case Studies/Capabilities/Stories | | Team | `team-index.blade.php` | CRUD mit MediaPicker für Profilbilder | | Suchindex | `search-index.blade.php` | Seitensuche: Keywords, Kategorien, Vorschau | ### 3.3 Livewire-Komponenten einrichten Funktionale Volt-Komponenten können kein `WithFileUploads` verwenden. Daher gibt es class-based Livewire-Komponenten: ```bash # Multi-File Upload cp package/flux-cms/core/src/Helpers/MediaLibraryUploader.php \ app/Livewire/Admin/Cms/MediaLibraryUploader.php # Medienauswahl-Modal cp package/flux-cms/core/src/Helpers/MediaPicker.php \ app/Livewire/Admin/Cms/MediaPicker.php ``` Namespace in beiden Dateien anpassen: ```php namespace App\Livewire\Admin\Cms; ``` ### 3.4 Blade-Views für Livewire-Komponenten ```bash # MediaLibraryUploader View cp package/flux-cms/core/resources/views/admin-reference/cms/media-library-uploader.blade.php \ resources/views/livewire/admin/cms/media-library-uploader.blade.php # MediaPicker View cp package/flux-cms/core/resources/views/admin-reference/cms/media-picker.blade.php \ resources/views/livewire/admin/cms/media-picker.blade.php ``` ### 3.5 Routes registrieren ```php // routes/web.php use Livewire\Volt\Volt; Route::middleware(['auth'])->group(function () { Volt::route('admin/cms', 'admin.cms.dashboard-index')->name('cms.dashboard'); Volt::route('admin/cms/content', 'admin.cms.content-index')->name('cms.content.index'); Volt::route('admin/cms/media', 'admin.cms.media-index')->name('cms.media.index'); Volt::route('admin/cms/news', 'admin.cms.news-index')->name('cms.news.index'); Volt::route('admin/cms/industries', 'admin.cms.industries-index')->name('cms.industries.index'); Volt::route('admin/cms/faqs', 'admin.cms.faqs-index')->name('cms.faqs.index'); Volt::route('admin/cms/linkedin', 'admin.cms.linkedin-index')->name('cms.linkedin.index'); Volt::route('admin/cms/downloads', 'admin.cms.downloads-index')->name('cms.downloads.index'); Volt::route('admin/cms/team', 'admin.cms.team-index')->name('cms.team.index'); Volt::route('admin/cms/search-index', 'admin.cms.search-index')->name('cms.search-index'); }); ``` --- ## 4. Medienbibliothek einrichten ### 4.1 Storage-Link ```bash php artisan storage:link ``` ### 4.2 Storage-Verzeichnisse Die Verzeichnisse werden automatisch erstellt beim ersten Upload: - `storage/app/public/cms/media/originals/` — Original-Uploads - `storage/app/public/cms/media/conversions/` — Generierte Bildgrößen - `storage/app/public/cms/media/thumbnails/` — Auto-Thumbnails ### 4.3 Bildprofile konfigurieren In `config/flux-cms.php` die Conversion-Profile an dein Projekt anpassen: ```php 'media' => [ 'max_upload_size' => 20480, // KB 'allowed_types' => ['jpg', 'jpeg', 'png', 'webp', 'gif', 'svg', 'pdf', 'doc', 'docx'], 'storage_disk' => 'public', 'profiles' => [ 'hero' => ['width' => 1920, 'height' => 800, 'format' => 'webp', 'quality' => 85], 'card' => ['width' => 768, 'height' => 512, 'format' => 'webp', 'quality' => 80], 'thumbnail' => ['width' => 400, 'height' => 300, 'format' => 'webp', 'quality' => 75], 'avatar' => ['width' => 400, 'height' => 400, 'format' => 'webp', 'quality' => 80], 'news' => ['width' => 1200, 'height' => 630, 'format' => 'webp', 'quality' => 80], 'thumb' => ['width' => 200, 'height' => 200, 'format' => 'webp', 'quality' => 70], ], ], ``` ### 4.4 HTTPS / Proxy Falls hinter einem Reverse Proxy, in `bootstrap/app.php`: ```php ->withMiddleware(function (Middleware $middleware) { $middleware->trustProxies(at: '*'); }) ``` Und in `AppServiceProvider::boot()`: ```php if (request()->header('X-Forwarded-Proto') === 'https' || app()->environment('production')) { URL::forceScheme('https'); } ``` --- ## 5. Inhalte importieren (Seeder) ### 5.1 Seeders kopieren & anpassen ```bash cp package/flux-cms/core/database/seeders-reference/*.php database/seeders/ ``` ### 5.2 CmsContentSeeder anpassen ```php protected array $skipFiles = [ 'faqs', 'sections', 'validation', 'auth', 'passwords', 'pagination', ]; protected array $skipKeys = [ 'components' => ['news_band', 'industries_band'], ]; ``` ### 5.3 CmsMediaSeeder erstellen Erstelle einen Seeder, der alle hochgeladenen Medien und die `CmsContent`-Einträge vom Typ `image` wiederherstellt. Dieser wird nach dem `CmsContentSeeder` ausgeführt, um Image-Keys zu erzeugen (z.B. `welcome.hero.image` → Dateiname). ### 5.4 CmsDownloadSeeder erstellen (optional) Falls du Downloads (Case Studies, Capabilities, Success Stories) verwendest, erstelle einen Seeder mit den vollständigen Inline-Daten. ### 5.5 DatabaseSeeder registrieren ```php public function run(): void { $this->call([ CmsContentSeeder::class, CmsMediaSeeder::class, CmsNewsItemSeeder::class, CmsIndustrySeeder::class, CmsFaqSeeder::class, CmsLinkedinPostSeeder::class, CmsDownloadSeeder::class, ]); } ``` ### 5.6 Seeding ausführen ```bash php artisan db:seed ``` --- ## 6. Frontend umstellen ### 6.1 `__()` durch `cms()` ersetzen ```diff - {{ __('welcome.hero.heading') }} + {{ cms('welcome.hero.heading') }} ``` ### 6.2 Bilder über Medienbibliothek laden ```diff - + ``` Oder direkt über Dateiname: ```blade ``` ### 6.3 Downloads über CmsDownload ```blade @foreach (CmsDownload::published()->byCategory('case_study')->ordered()->get() as $dl) @endforeach ``` ### 6.4 News über CmsNewsItem ```blade @php $items = CmsNewsItem::published()->ordered()->get() ->map(fn($i) => $i->toFrontendArray())->toArray(); @endphp ``` ### 6.5 :highlight Pattern ```blade {!! cms('welcome.solutions.heading', [ 'highlight' => '' . cms('welcome.solutions.heading_highlight') . '', ]) !!} ``` --- ## 7. Tests einrichten ### 7.1 Test-Dateien kopieren ```bash cp -r package/flux-cms/core/tests-reference/Feature/Cms tests/Feature/Cms ``` ### 7.2 Tests ausführen ```bash php artisan test --filter=Cms ``` --- ## 8. Anpassungen für dein Projekt ### Sprachen hinzufügen `config/flux-cms.php`: ```php 'locales' => [ 'de' => 'Deutsch', 'en' => 'English', 'fr' => 'Français', ], ``` ### Neue Content-Typen 1. Migration + Model mit `HasTranslations` 2. Admin-View als Volt-Komponente 3. Route registrieren, Sidebar-Link hinzufügen 4. `toFrontendArray()` Methode für Frontend-Integration 5. Seeder erstellen ### Editor-Toolbar - **Standard** (`bold italic`): Normale Texte - **Voll** (`heading | bold italic underline strike | bullet ordered blockquote | link`): Impressum, Datenschutz, News-Body ### Icon-Auswahl (Performance) Die Icon-Auswahl nutzt Blade Heroicons. Nur der Name wird im Dropdown angezeigt, das SVG nur als Vorschau neben dem Select-Feld — damit werden nicht 2800+ SVGs gerendert. --- ## Verzeichnisstruktur nach Installation ``` dein-projekt/ ├── app/ │ ├── helpers.php # cms(), tcms(), cms_media_url(), media_url() │ └── Livewire/Admin/Cms/ │ ├── MediaLibraryUploader.php # Multi-File Upload │ └── MediaPicker.php # Medienauswahl-Modal ├── config/ │ └── flux-cms.php # CMS + Media Konfiguration ├── database/ │ ├── migrations/ │ │ └── *_create_flux_cms_*.php # Automatisch vom Package │ └── seeders/ │ ├── CmsContentSeeder.php # Lang → DB │ ├── CmsMediaSeeder.php # Medien + Image-Content │ ├── CmsDownloadSeeder.php # Case Studies etc. │ ├── CmsNewsItemSeeder.php │ ├── CmsIndustrySeeder.php │ ├── CmsFaqSeeder.php │ └── CmsLinkedinPostSeeder.php ├── package/flux-cms/core/ # Das Package ├── resources/views/ │ ├── components/layouts/ │ │ └── cms.blade.php # Admin-Layout │ └── livewire/admin/cms/ │ ├── content-index.blade.php # Content-Editor │ ├── media-index.blade.php # Medienbibliothek │ ├── media-library-uploader.blade.php │ ├── media-picker.blade.php │ ├── news-index.blade.php │ ├── downloads-index.blade.php │ ├── team-index.blade.php │ ├── linkedin-index.blade.php │ ├── industries-index.blade.php │ ├── faqs-index.blade.php │ ├── search-index.blade.php # Suchindex-Verwaltung │ └── dashboard.blade.php # CMS-Dashboard └── routes/web.php # CMS-Routes ```