kamoji/cms
Laravel CMS package for building and managing website content, pages, and admin features in PHP. Provides a foundation for content modeling and backend management to speed up custom CMS development and integrations.
Installation
composer require kamoji/cms
Publish the package assets and configuration:
php artisan vendor:publish --provider="Kamoji\CMS\CMSServiceProvider" --tag="config"
php artisan vendor:publish --provider="Kamoji\CMS\CMSServiceProvider" --tag="migrations"
php artisan migrate
Service Provider & Routes
Ensure the package is registered in config/app.php under providers:
Kamoji\CMS\CMSServiceProvider::class,
Add CMS routes in routes/web.php:
Route::middleware(['web', 'auth'])->group(function () {
Route::prefix('admin')->group(function () {
Route::resource('pages', 'Kamoji\CMS\Http\Controllers\PageController');
});
});
First Use Case: Creating a Page
/admin/pages/create in your browser.CRUD Operations
Use the Page model (Kamoji\CMS\Models\Page) to interact with pages programmatically:
use Kamoji\CMS\Models\Page;
// Create a page
$page = Page::create([
'title' => 'About Us',
'slug' => 'about',
'content' => '<h1>Welcome to our page</h1>',
'status' => 'published',
]);
// Retrieve a page by slug
$page = Page::where('slug', 'about')->first();
// Update a page
$page->update(['content' => '<h1>Updated content</h1>']);
// Delete a page
$page->delete();
Frontend Display Retrieve and display pages in your views:
// In a controller
public function showPage($slug) {
$page = Page::where('slug', $slug)->firstOrFail();
return view('pages.show', compact('page'));
}
// In a blade view
<div class="page-content">
{!! $page->content !!}
</div>
Adding Custom Fields
Extend the Page model to include custom fields. For example, add a meta_description field:
// In a migration
Schema::table('pages', function (Blueprint $table) {
$table->text('meta_description')->nullable();
});
// Update the model
public function fillable() {
return array_merge(parent::fillable(), ['meta_description']);
}
Event Listeners
Listen to page events (e.g., page.created) to trigger custom logic:
// In EventServiceProvider
protected $listen = [
'Kamoji\CMS\Events\PageCreated' => [
'App\Listeners\LogPageCreation',
],
];
Route::middleware(['web', 'auth', 'admin'])->group(function () {
Route::resource('pages', 'Kamoji\CMS\Http\Controllers\PageController');
});
Create a custom middleware (app/Http/Middleware/AdminMiddleware.php):
public function handle($request, Closure $next) {
if (!auth()->user()->isAdmin()) {
abort(403);
}
return $next($request);
}
Override Default Views Publish and override the package’s views:
php artisan vendor:publish --provider="Kamoji\CMS\CMSServiceProvider" --tag="views"
Customize the views in resources/views/vendor/cms/.
Dynamic Templates Use blade templates to create reusable layouts for pages:
// In a controller
public function show($slug) {
$page = Page::where('slug', $slug)->firstOrFail();
return view('cms.templates.' . $page->template, compact('page'));
}
Route::prefix('admin')->namespace('Admin')->group(function () {
Route::resource('pages', 'PageController');
});
pages table structure before running migrations. If needed, rollback and re-run:
php artisan migrate:rollback
php artisan migrate
{!! $page->content !!}) can expose XSS vulnerabilities.
use Purifier;
$cleanContent = Purifier::clean($page->content);
Or use Laravel’s built-in e() helper for escaping:
{!! e($page->content) !!}
// Cache the page with a tag
Cache::tags(['page-' . $page->slug])->put('page-' . $page->slug, $page, now()->addHours(1));
// Clear cache on update
Cache::tags(['page-' . $page->slug])->flush();
php artisan cms:clear-cache
php artisan cms:sitemap
Custom Controllers Override the default controllers by binding them in the service provider:
public function boot() {
$this->app->bind(
'Kamoji\CMS\Http\Controllers\PageController',
'App\Http\Controllers\Admin\PageController'
);
}
Custom Models
Extend the Page model to add custom logic:
class CustomPage extends \Kamoji\CMS\Models\Page {
public function getFormattedContent() {
return str_replace(['<p>', '</p>'], ['<div class="content-paragraph">', '</div>'], $this->content);
}
}
Bind the custom model in the service provider:
$this->app->bind('Kamoji\CMS\Models\Page', 'App\Models\CustomPage');
Page model to support localization:
public function translations() {
return $this->hasMany(\App\Models\PageTranslation::class);
}
Create a pivot table for translations and update the CMS to handle them.use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Page extends \Kamoji\CMS\Models\Page implements HasMedia {
use InteractsWithMedia;
public function registerMediaCollections(): void {
$this->addMediaCollection('images');
}
}
// In a listener
Log::info('Page updated', ['page_id' => $page->id, 'changes' => $changes]);
Or use a package like spatie/laravel-logging for structured logging.Page model and its interactions:
public function test_page_creation() {
$page = Page::create(['title' => 'Test', 'slug' => 'test', 'content' => '<p>Test</p>']);
$this->
How can I help you explore Laravel packages today?