diff --git a/Modules/Banners/Config/config.php b/Modules/Banners/Config/config.php new file mode 100644 index 0000000..b2a20d0 --- /dev/null +++ b/Modules/Banners/Config/config.php @@ -0,0 +1,3 @@ + 'Banners']; diff --git a/Modules/Banners/Database/Migrations/2026_07_24_000600_create_banners_table.php b/Modules/Banners/Database/Migrations/2026_07_24_000600_create_banners_table.php new file mode 100644 index 0000000..672055a --- /dev/null +++ b/Modules/Banners/Database/Migrations/2026_07_24_000600_create_banners_table.php @@ -0,0 +1,16 @@ +id(); + $table->string('title'); + $table->text('content')->nullable(); + $table->string('link_url')->nullable(); + $table->string('position')->default('default'); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('banners'); } +}; diff --git a/Modules/Banners/Http/Controllers/BannerController.php b/Modules/Banners/Http/Controllers/BannerController.php new file mode 100644 index 0000000..409dcbc --- /dev/null +++ b/Modules/Banners/Http/Controllers/BannerController.php @@ -0,0 +1,27 @@ + Banner::query()->latest()->paginate(20)]); } + public function create(): View { return view('banners::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'content' => ['nullable', 'string'], + 'link_url' => ['nullable', 'string'], + 'position' => ['required', 'string', 'max:255'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); Banner::create($data); return redirect()->route('banners.index')->with('status', 'Banner created.'); } + public function edit(Banner $banner): View { return view('banners::admin.form', ['record' => $banner]); } + public function update(Request $request, Banner $banner): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'content' => ['nullable', 'string'], + 'link_url' => ['nullable', 'string'], + 'position' => ['required', 'string', 'max:255'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); $banner->update($data); return redirect()->route('banners.index')->with('status', 'Banner updated.'); } + public function destroy(Banner $banner): RedirectResponse { $banner->delete(); return back()->with('status', 'Banner deleted.'); } +} diff --git a/Modules/Banners/Models/Banner.php b/Modules/Banners/Models/Banner.php new file mode 100644 index 0000000..4257112 --- /dev/null +++ b/Modules/Banners/Models/Banner.php @@ -0,0 +1,19 @@ + 'boolean' + ]; } + +} diff --git a/Modules/Banners/Providers/BannersServiceProvider.php b/Modules/Banners/Providers/BannersServiceProvider.php new file mode 100644 index 0000000..eda98f7 --- /dev/null +++ b/Modules/Banners/Providers/BannersServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Banners', 'Config/config.php'), 'banners'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Banners', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Banners', 'Resources/views'), 'banners'); + } +} diff --git a/Modules/Banners/Providers/RouteServiceProvider.php b/Modules/Banners/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..c948511 --- /dev/null +++ b/Modules/Banners/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Banners', 'Routes/web.php'))); + } +} diff --git a/Modules/Banners/Resources/views/admin/form.blade.php b/Modules/Banners/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..b78be52 --- /dev/null +++ b/Modules/Banners/Resources/views/admin/form.blade.php @@ -0,0 +1,9 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Banner

@csrf @isset($record) @method('PUT') @endisset +
@error('title')

{{ $message }}

@enderror
+
@error('content')

{{ $message }}

@enderror
+
@error('link_url')

{{ $message }}

@enderror
+
@error('position')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Banners/Resources/views/admin/index.blade.php b/Modules/Banners/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..4ac0c2d --- /dev/null +++ b/Modules/Banners/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Banners

Manage banners content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
TitleContentLink UrlActions
{{ is_array($record->title) ? json_encode($record->title) : Str::limit((string) $record->title, 70) }}{{ is_array($record->content) ? json_encode($record->content) : Str::limit((string) $record->content, 70) }}{{ is_array($record->link_url) ? json_encode($record->link_url) : Str::limit((string) $record->link_url, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Banners/Routes/web.php b/Modules/Banners/Routes/web.php new file mode 100644 index 0000000..ff2fe14 --- /dev/null +++ b/Modules/Banners/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/banners')->name('administration.banners.')->group(function (): void { + Route::resource('/', BannerController::class)->parameters(['' => 'banner'])->except('show'); +}); diff --git a/Modules/Banners/Support/ModuleInfo.php b/Modules/Banners/Support/ModuleInfo.php new file mode 100644 index 0000000..45c47a6 --- /dev/null +++ b/Modules/Banners/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Banners/module.json b/Modules/Banners/module.json new file mode 100644 index 0000000..238aec6 --- /dev/null +++ b/Modules/Banners/module.json @@ -0,0 +1,20 @@ +{ + "name": "Banners", + "alias": "banners", + "version": "1.0.0", + "description": "Banners CMS module.", + "keywords": [ + "cms", + "banners" + ], + "priority": 26, + "providers": [ + "Modules\\Banners\\Providers\\BannersServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Documents/Config/config.php b/Modules/Documents/Config/config.php new file mode 100644 index 0000000..f780704 --- /dev/null +++ b/Modules/Documents/Config/config.php @@ -0,0 +1,3 @@ + 'Documents']; diff --git a/Modules/Documents/Database/Migrations/2026_07_24_000500_create_documents_table.php b/Modules/Documents/Database/Migrations/2026_07_24_000500_create_documents_table.php new file mode 100644 index 0000000..60bc66e --- /dev/null +++ b/Modules/Documents/Database/Migrations/2026_07_24_000500_create_documents_table.php @@ -0,0 +1,15 @@ +id(); + $table->string('title'); + $table->text('description')->nullable(); + $table->string('file_path')->nullable(); + $table->boolean('is_public')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('documents'); } +}; diff --git a/Modules/Documents/Http/Controllers/DocumentController.php b/Modules/Documents/Http/Controllers/DocumentController.php new file mode 100644 index 0000000..e14d691 --- /dev/null +++ b/Modules/Documents/Http/Controllers/DocumentController.php @@ -0,0 +1,25 @@ + Document::query()->latest()->paginate(20)]); } + public function create(): View { return view('documents::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'file_path' => ['nullable', 'string'], + 'is_public' => ['sometimes', 'boolean']]); $data['is_public'] = $request->boolean('is_public'); Document::create($data); return redirect()->route('documents.index')->with('status', 'Document created.'); } + public function edit(Document $document): View { return view('documents::admin.form', ['record' => $document]); } + public function update(Request $request, Document $document): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'file_path' => ['nullable', 'string'], + 'is_public' => ['sometimes', 'boolean']]); $data['is_public'] = $request->boolean('is_public'); $document->update($data); return redirect()->route('documents.index')->with('status', 'Document updated.'); } + public function destroy(Document $document): RedirectResponse { $document->delete(); return back()->with('status', 'Document deleted.'); } +} diff --git a/Modules/Documents/Models/Document.php b/Modules/Documents/Models/Document.php new file mode 100644 index 0000000..8009f45 --- /dev/null +++ b/Modules/Documents/Models/Document.php @@ -0,0 +1,19 @@ + 'boolean' + ]; } + +} diff --git a/Modules/Documents/Providers/DocumentsServiceProvider.php b/Modules/Documents/Providers/DocumentsServiceProvider.php new file mode 100644 index 0000000..5e19ae9 --- /dev/null +++ b/Modules/Documents/Providers/DocumentsServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Documents', 'Config/config.php'), 'documents'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Documents', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Documents', 'Resources/views'), 'documents'); + } +} diff --git a/Modules/Documents/Providers/RouteServiceProvider.php b/Modules/Documents/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..7c25a1d --- /dev/null +++ b/Modules/Documents/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Documents', 'Routes/web.php'))); + } +} diff --git a/Modules/Documents/Resources/views/admin/form.blade.php b/Modules/Documents/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..d94c9d1 --- /dev/null +++ b/Modules/Documents/Resources/views/admin/form.blade.php @@ -0,0 +1,8 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Document

@csrf @isset($record) @method('PUT') @endisset +
@error('title')

{{ $message }}

@enderror
+
@error('description')

{{ $message }}

@enderror
+
@error('file_path')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Documents/Resources/views/admin/index.blade.php b/Modules/Documents/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..f79986e --- /dev/null +++ b/Modules/Documents/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Documents

Manage documents content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
TitleDescriptionFile PathActions
{{ is_array($record->title) ? json_encode($record->title) : Str::limit((string) $record->title, 70) }}{{ is_array($record->description) ? json_encode($record->description) : Str::limit((string) $record->description, 70) }}{{ is_array($record->file_path) ? json_encode($record->file_path) : Str::limit((string) $record->file_path, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Documents/Routes/web.php b/Modules/Documents/Routes/web.php new file mode 100644 index 0000000..346e3b9 --- /dev/null +++ b/Modules/Documents/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/documents')->name('administration.documents.')->group(function (): void { + Route::resource('/', DocumentController::class)->parameters(['' => 'document'])->except('show'); +}); diff --git a/Modules/Documents/Support/ModuleInfo.php b/Modules/Documents/Support/ModuleInfo.php new file mode 100644 index 0000000..2643ae5 --- /dev/null +++ b/Modules/Documents/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Documents/module.json b/Modules/Documents/module.json new file mode 100644 index 0000000..318fef2 --- /dev/null +++ b/Modules/Documents/module.json @@ -0,0 +1,20 @@ +{ + "name": "Documents", + "alias": "documents", + "version": "1.0.0", + "description": "Documents CMS module.", + "keywords": [ + "cms", + "documents" + ], + "priority": 25, + "providers": [ + "Modules\\Documents\\Providers\\DocumentsServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Faq/Config/config.php b/Modules/Faq/Config/config.php new file mode 100644 index 0000000..47a7171 --- /dev/null +++ b/Modules/Faq/Config/config.php @@ -0,0 +1,3 @@ + 'Faq']; diff --git a/Modules/Faq/Database/Migrations/2026_07_24_000700_create_faqs_table.php b/Modules/Faq/Database/Migrations/2026_07_24_000700_create_faqs_table.php new file mode 100644 index 0000000..58335ba --- /dev/null +++ b/Modules/Faq/Database/Migrations/2026_07_24_000700_create_faqs_table.php @@ -0,0 +1,16 @@ +id(); + $table->string('question'); + $table->longText('answer'); + $table->string('category')->nullable(); + $table->unsignedInteger('sort_order')->default(0); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('faqs'); } +}; diff --git a/Modules/Faq/Http/Controllers/FaqController.php b/Modules/Faq/Http/Controllers/FaqController.php new file mode 100644 index 0000000..e58c082 --- /dev/null +++ b/Modules/Faq/Http/Controllers/FaqController.php @@ -0,0 +1,27 @@ + Faq::query()->latest()->paginate(20)]); } + public function create(): View { return view('faq::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['question' => ['required', 'string', 'max:255'], + 'answer' => ['required', 'string'], + 'category' => ['nullable', 'string'], + 'sort_order' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); Faq::create($data); return redirect()->route('faq.index')->with('status', 'Faq created.'); } + public function edit(Faq $faq): View { return view('faq::admin.form', ['record' => $faq]); } + public function update(Request $request, Faq $faq): RedirectResponse { $data = $request->validate(['question' => ['required', 'string', 'max:255'], + 'answer' => ['required', 'string'], + 'category' => ['nullable', 'string'], + 'sort_order' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); $faq->update($data); return redirect()->route('faq.index')->with('status', 'Faq updated.'); } + public function destroy(Faq $faq): RedirectResponse { $faq->delete(); return back()->with('status', 'Faq deleted.'); } +} diff --git a/Modules/Faq/Models/Faq.php b/Modules/Faq/Models/Faq.php new file mode 100644 index 0000000..b381686 --- /dev/null +++ b/Modules/Faq/Models/Faq.php @@ -0,0 +1,20 @@ + 'integer', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Faq/Providers/FaqServiceProvider.php b/Modules/Faq/Providers/FaqServiceProvider.php new file mode 100644 index 0000000..43f9071 --- /dev/null +++ b/Modules/Faq/Providers/FaqServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Faq', 'Config/config.php'), 'faq'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Faq', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Faq', 'Resources/views'), 'faq'); + } +} diff --git a/Modules/Faq/Providers/RouteServiceProvider.php b/Modules/Faq/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..8c5175d --- /dev/null +++ b/Modules/Faq/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Faq', 'Routes/web.php'))); + } +} diff --git a/Modules/Faq/Resources/views/admin/form.blade.php b/Modules/Faq/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..9998104 --- /dev/null +++ b/Modules/Faq/Resources/views/admin/form.blade.php @@ -0,0 +1,9 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Faq

@csrf @isset($record) @method('PUT') @endisset +
@error('question')

{{ $message }}

@enderror
+
@error('answer')

{{ $message }}

@enderror
+
@error('category')

{{ $message }}

@enderror
+
@error('sort_order')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Faq/Resources/views/admin/index.blade.php b/Modules/Faq/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..5bceb8c --- /dev/null +++ b/Modules/Faq/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Faq

Manage faq content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
QuestionAnswerCategoryActions
{{ is_array($record->question) ? json_encode($record->question) : Str::limit((string) $record->question, 70) }}{{ is_array($record->answer) ? json_encode($record->answer) : Str::limit((string) $record->answer, 70) }}{{ is_array($record->category) ? json_encode($record->category) : Str::limit((string) $record->category, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Faq/Routes/web.php b/Modules/Faq/Routes/web.php new file mode 100644 index 0000000..df41545 --- /dev/null +++ b/Modules/Faq/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/faq')->name('administration.faq.')->group(function (): void { + Route::resource('/', FaqController::class)->parameters(['' => 'faq'])->except('show'); +}); diff --git a/Modules/Faq/Support/ModuleInfo.php b/Modules/Faq/Support/ModuleInfo.php new file mode 100644 index 0000000..0b812e8 --- /dev/null +++ b/Modules/Faq/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Faq/module.json b/Modules/Faq/module.json new file mode 100644 index 0000000..1996222 --- /dev/null +++ b/Modules/Faq/module.json @@ -0,0 +1,20 @@ +{ + "name": "Faq", + "alias": "faq", + "version": "1.0.0", + "description": "Faq CMS module.", + "keywords": [ + "cms", + "faq" + ], + "priority": 27, + "providers": [ + "Modules\\Faq\\Providers\\FaqServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Forms/Config/config.php b/Modules/Forms/Config/config.php new file mode 100644 index 0000000..ba58e72 --- /dev/null +++ b/Modules/Forms/Config/config.php @@ -0,0 +1,3 @@ + 'Forms']; diff --git a/Modules/Forms/Database/Migrations/2026_07_24_000400_create_forms_table.php b/Modules/Forms/Database/Migrations/2026_07_24_000400_create_forms_table.php new file mode 100644 index 0000000..8a5a607 --- /dev/null +++ b/Modules/Forms/Database/Migrations/2026_07_24_000400_create_forms_table.php @@ -0,0 +1,16 @@ +id(); + $table->string('name'); + $table->string('slug'); + $table->text('description')->nullable(); + $table->json('schema')->nullable(); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('forms'); } +}; diff --git a/Modules/Forms/Http/Controllers/FormController.php b/Modules/Forms/Http/Controllers/FormController.php new file mode 100644 index 0000000..2ba15ed --- /dev/null +++ b/Modules/Forms/Http/Controllers/FormController.php @@ -0,0 +1,29 @@ + Form::query()->latest()->paginate(20)]); } + public function create(): View { return view('forms::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'slug' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'schema' => ['nullable', 'array'], + 'enabled' => ['sometimes', 'boolean']]); if ($request->filled('schema_json')) { $data['schema'] = json_decode($request->string('schema_json')->toString(), true, 512, JSON_THROW_ON_ERROR); } + $data['enabled'] = $request->boolean('enabled'); Form::create($data); return redirect()->route('forms.index')->with('status', 'Form created.'); } + public function edit(Form $form): View { return view('forms::admin.form', ['record' => $form]); } + public function update(Request $request, Form $form): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'slug' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'schema' => ['nullable', 'array'], + 'enabled' => ['sometimes', 'boolean']]); if ($request->filled('schema_json')) { $data['schema'] = json_decode($request->string('schema_json')->toString(), true, 512, JSON_THROW_ON_ERROR); } + $data['enabled'] = $request->boolean('enabled'); $form->update($data); return redirect()->route('forms.index')->with('status', 'Form updated.'); } + public function destroy(Form $form): RedirectResponse { $form->delete(); return back()->with('status', 'Form deleted.'); } +} diff --git a/Modules/Forms/Models/Form.php b/Modules/Forms/Models/Form.php new file mode 100644 index 0000000..2d8c1e4 --- /dev/null +++ b/Modules/Forms/Models/Form.php @@ -0,0 +1,20 @@ + 'array', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Forms/Providers/FormsServiceProvider.php b/Modules/Forms/Providers/FormsServiceProvider.php new file mode 100644 index 0000000..53ce6d1 --- /dev/null +++ b/Modules/Forms/Providers/FormsServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Forms', 'Config/config.php'), 'forms'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Forms', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Forms', 'Resources/views'), 'forms'); + } +} diff --git a/Modules/Forms/Providers/RouteServiceProvider.php b/Modules/Forms/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..1d81fce --- /dev/null +++ b/Modules/Forms/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Forms', 'Routes/web.php'))); + } +} diff --git a/Modules/Forms/Resources/views/admin/form.blade.php b/Modules/Forms/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..88a9260 --- /dev/null +++ b/Modules/Forms/Resources/views/admin/form.blade.php @@ -0,0 +1,9 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Form

@csrf @isset($record) @method('PUT') @endisset +
@error('name')

{{ $message }}

@enderror
+
@error('slug')

{{ $message }}

@enderror
+
@error('description')

{{ $message }}

@enderror
+
+ +
Cancel
+
diff --git a/Modules/Forms/Resources/views/admin/index.blade.php b/Modules/Forms/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..4548d67 --- /dev/null +++ b/Modules/Forms/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Forms

Manage forms content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
NameSlugDescriptionActions
{{ is_array($record->name) ? json_encode($record->name) : Str::limit((string) $record->name, 70) }}{{ is_array($record->slug) ? json_encode($record->slug) : Str::limit((string) $record->slug, 70) }}{{ is_array($record->description) ? json_encode($record->description) : Str::limit((string) $record->description, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Forms/Routes/web.php b/Modules/Forms/Routes/web.php new file mode 100644 index 0000000..f4fd6bb --- /dev/null +++ b/Modules/Forms/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/forms')->name('administration.forms.')->group(function (): void { + Route::resource('/', FormController::class)->parameters(['' => 'form'])->except('show'); +}); diff --git a/Modules/Forms/Support/ModuleInfo.php b/Modules/Forms/Support/ModuleInfo.php new file mode 100644 index 0000000..a6e2507 --- /dev/null +++ b/Modules/Forms/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Forms/module.json b/Modules/Forms/module.json new file mode 100644 index 0000000..b4450a2 --- /dev/null +++ b/Modules/Forms/module.json @@ -0,0 +1,20 @@ +{ + "name": "Forms", + "alias": "forms", + "version": "1.0.0", + "description": "Forms CMS module.", + "keywords": [ + "cms", + "forms" + ], + "priority": 24, + "providers": [ + "Modules\\Forms\\Providers\\FormsServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Menus/Config/config.php b/Modules/Menus/Config/config.php new file mode 100644 index 0000000..634ea78 --- /dev/null +++ b/Modules/Menus/Config/config.php @@ -0,0 +1,3 @@ + 'Menus']; diff --git a/Modules/Menus/Database/Migrations/2026_07_24_000200_create_menus_table.php b/Modules/Menus/Database/Migrations/2026_07_24_000200_create_menus_table.php new file mode 100644 index 0000000..e49ccd6 --- /dev/null +++ b/Modules/Menus/Database/Migrations/2026_07_24_000200_create_menus_table.php @@ -0,0 +1,15 @@ +id(); + $table->string('name'); + $table->string('location'); + $table->json('items')->nullable(); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('menus'); } +}; diff --git a/Modules/Menus/Http/Controllers/MenuController.php b/Modules/Menus/Http/Controllers/MenuController.php new file mode 100644 index 0000000..419dc64 --- /dev/null +++ b/Modules/Menus/Http/Controllers/MenuController.php @@ -0,0 +1,27 @@ + Menu::query()->latest()->paginate(20)]); } + public function create(): View { return view('menus::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'location' => ['required', 'string', 'max:255'], + 'items' => ['nullable', 'array'], + 'enabled' => ['sometimes', 'boolean']]); if ($request->filled('items_json')) { $data['items'] = json_decode($request->string('items_json')->toString(), true, 512, JSON_THROW_ON_ERROR); } + $data['enabled'] = $request->boolean('enabled'); Menu::create($data); return redirect()->route('menus.index')->with('status', 'Menu created.'); } + public function edit(Menu $menu): View { return view('menus::admin.form', ['record' => $menu]); } + public function update(Request $request, Menu $menu): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'location' => ['required', 'string', 'max:255'], + 'items' => ['nullable', 'array'], + 'enabled' => ['sometimes', 'boolean']]); if ($request->filled('items_json')) { $data['items'] = json_decode($request->string('items_json')->toString(), true, 512, JSON_THROW_ON_ERROR); } + $data['enabled'] = $request->boolean('enabled'); $menu->update($data); return redirect()->route('menus.index')->with('status', 'Menu updated.'); } + public function destroy(Menu $menu): RedirectResponse { $menu->delete(); return back()->with('status', 'Menu deleted.'); } +} diff --git a/Modules/Menus/Models/Menu.php b/Modules/Menus/Models/Menu.php new file mode 100644 index 0000000..6eb9153 --- /dev/null +++ b/Modules/Menus/Models/Menu.php @@ -0,0 +1,20 @@ + 'array', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Menus/Providers/MenusServiceProvider.php b/Modules/Menus/Providers/MenusServiceProvider.php new file mode 100644 index 0000000..9572a1a --- /dev/null +++ b/Modules/Menus/Providers/MenusServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Menus', 'Config/config.php'), 'menus'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Menus', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Menus', 'Resources/views'), 'menus'); + } +} diff --git a/Modules/Menus/Providers/RouteServiceProvider.php b/Modules/Menus/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..2e19213 --- /dev/null +++ b/Modules/Menus/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Menus', 'Routes/web.php'))); + } +} diff --git a/Modules/Menus/Resources/views/admin/form.blade.php b/Modules/Menus/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..8203074 --- /dev/null +++ b/Modules/Menus/Resources/views/admin/form.blade.php @@ -0,0 +1,8 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Menu

@csrf @isset($record) @method('PUT') @endisset +
@error('name')

{{ $message }}

@enderror
+
@error('location')

{{ $message }}

@enderror
+
+ +
Cancel
+
diff --git a/Modules/Menus/Resources/views/admin/index.blade.php b/Modules/Menus/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..2c51b25 --- /dev/null +++ b/Modules/Menus/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Menus

Manage menus content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
NameLocationItemsActions
{{ is_array($record->name) ? json_encode($record->name) : Str::limit((string) $record->name, 70) }}{{ is_array($record->location) ? json_encode($record->location) : Str::limit((string) $record->location, 70) }}{{ is_array($record->items) ? json_encode($record->items) : Str::limit((string) $record->items, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Menus/Routes/web.php b/Modules/Menus/Routes/web.php new file mode 100644 index 0000000..32b6ab8 --- /dev/null +++ b/Modules/Menus/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/menus')->name('administration.menus.')->group(function (): void { + Route::resource('/', MenuController::class)->parameters(['' => 'menu'])->except('show'); +}); diff --git a/Modules/Menus/Support/ModuleInfo.php b/Modules/Menus/Support/ModuleInfo.php new file mode 100644 index 0000000..4a845a6 --- /dev/null +++ b/Modules/Menus/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Menus/module.json b/Modules/Menus/module.json new file mode 100644 index 0000000..6474504 --- /dev/null +++ b/Modules/Menus/module.json @@ -0,0 +1,20 @@ +{ + "name": "Menus", + "alias": "menus", + "version": "1.0.0", + "description": "Menus CMS module.", + "keywords": [ + "cms", + "menus" + ], + "priority": 22, + "providers": [ + "Modules\\Menus\\Providers\\MenusServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Pages/Config/config.php b/Modules/Pages/Config/config.php new file mode 100644 index 0000000..68aabbf --- /dev/null +++ b/Modules/Pages/Config/config.php @@ -0,0 +1,3 @@ + 'Pages']; diff --git a/Modules/Pages/Database/Migrations/2026_07_24_000100_create_pages_table.php b/Modules/Pages/Database/Migrations/2026_07_24_000100_create_pages_table.php new file mode 100644 index 0000000..6095217 --- /dev/null +++ b/Modules/Pages/Database/Migrations/2026_07_24_000100_create_pages_table.php @@ -0,0 +1,18 @@ +id(); + $table->string('title'); + $table->string('slug'); + $table->text('summary')->nullable(); + $table->longText('content')->nullable(); + $table->string('status')->default('draft'); + $table->timestamp('published_at')->nullable(); + $table->boolean('is_home')->default(false); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('pages'); } +}; diff --git a/Modules/Pages/Http/Controllers/PageController.php b/Modules/Pages/Http/Controllers/PageController.php new file mode 100644 index 0000000..8928a75 --- /dev/null +++ b/Modules/Pages/Http/Controllers/PageController.php @@ -0,0 +1,31 @@ + Page::query()->latest()->paginate(20)]); } + public function create(): View { return view('pages::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'slug' => ['required', 'string', 'max:255'], + 'summary' => ['nullable', 'string'], + 'content' => ['nullable', 'string'], + 'status' => ['required', 'string', 'max:255'], + 'published_at' => ['nullable', 'date'], + 'is_home' => ['sometimes', 'boolean']]); $data['is_home'] = $request->boolean('is_home'); Page::create($data); return redirect()->route('pages.index')->with('status', 'Page created.'); } + public function edit(Page $page): View { return view('pages::admin.form', ['record' => $page]); } + public function update(Request $request, Page $page): RedirectResponse { $data = $request->validate(['title' => ['required', 'string', 'max:255'], + 'slug' => ['required', 'string', 'max:255'], + 'summary' => ['nullable', 'string'], + 'content' => ['nullable', 'string'], + 'status' => ['required', 'string', 'max:255'], + 'published_at' => ['nullable', 'date'], + 'is_home' => ['sometimes', 'boolean']]); $data['is_home'] = $request->boolean('is_home'); $page->update($data); return redirect()->route('pages.index')->with('status', 'Page updated.'); } + public function destroy(Page $page): RedirectResponse { $page->delete(); return back()->with('status', 'Page deleted.'); } +} diff --git a/Modules/Pages/Http/Controllers/PublicPageController.php b/Modules/Pages/Http/Controllers/PublicPageController.php new file mode 100644 index 0000000..fd3e0df --- /dev/null +++ b/Modules/Pages/Http/Controllers/PublicPageController.php @@ -0,0 +1,6 @@ +where('slug',$slug)->where('status','published')->where(fn($q)=>$q->whereNull('published_at')->orWhere('published_at','<=',now()))->firstOrFail(); return view('pages::public.show',compact('page')); } } diff --git a/Modules/Pages/Models/Page.php b/Modules/Pages/Models/Page.php new file mode 100644 index 0000000..2a713a1 --- /dev/null +++ b/Modules/Pages/Models/Page.php @@ -0,0 +1,20 @@ + 'datetime', + 'is_home' => 'boolean' + ]; } + +} diff --git a/Modules/Pages/Providers/PagesServiceProvider.php b/Modules/Pages/Providers/PagesServiceProvider.php new file mode 100644 index 0000000..0a1d101 --- /dev/null +++ b/Modules/Pages/Providers/PagesServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Pages', 'Config/config.php'), 'pages'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Pages', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Pages', 'Resources/views'), 'pages'); + } +} diff --git a/Modules/Pages/Providers/RouteServiceProvider.php b/Modules/Pages/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..7984a9e --- /dev/null +++ b/Modules/Pages/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Pages', 'Routes/web.php'))); + } +} diff --git a/Modules/Pages/Resources/views/admin/form.blade.php b/Modules/Pages/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..55df2bc --- /dev/null +++ b/Modules/Pages/Resources/views/admin/form.blade.php @@ -0,0 +1,11 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Page

@csrf @isset($record) @method('PUT') @endisset +
@error('title')

{{ $message }}

@enderror
+
@error('slug')

{{ $message }}

@enderror
+
@error('summary')

{{ $message }}

@enderror
+
@error('content')

{{ $message }}

@enderror
+
@error('status')

{{ $message }}

@enderror
+
@error('published_at')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Pages/Resources/views/admin/index.blade.php b/Modules/Pages/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..fe1828c --- /dev/null +++ b/Modules/Pages/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Pages

Manage pages content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
TitleSlugSummaryActions
{{ is_array($record->title) ? json_encode($record->title) : Str::limit((string) $record->title, 70) }}{{ is_array($record->slug) ? json_encode($record->slug) : Str::limit((string) $record->slug, 70) }}{{ is_array($record->summary) ? json_encode($record->summary) : Str::limit((string) $record->summary, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Pages/Resources/views/public/show.blade.php b/Modules/Pages/Resources/views/public/show.blade.php new file mode 100644 index 0000000..ee80ff9 --- /dev/null +++ b/Modules/Pages/Resources/views/public/show.blade.php @@ -0,0 +1 @@ +

{{ $page->title }}

@if($page->summary)

{{ $page->summary }}

@endif{!! $page->content !!}
\ No newline at end of file diff --git a/Modules/Pages/Routes/web.php b/Modules/Pages/Routes/web.php new file mode 100644 index 0000000..c3eef5b --- /dev/null +++ b/Modules/Pages/Routes/web.php @@ -0,0 +1,10 @@ +prefix('administration/pages')->name('administration.pages.')->group(function (): void { + Route::resource('/', PageController::class)->parameters(['' => 'page'])->except('show'); +}); + +Route::get('/pages/{slug}', [Modules\Pages\Http\Controllers\PublicPageController::class, 'show'])->name('pages.public.show'); diff --git a/Modules/Pages/Support/ModuleInfo.php b/Modules/Pages/Support/ModuleInfo.php new file mode 100644 index 0000000..b0c7b4a --- /dev/null +++ b/Modules/Pages/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Pages/module.json b/Modules/Pages/module.json new file mode 100644 index 0000000..d891304 --- /dev/null +++ b/Modules/Pages/module.json @@ -0,0 +1,20 @@ +{ + "name": "Pages", + "alias": "pages", + "version": "1.0.0", + "description": "Pages CMS module.", + "keywords": [ + "cms", + "pages" + ], + "priority": 21, + "providers": [ + "Modules\\Pages\\Providers\\PagesServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Redirects/Config/config.php b/Modules/Redirects/Config/config.php new file mode 100644 index 0000000..e5170bd --- /dev/null +++ b/Modules/Redirects/Config/config.php @@ -0,0 +1,3 @@ + 'Redirects']; diff --git a/Modules/Redirects/Database/Migrations/2026_07_24_000300_create_redirects_table.php b/Modules/Redirects/Database/Migrations/2026_07_24_000300_create_redirects_table.php new file mode 100644 index 0000000..9708c38 --- /dev/null +++ b/Modules/Redirects/Database/Migrations/2026_07_24_000300_create_redirects_table.php @@ -0,0 +1,15 @@ +id(); + $table->string('source'); + $table->string('destination'); + $table->unsignedInteger('status_code')->default(301); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('redirects'); } +}; diff --git a/Modules/Redirects/Http/Controllers/RedirectController.php b/Modules/Redirects/Http/Controllers/RedirectController.php new file mode 100644 index 0000000..9b45119 --- /dev/null +++ b/Modules/Redirects/Http/Controllers/RedirectController.php @@ -0,0 +1,25 @@ + Redirect::query()->latest()->paginate(20)]); } + public function create(): View { return view('redirects::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['source' => ['required', 'string', 'max:255'], + 'destination' => ['required', 'string', 'max:255'], + 'status_code' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); Redirect::create($data); return redirect()->route('redirects.index')->with('status', 'Redirect created.'); } + public function edit(Redirect $redirect): View { return view('redirects::admin.form', ['record' => $redirect]); } + public function update(Request $request, Redirect $redirect): RedirectResponse { $data = $request->validate(['source' => ['required', 'string', 'max:255'], + 'destination' => ['required', 'string', 'max:255'], + 'status_code' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); $redirect->update($data); return redirect()->route('redirects.index')->with('status', 'Redirect updated.'); } + public function destroy(Redirect $redirect): RedirectResponse { $redirect->delete(); return back()->with('status', 'Redirect deleted.'); } +} diff --git a/Modules/Redirects/Models/Redirect.php b/Modules/Redirects/Models/Redirect.php new file mode 100644 index 0000000..cb2b84f --- /dev/null +++ b/Modules/Redirects/Models/Redirect.php @@ -0,0 +1,20 @@ + 'integer', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Redirects/Providers/RedirectsServiceProvider.php b/Modules/Redirects/Providers/RedirectsServiceProvider.php new file mode 100644 index 0000000..d32dbda --- /dev/null +++ b/Modules/Redirects/Providers/RedirectsServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Redirects', 'Config/config.php'), 'redirects'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Redirects', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Redirects', 'Resources/views'), 'redirects'); + } +} diff --git a/Modules/Redirects/Providers/RouteServiceProvider.php b/Modules/Redirects/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..ba5a142 --- /dev/null +++ b/Modules/Redirects/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Redirects', 'Routes/web.php'))); + } +} diff --git a/Modules/Redirects/Resources/views/admin/form.blade.php b/Modules/Redirects/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..18dccf9 --- /dev/null +++ b/Modules/Redirects/Resources/views/admin/form.blade.php @@ -0,0 +1,8 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Redirect

@csrf @isset($record) @method('PUT') @endisset +
@error('source')

{{ $message }}

@enderror
+
@error('destination')

{{ $message }}

@enderror
+
@error('status_code')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Redirects/Resources/views/admin/index.blade.php b/Modules/Redirects/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..cf7590b --- /dev/null +++ b/Modules/Redirects/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Redirects

Manage redirects content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
SourceDestinationStatus CodeActions
{{ is_array($record->source) ? json_encode($record->source) : Str::limit((string) $record->source, 70) }}{{ is_array($record->destination) ? json_encode($record->destination) : Str::limit((string) $record->destination, 70) }}{{ is_array($record->status_code) ? json_encode($record->status_code) : Str::limit((string) $record->status_code, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Redirects/Routes/web.php b/Modules/Redirects/Routes/web.php new file mode 100644 index 0000000..d48f606 --- /dev/null +++ b/Modules/Redirects/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/redirects')->name('administration.redirects.')->group(function (): void { + Route::resource('/', RedirectController::class)->parameters(['' => 'redirect'])->except('show'); +}); diff --git a/Modules/Redirects/Support/ModuleInfo.php b/Modules/Redirects/Support/ModuleInfo.php new file mode 100644 index 0000000..3f265d0 --- /dev/null +++ b/Modules/Redirects/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Redirects/module.json b/Modules/Redirects/module.json new file mode 100644 index 0000000..cebfd49 --- /dev/null +++ b/Modules/Redirects/module.json @@ -0,0 +1,20 @@ +{ + "name": "Redirects", + "alias": "redirects", + "version": "1.0.0", + "description": "Redirects CMS module.", + "keywords": [ + "cms", + "redirects" + ], + "priority": 23, + "providers": [ + "Modules\\Redirects\\Providers\\RedirectsServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Roles/Database/Seeders/RolePermissionSeeder.php b/Modules/Roles/Database/Seeders/RolePermissionSeeder.php index 0402e8b..3ad41ea 100644 --- a/Modules/Roles/Database/Seeders/RolePermissionSeeder.php +++ b/Modules/Roles/Database/Seeders/RolePermissionSeeder.php @@ -30,6 +30,15 @@ final class RolePermissionSeeder extends Seeder 'seo.manage', 'search.manage', 'themes.manage', + 'pages.manage', + 'menus.manage', + 'redirects.manage', + 'forms.manage', + 'documents.manage', + 'banners.manage', + 'faq.manage', + 'team.manage', + 'testimonials.manage', ]; foreach ($permissions as $permission) { diff --git a/Modules/Team/Config/config.php b/Modules/Team/Config/config.php new file mode 100644 index 0000000..3342295 --- /dev/null +++ b/Modules/Team/Config/config.php @@ -0,0 +1,3 @@ + 'Team']; diff --git a/Modules/Team/Database/Migrations/2026_07_24_000800_create_team_members_table.php b/Modules/Team/Database/Migrations/2026_07_24_000800_create_team_members_table.php new file mode 100644 index 0000000..75e742b --- /dev/null +++ b/Modules/Team/Database/Migrations/2026_07_24_000800_create_team_members_table.php @@ -0,0 +1,17 @@ +id(); + $table->string('name'); + $table->string('job_title')->nullable(); + $table->text('biography')->nullable(); + $table->string('email')->nullable(); + $table->unsignedInteger('sort_order')->default(0); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('team_members'); } +}; diff --git a/Modules/Team/Http/Controllers/TeamMemberController.php b/Modules/Team/Http/Controllers/TeamMemberController.php new file mode 100644 index 0000000..2de2eb8 --- /dev/null +++ b/Modules/Team/Http/Controllers/TeamMemberController.php @@ -0,0 +1,29 @@ + TeamMember::query()->latest()->paginate(20)]); } + public function create(): View { return view('team::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'job_title' => ['nullable', 'string'], + 'biography' => ['nullable', 'string'], + 'email' => ['nullable', 'string'], + 'sort_order' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); TeamMember::create($data); return redirect()->route('team.index')->with('status', 'TeamMember created.'); } + public function edit(TeamMember $teamMember): View { return view('team::admin.form', ['record' => $teamMember]); } + public function update(Request $request, TeamMember $teamMember): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'job_title' => ['nullable', 'string'], + 'biography' => ['nullable', 'string'], + 'email' => ['nullable', 'string'], + 'sort_order' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); $teamMember->update($data); return redirect()->route('team.index')->with('status', 'TeamMember updated.'); } + public function destroy(TeamMember $teamMember): RedirectResponse { $teamMember->delete(); return back()->with('status', 'TeamMember deleted.'); } +} diff --git a/Modules/Team/Models/TeamMember.php b/Modules/Team/Models/TeamMember.php new file mode 100644 index 0000000..fd7b518 --- /dev/null +++ b/Modules/Team/Models/TeamMember.php @@ -0,0 +1,20 @@ + 'integer', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Team/Providers/RouteServiceProvider.php b/Modules/Team/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..a50f441 --- /dev/null +++ b/Modules/Team/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Team', 'Routes/web.php'))); + } +} diff --git a/Modules/Team/Providers/TeamServiceProvider.php b/Modules/Team/Providers/TeamServiceProvider.php new file mode 100644 index 0000000..6cdcac1 --- /dev/null +++ b/Modules/Team/Providers/TeamServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Team', 'Config/config.php'), 'team'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Team', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Team', 'Resources/views'), 'team'); + } +} diff --git a/Modules/Team/Resources/views/admin/form.blade.php b/Modules/Team/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..621f780 --- /dev/null +++ b/Modules/Team/Resources/views/admin/form.blade.php @@ -0,0 +1,10 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Team member

@csrf @isset($record) @method('PUT') @endisset +
@error('name')

{{ $message }}

@enderror
+
@error('job_title')

{{ $message }}

@enderror
+
@error('biography')

{{ $message }}

@enderror
+
@error('email')

{{ $message }}

@enderror
+
@error('sort_order')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Team/Resources/views/admin/index.blade.php b/Modules/Team/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..6345c12 --- /dev/null +++ b/Modules/Team/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Team

Manage team content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
NameJob TitleBiographyActions
{{ is_array($record->name) ? json_encode($record->name) : Str::limit((string) $record->name, 70) }}{{ is_array($record->job_title) ? json_encode($record->job_title) : Str::limit((string) $record->job_title, 70) }}{{ is_array($record->biography) ? json_encode($record->biography) : Str::limit((string) $record->biography, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Team/Routes/web.php b/Modules/Team/Routes/web.php new file mode 100644 index 0000000..f9b0f47 --- /dev/null +++ b/Modules/Team/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/team')->name('administration.team.')->group(function (): void { + Route::resource('/', TeamMemberController::class)->parameters(['' => 'teamMember'])->except('show'); +}); diff --git a/Modules/Team/Support/ModuleInfo.php b/Modules/Team/Support/ModuleInfo.php new file mode 100644 index 0000000..3189d8a --- /dev/null +++ b/Modules/Team/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Team/module.json b/Modules/Team/module.json new file mode 100644 index 0000000..7cbacd8 --- /dev/null +++ b/Modules/Team/module.json @@ -0,0 +1,20 @@ +{ + "name": "Team", + "alias": "team", + "version": "1.0.0", + "description": "Team CMS module.", + "keywords": [ + "cms", + "team" + ], + "priority": 28, + "providers": [ + "Modules\\Team\\Providers\\TeamServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/Modules/Testimonials/Config/config.php b/Modules/Testimonials/Config/config.php new file mode 100644 index 0000000..ab940e8 --- /dev/null +++ b/Modules/Testimonials/Config/config.php @@ -0,0 +1,3 @@ + 'Testimonials']; diff --git a/Modules/Testimonials/Database/Migrations/2026_07_24_000900_create_testimonials_table.php b/Modules/Testimonials/Database/Migrations/2026_07_24_000900_create_testimonials_table.php new file mode 100644 index 0000000..43bed44 --- /dev/null +++ b/Modules/Testimonials/Database/Migrations/2026_07_24_000900_create_testimonials_table.php @@ -0,0 +1,16 @@ +id(); + $table->string('name'); + $table->string('company')->nullable(); + + $table->unsignedInteger('rating')->default(5); + $table->boolean('enabled')->default(true); + $table->timestamps(); $table->softDeletes(); }); } + public function down(): void { Schema::dropIfExists('testimonials'); } +}; diff --git a/Modules/Testimonials/Http/Controllers/TestimonialController.php b/Modules/Testimonials/Http/Controllers/TestimonialController.php new file mode 100644 index 0000000..b5d44a3 --- /dev/null +++ b/Modules/Testimonials/Http/Controllers/TestimonialController.php @@ -0,0 +1,27 @@ + Testimonial::query()->latest()->paginate(20)]); } + public function create(): View { return view('testimonials::admin.form'); } + public function store(Request $request): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'company' => ['nullable', 'string'], + 'content' => ['required', 'string'], + 'rating' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); Testimonial::create($data); return redirect()->route('testimonials.index')->with('status', 'Testimonial created.'); } + public function edit(Testimonial $testimonial): View { return view('testimonials::admin.form', ['record' => $testimonial]); } + public function update(Request $request, Testimonial $testimonial): RedirectResponse { $data = $request->validate(['name' => ['required', 'string', 'max:255'], + 'company' => ['nullable', 'string'], + 'content' => ['required', 'string'], + 'rating' => ['nullable', 'integer', 'min:0'], + 'enabled' => ['sometimes', 'boolean']]); $data['enabled'] = $request->boolean('enabled'); $testimonial->update($data); return redirect()->route('testimonials.index')->with('status', 'Testimonial updated.'); } + public function destroy(Testimonial $testimonial): RedirectResponse { $testimonial->delete(); return back()->with('status', 'Testimonial deleted.'); } +} diff --git a/Modules/Testimonials/Models/Testimonial.php b/Modules/Testimonials/Models/Testimonial.php new file mode 100644 index 0000000..642d9a2 --- /dev/null +++ b/Modules/Testimonials/Models/Testimonial.php @@ -0,0 +1,20 @@ + 'integer', + 'enabled' => 'boolean' + ]; } + +} diff --git a/Modules/Testimonials/Providers/RouteServiceProvider.php b/Modules/Testimonials/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..98aac75 --- /dev/null +++ b/Modules/Testimonials/Providers/RouteServiceProvider.php @@ -0,0 +1,15 @@ +routes(fn () => Route::middleware('web')->group(module_path('Testimonials', 'Routes/web.php'))); + } +} diff --git a/Modules/Testimonials/Providers/TestimonialsServiceProvider.php b/Modules/Testimonials/Providers/TestimonialsServiceProvider.php new file mode 100644 index 0000000..fde762a --- /dev/null +++ b/Modules/Testimonials/Providers/TestimonialsServiceProvider.php @@ -0,0 +1,20 @@ +app->register(RouteServiceProvider::class); + $this->mergeConfigFrom(module_path('Testimonials', 'Config/config.php'), 'testimonials'); + } + + public function boot(): void + { + $this->loadMigrationsFrom(module_path('Testimonials', 'Database/Migrations')); + $this->loadViewsFrom(module_path('Testimonials', 'Resources/views'), 'testimonials'); + } +} diff --git a/Modules/Testimonials/Resources/views/admin/form.blade.php b/Modules/Testimonials/Resources/views/admin/form.blade.php new file mode 100644 index 0000000..c6f4e86 --- /dev/null +++ b/Modules/Testimonials/Resources/views/admin/form.blade.php @@ -0,0 +1,9 @@ + +

{{ isset($record) ? 'Edit' : 'Create' }} Testimonial

@csrf @isset($record) @method('PUT') @endisset +
@error('name')

{{ $message }}

@enderror
+
@error('company')

{{ $message }}

@enderror
+
@error('content')

{{ $message }}

@enderror
+
@error('rating')

{{ $message }}

@enderror
+ +
Cancel
+
diff --git a/Modules/Testimonials/Resources/views/admin/index.blade.php b/Modules/Testimonials/Resources/views/admin/index.blade.php new file mode 100644 index 0000000..ab55427 --- /dev/null +++ b/Modules/Testimonials/Resources/views/admin/index.blade.php @@ -0,0 +1,5 @@ + +

Testimonials

Manage testimonials content.

Add new
+@if(session('status'))
{{ session('status') }}
@endif +
@forelse($records as $record)@empty@endforelse
NameCompanyContentActions
{{ is_array($record->name) ? json_encode($record->name) : Str::limit((string) $record->name, 70) }}{{ is_array($record->company) ? json_encode($record->company) : Str::limit((string) $record->company, 70) }}{{ is_array($record->content) ? json_encode($record->content) : Str::limit((string) $record->content, 70) }}Edit
@csrf @method('DELETE')
No records yet.
{{ $records->links() }}
+
diff --git a/Modules/Testimonials/Routes/web.php b/Modules/Testimonials/Routes/web.php new file mode 100644 index 0000000..e7f2888 --- /dev/null +++ b/Modules/Testimonials/Routes/web.php @@ -0,0 +1,8 @@ +prefix('administration/testimonials')->name('administration.testimonials.')->group(function (): void { + Route::resource('/', TestimonialController::class)->parameters(['' => 'testimonial'])->except('show'); +}); diff --git a/Modules/Testimonials/Support/ModuleInfo.php b/Modules/Testimonials/Support/ModuleInfo.php new file mode 100644 index 0000000..57474b2 --- /dev/null +++ b/Modules/Testimonials/Support/ModuleInfo.php @@ -0,0 +1,5 @@ +toBeTrue(); }); diff --git a/Modules/Testimonials/module.json b/Modules/Testimonials/module.json new file mode 100644 index 0000000..9ee5cfa --- /dev/null +++ b/Modules/Testimonials/module.json @@ -0,0 +1,20 @@ +{ + "name": "Testimonials", + "alias": "testimonials", + "version": "1.0.0", + "description": "Testimonials CMS module.", + "keywords": [ + "cms", + "testimonials" + ], + "priority": 29, + "providers": [ + "Modules\\Testimonials\\Providers\\TestimonialsServiceProvider" + ], + "aliases": {}, + "files": [], + "requires": [ + "Core", + "Administration" + ] +} diff --git a/modules_statuses.json b/modules_statuses.json index d0e54d9..31f9129 100644 --- a/modules_statuses.json +++ b/modules_statuses.json @@ -8,5 +8,14 @@ "Audit": true, "Media": true, "Seo": true, - "Search": true + "Search": true, + "Pages": true, + "Menus": true, + "Redirects": true, + "Forms": true, + "Documents": true, + "Banners": true, + "Faq": true, + "Team": true, + "Testimonials": true } diff --git a/resources/themes/common/views/components/layouts/app/sidebar.blade.php b/resources/themes/common/views/components/layouts/app/sidebar.blade.php index 8f3b850..39773a2 100644 --- a/resources/themes/common/views/components/layouts/app/sidebar.blade.php +++ b/resources/themes/common/views/components/layouts/app/sidebar.blade.php @@ -11,6 +11,19 @@ + + + {{ __('Pages') }} + {{ __('Menus') }} + {{ __('Redirects') }} + {{ __('Forms') }} + {{ __('Documents') }} + {{ __('Banners') }} + {{ __('FAQ') }} + {{ __('Team') }} + {{ __('Testimonials') }} + + {{ __('Dashboard') }} {{ __('Administration') }} diff --git a/storage/logs/laravel.log b/storage/logs/laravel.log index 3d3b35f..a7e48c9 100644 --- a/storage/logs/laravel.log +++ b/storage/logs/laravel.log @@ -1220,3 +1220,63 @@ #54 /Users/mag/Sites/Content_Manager/public/index.php(20): Illuminate\\Foundation\\Application->handleRequest(Object(Illuminate\\Http\\Request)) #55 {main} "} +[2026-07-24 08:44:39] local.ERROR: Route [faq.index] not defined. {"userId":1,"exception":"[object] (Symfony\\Component\\Routing\\Exception\\RouteNotFoundException(code: 0): Route [faq.index] not defined. at /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php:540) +[stacktrace] +#0 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Redirector.php(153): Illuminate\\Routing\\UrlGenerator->route('faq.index', Array) +#1 /Users/mag/Sites/Content_Manager/Modules/Faq/Http/Controllers/FaqController.php(19): Illuminate\\Routing\\Redirector->route('faq.index') +#2 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(46): Modules\\Faq\\Http\\Controllers\\FaqController->store(Object(Illuminate\\Http\\Request)) +#3 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Route.php(276): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(Modules\\Faq\\Http\\Controllers\\FaqController), 'store') +#4 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Route.php(216): Illuminate\\Routing\\Route->runController() +#5 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Router.php(822): Illuminate\\Routing\\Route->run() +#6 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request)) +#7 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php(41): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#8 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Auth\\Middleware\\EnsureEmailIsVerified->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#9 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(52): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#10 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#11 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(63): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#12 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Auth\\Middleware\\Authenticate->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#13 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestForgery.php(104): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#14 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestForgery->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#15 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(48): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#16 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#17 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(120): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#18 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(63): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure)) +#19 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#20 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(36): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#21 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#22 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(74): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#23 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#24 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#25 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Router.php(821): Illuminate\\Pipeline\\Pipeline->then(Object(Closure)) +#26 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Router.php(800): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request)) +#27 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Router.php(764): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route)) +#28 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Routing/Router.php(753): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request)) +#29 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(200): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request)) +#30 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request)) +#31 /Users/mag/Sites/Content_Manager/vendor/livewire/livewire/src/Features/SupportDisablingBackButtonCache/DisableBackButtonCacheMiddleware.php(19): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#32 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Livewire\\Features\\SupportDisablingBackButtonCache\\DisableBackButtonCacheMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#33 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#34 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#35 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#36 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#37 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(51): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#38 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#39 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#40 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#41 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(109): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#42 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#43 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(61): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#44 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#45 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(58): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#46 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#47 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/InvokeDeferredCallbacks.php(22): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#48 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Foundation\\Http\\Middleware\\InvokeDeferredCallbacks->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#49 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Http/Middleware/ValidatePathEncoding.php(28): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#50 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(219): Illuminate\\Http\\Middleware\\ValidatePathEncoding->handle(Object(Illuminate\\Http\\Request), Object(Closure)) +#51 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(137): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request)) +#52 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(175): Illuminate\\Pipeline\\Pipeline->then(Object(Closure)) +#53 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(144): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request)) +#54 /Users/mag/Sites/Content_Manager/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1227): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request)) +#55 /Users/mag/Sites/Content_Manager/public/index.php(20): Illuminate\\Foundation\\Application->handleRequest(Object(Illuminate\\Http\\Request)) +#56 {main} +"}