14 KiB
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 Checkliste.
Voraussetzungen
- Laravel 11+ oder 12
- Livewire 4 mit Volt
- Flux UI (Free oder Pro)
spatie/laravel-translatable(wird vom Package mitgebracht)intervention/imagev3 (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
// composer.json
{
"repositories": [
{ "type": "path", "url": "package/flux-cms/core" }
]
}
1.2 Dependencies hinzufügen
composer require flux-cms/core:@dev
composer require intervention/image
1.3 Konfiguration publizieren
php artisan vendor:publish --tag=flux-cms-config
1.4 Migrations ausführen
php artisan migrate
Dies erstellt folgende Tabellen:
flux_cms_contents— Alle Seiteninhalte (Key-Value mit Übersetzungen)flux_cms_news_items— Nachrichteneinträgeflux_cms_industries— Branchen-Bandflux_cms_faqs— FAQ-Einträgeflux_cms_downloads— Downloads (PDFs, etc.)flux_cms_linkedin_posts— LinkedIn-Postsflux_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
use FluxCms\Core\Models\CmsMedia;
use FluxCms\Core\Services\CmsContentService;
if (! function_exists('cms')) {
function cms(string $key, array $replace = [], ?string $locale = null): mixed
{
return app(CmsContentService::class)->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
// composer.json → autoload
{
"autoload": {
"files": ["app/helpers.php"]
}
}
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 <flux:toast /> enthalten für die Benachrichtigungen.
3.2 Admin Views kopieren
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-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:
# 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:
namespace App\Livewire\Admin\Cms;
3.4 Blade-Views für Livewire-Komponenten
# 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
// 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
php artisan storage:link
4.2 Storage-Verzeichnisse
Die Verzeichnisse werden automatisch erstellt beim ersten Upload:
storage/app/public/cms/media/originals/— Original-Uploadsstorage/app/public/cms/media/conversions/— Generierte Bildgrößenstorage/app/public/cms/media/thumbnails/— Auto-Thumbnails
4.3 Bildprofile konfigurieren
In config/flux-cms.php die Conversion-Profile an dein Projekt anpassen:
'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:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: '*');
})
Und in AppServiceProvider::boot():
if (request()->header('X-Forwarded-Proto') === 'https' || app()->environment('production')) {
URL::forceScheme('https');
}
5. Inhalte importieren (Seeder)
5.1 Seeders kopieren & anpassen
cp package/flux-cms/core/database/seeders-reference/*.php database/seeders/
5.2 CmsContentSeeder anpassen
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
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
php artisan db:seed
6. Frontend umstellen
6.1 __() durch cms() ersetzen
- {{ __('welcome.hero.heading') }}
+ {{ cms('welcome.hero.heading') }}
6.2 Bilder über Medienbibliothek laden
- <img src="{{ asset('assets/images/keyvisual.webp') }}" />
+ <img src="{{ cms_media_url('welcome.hero.image', 'hero') }}" />
Oder direkt über Dateiname:
<img src="{{ media_url($item['image'], 'card') }}" />
6.3 Downloads über CmsDownload
@foreach (CmsDownload::published()->byCategory('case_study')->ordered()->get() as $dl)
<x-download-article-card :article="$dl->toFrontendArray()" :index="$loop->index" />
@endforeach
6.4 News über CmsNewsItem
@php
$items = CmsNewsItem::published()->ordered()->get()
->map(fn($i) => $i->toFrontendArray())->toArray();
@endphp
6.5 :highlight Pattern
{!! cms('welcome.solutions.heading', [
'highlight' => '<span class="text-gradient-premium">'
. cms('welcome.solutions.heading_highlight') . '</span>',
]) !!}
7. Tests einrichten
7.1 Test-Dateien kopieren
cp -r package/flux-cms/core/tests-reference/Feature/Cms tests/Feature/Cms
7.2 Tests ausführen
php artisan test --filter=Cms
8. Anpassungen für dein Projekt
Sprachen hinzufügen
config/flux-cms.php:
'locales' => [
'de' => 'Deutsch',
'en' => 'English',
'fr' => 'Français',
],
Neue Content-Typen
- Migration + Model mit
HasTranslations - Admin-View als Volt-Komponente
- Route registrieren, Sidebar-Link hinzufügen
toFrontendArray()Methode für Frontend-Integration- 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