14 KiB
14 KiB
Flux CMS Installation Guide
This guide will walk you through installing and setting up Flux CMS in your Laravel application.
System Requirements
- PHP: 8.2 or higher
- Laravel: 11.0 or higher
- Livewire: 3.0 or higher
- Database: MySQL 8.0+ or PostgreSQL 13+
- Node.js: 18+ (for asset compilation)
Required Laravel Packages
Flux CMS requires these packages to be installed:
spatie/laravel-translatable: For multilingual contentspatie/laravel-medialibrary: For media managementspatie/laravel-tags: For tagging blog postslivewire/livewire: For reactive componentslivewire/flux: For UI components (recommended)
Step-by-Step Installation
1. Install Required Dependencies
# Install required packages
composer require spatie/laravel-translatable spatie/laravel-medialibrary spatie/laravel-tags
# Install Livewire if not already installed
composer require livewire/livewire
# Install Flux UI (recommended for admin interface)
composer require livewire/flux
2. Install Flux CMS Packages
# Install core package
composer require flux-cms/core
# Install components package (recommended)
composer require flux-cms/components
# Install starter components (optional)
composer require flux-cms/starter-components
3. Run Installation Command
# This will publish config, run migrations, and set up permissions
php artisan flux-cms:install
# Or with options
php artisan flux-cms:install --no-migrate --no-publish
The installation command will:
- ✅ Check system requirements
- 📦 Publish configuration files
- 🗃️ Run database migrations
- 🔗 Create storage link
- 📝 Create sample content (optional)
- 🔐 Set up permissions (optional)
4. Configure Your Application
Environment Variables
Add these to your .env file:
# Flux CMS Configuration
FLUX_CMS_DEFAULT_LOCALE=de
FLUX_CMS_CACHE_ENABLED=true
FLUX_CMS_ROUTES_ENABLED=true
# Media Configuration
FLUX_CMS_MEDIA_DISK=public
FLUX_CMS_MAX_FILE_SIZE=10240
# Multi-domain (if using)
FLUX_CMS_MULTI_DOMAIN=true
FLUX_CMS_AUTO_DETECT_DOMAIN=true
Update App Configuration
// config/app.php
'locale' => env('APP_LOCALE', 'de'),
'fallback_locale' => 'de',
// Add available locales
'available_locales' => ['de', 'en'],
5. Set Up Routes
Admin Routes
Add to your routes/web.php or create routes/admin.php:
// Admin routes (protected)
Route::middleware(['web', 'auth'])->prefix('admin')->name('admin.')->group(function () {
Route::prefix('cms')->name('cms.')->group(function () {
Route::get('/', [Admin\DashboardController::class, 'index'])->name('index');
Route::resource('/pages', Admin\PageController::class)->except(['show']);
Route::get('/blog', [Admin\BlogController::class, 'index'])->name('blog.index');
Route::get('/media', [Admin\MediaController::class, 'index'])->name('media.index');
Route::get('/navigation', [Admin\NavigationController::class, 'index'])->name('navigation.index');
});
});
Frontend Routes
Add to your routes/web.php (MUST be at the end):
// SEO routes
Route::get('/sitemap.xml', [PageController::class, 'sitemap'])->name('sitemap');
Route::get('/robots.txt', [PageController::class, 'robots'])->name('robots');
// Blog routes (if using blog)
Route::prefix('blog')->name('blog.')->group(function () {
Route::get('/', [PageController::class, 'blogIndex'])->name('index');
Route::get('/{slug}', [PageController::class, 'blogPost'])->name('show');
});
// CMS pages - MUST BE LAST!
Route::get('/{slug?}', [PageController::class, 'show'])
->where('slug', '.*')
->name('cms.page');
6. Create Controllers
Page Controller
<?php
namespace App\Http\Controllers;
use FluxCms\Core\Models\Page;
use Illuminate\Http\Request;
class PageController extends Controller
{
public function show(Request $request, string $slug = '/')
{
// Get domain key from existing domains config
$domainKey = $this->getCurrentDomainKey($request);
$locale = app()->getLocale();
// Find page
$page = Page::forDomain($domainKey)
->bySlug($slug, $locale)
->published()
->firstOrFail();
// Load components
$components = $page->components()->get();
return view('pages.show', compact('page', 'components'));
}
public function sitemap(Request $request)
{
$domainKey = $this->getCurrentDomainKey($request);
$pages = Page::forDomain($domainKey)->published()->get();
return response()->view('sitemap', compact('pages'))
->header('Content-Type', 'application/xml');
}
protected function getCurrentDomainKey(Request $request): string
{
$host = $request->getHost();
$domains = config('domains.domains', []);
foreach ($domains as $key => $config) {
if (isset($config['url']) && parse_url($config['url'], PHP_URL_HOST) === $host) {
return $key;
}
}
return config('flux-cms.domains.default_domain', 'default');
}
}
Admin Controller
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use FluxCms\Core\Models\Page;
class CmsController extends Controller
{
public function __construct()
{
$this->middleware('can:flux-cms.view');
}
public function index()
{
$stats = [
'pages' => Page::count(),
'published_pages' => Page::published()->count(),
'draft_pages' => Page::where('is_published', false)->count(),
];
return view('admin.cms.index', compact('stats'));
}
public function pages()
{
$pages = Page::with(['components'])
->orderBy('updated_at', 'desc')
->paginate(20);
return view('admin.cms.pages', compact('pages'));
}
public function editPage(Page $page)
{
$this->authorize('flux-cms.edit');
return view('admin.cms.edit-page', compact('page'));
}
}
7. Create Views
Frontend Page Template
{{-- resources/views/pages/show.blade.php --}}
@extends('layouts.app')
@section('title', $page->getSeoTitle())
@section('description', $page->getSeoDescription())
@push('meta')
<meta property="og:title" content="{{ $page->getTranslation('title') }}">
<meta property="og:description" content="{{ $page->getSeoDescription() }}">
<meta property="og:url" content="{{ request()->url() }}">
@if($page->getTranslation('og_image'))
<meta property="og:image" content="{{ $page->getTranslation('og_image') }}">
@endif
@endpush
@section('content')
<main class="cms-page">
@foreach($components as $component)
@if($component->canRender())
<div class="cms-component" data-component="{{ class_basename($component->component_class) }}">
@livewire($component->component_class, [
'content' => $component->getTranslations('content')
], key('component-' . $component->id))
</div>
@endif
@endforeach
</main>
@endsection
Admin Views
{{-- resources/views/admin/cms/edit-page.blade.php --}}
@extends('layouts.admin')
@section('title', 'Edit Page: ' . $page->getTranslation('title'))
@section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@livewire('flux-cms::page-editor', ['page' => $page])
</div>
@endsection
@push('scripts')
<script>
// Enable drag & drop sorting
Livewire.on('components-reordered', (orderedIds) => {
// Handle reordering feedback
console.log('Components reordered:', orderedIds);
});
// Preview functionality
Livewire.on('open-preview', (url) => {
window.open(url, '_blank');
});
</script>
@endpush
8. Set Up Permissions
If you're using Spatie Laravel Permission:
// database/seeders/CmsPermissionSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class CmsPermissionSeeder extends Seeder
{
public function run()
{
// Create permissions
$permissions = [
'flux-cms.view',
'flux-cms.edit',
'flux-cms.publish',
'flux-cms.delete',
'flux-cms.admin',
];
foreach ($permissions as $permission) {
Permission::firstOrCreate(['name' => $permission]);
}
// Create CMS role
$cmsRole = Role::firstOrCreate(['name' => 'flux-cms']);
$cmsRole->syncPermissions($permissions);
// Assign to users
// User::find(1)->assignRole('flux-cms');
}
}
Run the seeder:
php artisan db:seed --class=CmsPermissionSeeder
9. Configure Multi-Domain (Optional)
If you're using multi-domain setup, ensure your config/domains.php is configured:
// config/domains.php
return [
'domains' => [
'main' => [
'name' => 'Main Site',
'url' => env('APP_URL', 'https://example.com'),
'theme' => 'default',
],
'blog' => [
'name' => 'Blog Site',
'url' => 'https://blog.example.com',
'theme' => 'blog',
],
],
];
Update Flux CMS config:
// config/flux-cms.php
'domains' => [
'enabled' => true,
'config_source' => 'domains', // Use domains.php config
'auto_detect' => true,
],
10. Create Your First Component
Generate a new component:
php artisan make:livewire Components/WelcomeHero
Update the component:
<?php
namespace App\Livewire\Components;
use Livewire\Component;
use FluxCms\Core\FieldTypes\TextField;
use FluxCms\Core\FieldTypes\WysiwygField;
class WelcomeHero extends Component
{
public array $content = [];
public function mount(array $content = [])
{
$this->content = $content;
}
public static function getCmsName(): string
{
return 'Welcome Hero';
}
public static function getCmsCategory(): string
{
return 'Content';
}
public static function getCmsFields(): array
{
return [
TextField::make('headline', 'Headline')
->translatable()
->required(),
WysiwygField::make('description', 'Description')
->translatable(),
];
}
public function render()
{
return view('livewire.components.welcome-hero');
}
}
Create the view:
{{-- resources/views/livewire/components/welcome-hero.blade.php --}}
<section class="hero bg-gradient-to-r from-blue-500 to-purple-600 text-white py-20">
<div class="container mx-auto px-4 text-center">
@if($headline = $this->content['headline'][app()->getLocale()] ?? '')
<h1 class="text-5xl font-bold mb-6">{{ $headline }}</h1>
@endif
@if($description = $this->content['description'][app()->getLocale()] ?? '')
<div class="text-xl prose prose-lg prose-invert mx-auto">
{!! $description !!}
</div>
@endif
</div>
</section>
11. Create Your First Page
// database/seeders/CmsContentSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use FluxCms\Core\Models\Page;
class CmsContentSeeder extends Seeder
{
public function run()
{
$homepage = Page::create([
'domain_key' => 'main',
'title' => [
'de' => 'Startseite',
'en' => 'Homepage'
],
'slug' => [
'de' => '/',
'en' => '/'
],
'meta_description' => [
'de' => 'Willkommen auf unserer Website',
'en' => 'Welcome to our website'
],
'is_published' => true,
]);
// Add welcome hero component
$homepage->allComponents()->create([
'component_class' => \App\Livewire\Components\WelcomeHero::class,
'order' => 1,
'content' => [
'headline' => [
'de' => 'Willkommen bei Flux CMS',
'en' => 'Welcome to Flux CMS'
],
'description' => [
'de' => 'Das moderne Content Management System für Laravel.',
'en' => 'The modern Content Management System for Laravel.'
]
],
]);
}
}
Run the seeder:
php artisan db:seed --class=CmsContentSeeder
Verification
After installation, verify everything works:
- Visit admin interface:
/admin/cms - Edit a page: Click on your homepage
- Add components: Try adding components to your page
- Check frontend: Visit your homepage
- Test translations: Switch languages if configured
Troubleshooting
Common Issues
1. Component Registry Empty
# Clear cache and refresh
php artisan flux-cms:clear-cache
php artisan cache:clear
2. Permission Denied
# Check if user has CMS role
php artisan tinker
> User::find(1)->assignRole('flux-cms');
3. Media Files Not Loading
# Ensure storage link exists
php artisan storage:link
# Check disk configuration
php artisan tinker
> Storage::disk('public')->exists('test.txt');
4. Routes Not Working
- Ensure CMS routes are at the end of
routes/web.php - Check middleware and permissions
- Verify domain configuration if using multi-domain
Debug Mode
Enable debug mode in config:
// config/flux-cms.php
'development' => [
'debug_mode' => true,
'show_component_info' => true,
'log_queries' => true,
],
Getting Help
- 📖 Documentation: Check the full documentation
- 💬 Community: Join GitHub Discussions
- 🐛 Issues: Report bugs on GitHub
- 📧 Support: Contact support team
Next Steps
- Create custom components for your specific needs
- Set up navigation using the navigation manager
- Configure domains if using multi-domain
- Customize styling to match your brand
- Set up deployment with proper caching
You're now ready to start building amazing content with Flux CMS! 🚀