First commit
This commit is contained in:
commit
7cf3558ba7
12933 changed files with 1180047 additions and 0 deletions
597
packages/flux-cms/INSTALLATION.md
Normal file
597
packages/flux-cms/INSTALLATION.md
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
# 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 content
|
||||
- `spatie/laravel-medialibrary`: For media management
|
||||
- `spatie/laravel-tags`: For tagging blog posts
|
||||
- `livewire/livewire`: For reactive components
|
||||
- `livewire/flux`: For UI components (recommended)
|
||||
|
||||
## Step-by-Step Installation
|
||||
|
||||
### 1. Install Required Dependencies
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```env
|
||||
# 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
|
||||
|
||||
```php
|
||||
// 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`:
|
||||
|
||||
```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):
|
||||
|
||||
```php
|
||||
// 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
|
||||
<?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
|
||||
<?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
|
||||
|
||||
```blade
|
||||
{{-- 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
|
||||
|
||||
```blade
|
||||
{{-- 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:
|
||||
|
||||
```php
|
||||
// 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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```php
|
||||
// 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:
|
||||
|
||||
```php
|
||||
// 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:
|
||||
|
||||
```bash
|
||||
php artisan make:livewire Components/WelcomeHero
|
||||
```
|
||||
|
||||
Update the component:
|
||||
|
||||
```php
|
||||
<?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:
|
||||
|
||||
```blade
|
||||
{{-- 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
|
||||
|
||||
```php
|
||||
// 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:
|
||||
|
||||
```bash
|
||||
php artisan db:seed --class=CmsContentSeeder
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
After installation, verify everything works:
|
||||
|
||||
1. **Visit admin interface**: `/admin/cms`
|
||||
2. **Edit a page**: Click on your homepage
|
||||
3. **Add components**: Try adding components to your page
|
||||
4. **Check frontend**: Visit your homepage
|
||||
5. **Test translations**: Switch languages if configured
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Component Registry Empty
|
||||
|
||||
```bash
|
||||
# Clear cache and refresh
|
||||
php artisan flux-cms:clear-cache
|
||||
php artisan cache:clear
|
||||
```
|
||||
|
||||
#### 2. Permission Denied
|
||||
|
||||
```bash
|
||||
# Check if user has CMS role
|
||||
php artisan tinker
|
||||
> User::find(1)->assignRole('flux-cms');
|
||||
```
|
||||
|
||||
#### 3. Media Files Not Loading
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
1. **Create custom components** for your specific needs
|
||||
2. **Set up navigation** using the navigation manager
|
||||
3. **Configure domains** if using multi-domain
|
||||
4. **Customize styling** to match your brand
|
||||
5. **Set up deployment** with proper caching
|
||||
|
||||
You're now ready to start building amazing content with Flux CMS! 🚀
|
||||
Loading…
Add table
Add a link
Reference in a new issue