Plugin Development
# Overview
SITS CMS provides a flexible plugin system that allows developers to extend core functionality. This guide explains how to create and integrate custom plugins.
# Plugin Directory Structure
Create your plugin with the following structure in the plugins/ directory:
your-plugin-name/
├── database/
│ └── migrations
| └── create_your_plugin_name_table.php
├── helpers/
│ └── helpers.php
├── resources/
│ └── views/
| ├── details.blade.php
| ├── index.blade.php
| ├── single.blade.php
| └── table-details.blade.php
├── routes/
│ └── web.php
├── src/
│ ├── Http/
| | └── Controllers/
| | └── YourPluginController.php
│ ├── Models/
| | └── YourPluginModel.php
│ └── Providers/
| └── YourPluginServiceProvider.php
└── plugin.json
Key components of a plugin include:
- database/ - Database migrations
- resources/ - Views
- routes/ - Route definitions
- src/ - Core plugin code including controllers, models, and service providers
- plugin.json - Plugin metadata and dependencies
Each plugin must have a plugin.json file that provides essential information for
auto-loading and plugin management. This file includes details like the plugin name,
description, author, and version.
Plugins are registered to the system's autoloader automatically when installed. The service provider in each plugin bootstraps the plugin's components and registers its services with the application container.
# Step-by-Step Plugin Creation
- Create plugin.json
{ "id": "YourVendor/your plugin name", "name": "Your Plugin Name", "namespace": "YourVendor\\YourPlugin", "provider": "YourVendor\\YourPlugin\\Providers\\YourPluginServiceProvider", "author": "Your Name", "url": "https://yourdomain.com", "version": "1.0", "description": "Description of your plugin", "require":{ "plugins" :[ { "id":"YourVendor/plugin name", "name" : "Plugin Name", "version":"1.0" } ] } }The key fields in plugin.json are:
- id - Unique identifier for the plugin
- name - Display name of the plugin
- namespace - PHP namespace used by the plugin
- provider - Service provider class that bootstraps the plugin
- author - Plugin author/organization name
- version - Plugin version number
- description - Brief description of plugin functionality
- require – This is optional. Use it only if your plugin depends on another plugin or package that needs to be activated or installed. Otherwise, you can leave it out.
Example: blog/plugin.json
- Create Service Provider
Create
YourPluginServiceProvider.phpin the src directory:The service provider is the main bootstrapping class for your plugin. It handles tasks like:
- Loading routes, views, migrations and other resources
- Publishing assets and configuration files
- Registering services with the application container
- Setting up event listeners and hooks
Example: blog/src/Providers/BlogServiceProvider.php
namespace Sits\Blog\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Routing\Events\RouteMatched; use Illuminate\Support\Facades\Event; use Sits\Base\Traits\LoadAndPublish; class BlogServiceProvider extends ServiceProvider { use LoadAndPublish; public function boot() { $this->loadRoutes() ->loadViews('sits/blog') ->loadMigrations() ->publishMigrations('sits-blog-migrations'); # Register Dashboard Menu Event::listen(RouteMatched::class, function () { dashboard_menu()->registerMenu([ 'id' => 'blogs', 'title' => "Blogs", "icon" => "fa fa-blog", "type" => "plugin", "url" => '#', "route_name" => "admin.blogs", "sub_menus" => [ (object) [ 'id' => 'blog-categories', 'title' => "Category", "icon" => "fa fa-blog", "route_name" => "admin.blogs.categories", "url" => url('admin/blogs/categories') ], (object) [ 'id' => 'blogs', 'title' => "Posts", "icon" => "fa fa-hammer", "route_name" => "admin.blogs.posts", "url" => url('admin/blogs/posts') ], (object) [ 'id' => 'blog-tags', 'title' => "Tags", "icon" => "fa fa-tags", "route_name" => "admin.blogs.tags", "url" => url('admin/blogs/tags'), ], ], ]); }); } } - Add Routes
Define your plugin routes in
routes/web.php:Example: blog/routes/web.php
Route::middleware(['web', 'auth:admin'])->prefix('admin/blogs/posts')->name('admin.blogs.posts.')->group(function () { Route::resource('/', BlogController::class)->parameters(['' => 'blog']); Route::post('bulk_delete', [BlogController::class, 'bulk_delete'])->name('bulk_delete'); Route::post('bulk_restore', [BlogController::class, 'bulk_restore'])->name('bulk_restore'); Route::post('bulk_permanent_delete', [BlogController::class, 'bulk_permanent_delete'])->name('bulk_permanent_delete'); Route::post('restore/{id}', [BlogController::class, 'restore'])->name('restore'); Route::delete('permanent-delete/{id}', [BlogController::class, 'permanent_delete'])->name('permanent_delete'); }); -
Required Resource Files
The
resourcesdirectory of the plugin must contain the following Blade view templates:details.blade.phpandtable-details.blade.php. These templates are utilized for rendering the detailed view.
# Plugin Activation
Follow the steps below to activate a plugin and make it available in the system:
- Open the Admin Panel and navigate to Plugins.
- Search for the plugin by its name using the search field.
- Click the Activate button next to the plugin.
Once the plugin is successfully activated, its status will change to Activated, as shown in the example below.
Example: blog plugin activated
# About Folders and Files
# database/
The database folder contains the migrations for the plugin.
sits/plugins/example-plugin/database/migrations/
└── 2023_01_01_000000_create_example_plugin_table.php
To create a new migration file for your plugin table, run the following Artisan command:
php artisan make:migration create_example_plugin_table --path=sits/plugins/example-plugin/database/migrations
After creating the migration file inside your plugin's
database/migrations directory,
define your table structure as shown below.
Here's an example of a typical migration file that creates a example-plugin table with various columns:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::create('example_plugin', function (Blueprint $table) {
$table->id(); // Auto-incrementing ID
$table->string('title'); // Example plugin title
$table->string('slug')->unique(); // URL-friendly slug
$table->text('description')->nullable(); // Main content
$table->string('short_description', 500)->nullable(); // Brief excerpt
$table->string('featured_image')->nullable(); // Featured image path
$table->string('banner_image')->nullable(); // Banner image path
$table->date('post_date')->nullable(); // Publication date
$table->string('author')->nullable(); // Author name
$table->boolean('status')->default(1); // Publication status
$table->integer('created_by')->nullable(); // User who created
$table->integer('updated_by')->nullable(); // User who updated
$table->softDeletes(); // Soft delete support
$table->timestamps(); // Created/Updated timestamps
});
}
public function down()
{
Schema::dropIfExists('example_plugin');
}
};
Once your migration is ready, run the following command to apply (migrate) it to the database:
php artisan migrate --path=sits/plugins/example-plugin/database/migrations
This migration demonstrates common column types and modifiers used in Laravel migrations:
id()- Creates an auto-incrementing primary keystring()- Creates VARCHAR columns with optional lengthtext()- Creates TEXT columns for longer contentboolean()- Creates BOOLEAN columns with defaultsinteger()- Creates INT columns for numeric valuestimestamps()- Adds created_at and updated_at columnssoftDeletes()- Adds deleted_at column for soft deletes
# Helpers/
The helpers folder contains helper functions and utility methods used across the plugin.
Here's an example of a typical helper file:
sits/plugins/example-plugin/helpers/example-plugin.php
if (!function_exists('example_plugin_setting')) {
/**
* Get example plugin setting value
* @param string $key
* @param mixed $default
* @return mixed
*/
function example_plugin_setting($key, $default = null) {
return setting('example_plugin_' . $key, $default);
}
}
if (!function_exists('get_example_plugins')) {
/**
* Get list of example plugins
* @param array $params
* @return Collection
*/
function get_example_plugins($params = []) {
return app(ExamplepluginInterface::class)->getAll($params);
}
}
if (!function_exists('get_example_plugin_by_id')) {
/**
* Get example plugin by ID
* @param int $id
* @return Exampleplugin|null
*/
function get_example_plugin_by_id($id) {
return app(ExamplepluginInterface::class)->findById($id);
}
}
if (!function_exists('format_example_date')) {
/**
* Format date for example plugin
* @param string $date
* @param string $format
* @return string
*/
function format_example_date($date, $format = 'Y-m-d') {
return date($format, strtotime($date));
}
}
- The helper functions are automatically loaded and available as soon as you activate the plugin - no extra configuration needed!
# Resources/
The resources folder contains the views, assets and other frontend resources for the plugin.
Here's an example of a typical resource file:
sits/plugins/example-plugin/resources/views/example-plugin/index.blade.php
Here's an example of a typical index.blade.php view file:
@extends('sits/base::master')
@section('table-filter-view')
<div class="grid grid-cols-2 md:grid-cols-5 lg:grid-cols-5 gap-4">
{{-- Status Filter --}}
<div class="form-group">
<label for="status" class="form-label">Status</label>
<select name="status" id="status" class="form-control filterTable">
<option value="all" selected>All</option>
<option value="publish">{{ getStatus(1) }}</option>
<option value="draft">{{ getStatus(0) }}</option>
</select>
</div>
{{-- Date Range Filter --}}
<div class="form-group">
<div>
<label for="created_at_date_range" class="form-label">Date Range</label>
<input class="form-control py-2 flatpickr filterTable"
name="created_at_date_range"
id="created_at_date_range"
data-mode="range"
type="text"
placeholder="Select date range">
</div>
</div>
{{-- Apply Button --}}
<div class="form-group content-end w-6/12">
<div class="datatable-filter-wrapper">
<button type="button" class="form-control bg-blue-600 text-white filter-apply-btn">
Apply
</button>
</div>
</div>
</div>
@endsection
@section('content')
<div class="content-wrapper transition-all duration-150" id="content_wrapper">
<div class="container-fluid" id="page_layout">
<div id="content_layout">
<div class="space-y-5">
@include('sits/base::components.list-section', [
'tableId' => 'example-table',
'tableHeaders' => ['#', 'Title', 'Status', 'Created At', 'Action'],
'isExport' => true,
'isFilter' => true,
'isRecordTypeFilter' => true,
'isColumnVisibility' => true,
])
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
let columns = [
{
data: 'DT_RowIndex',
name: 'DT_RowIndex',
orderable: false,
searchable: false
},
{
data: 'title',
name: 'title',
searchable: true,
orderable: true
},
{
data: 'status_label',
name: 'status',
orderable: false,
searchable: false,
statusType: 'post'
},
{
data: 'created_at',
name: 'created_at',
orderable: true,
searchable: false
},
{
data: 'action',
name: 'action',
orderable: false,
searchable: false
}
];
SITS_TABLE({
id: '#example-table',
columns: columns
});
</script>
@endpush
This example shows a typical index view that:
- Extends the base master layout
- Includes filter sections for status and date ranges
- Uses the SITS table component for displaying data
- Configures DataTables columns and settings
# Controllers
Controllers define the logic for handling requests and responses for your plugin. They are located
in the src/Http/Controllers directory.
Example:
sits/plugins/example-plugin/src/Http/Controllers/ExamplepluginController.php
Here's an example of a typical controller for a example_plugin plugin:
namespace Sits\Exampleplugin\Http\Controllers;
use Sits\Exampleplugin\Models\Exampleplugin;
use Illuminate\Routing\Controller;
use Sits\ACL\Models\Administrator;
use Sits\Base\Traits\HasSitsDeleteAndRestore;
use Sits\Exampleplugin\Models\Exampleplugin;
use Yajra\DataTables\DataTables;
class ExamplepluginController extends Controller
{
use HasSitsDeleteAndRestore;
protected $page_title = "Exampleplugin";
protected $route_name = "admin.example_plugins.";
protected $view = "sits/example_plugin::example_plugins";
protected $table_name = "example_plugins";
public function __construct()
{
$shared_data = (object) [
'page_title' => $this->page_title,
'route_name' => $this->route_name,
'view' => $this->view,
'table_name' => $this->table_name,
'file_paths' => $this->eloquentModel()->file_paths,
];
view()->share('shared_data', $shared_data);
}
public function eloquentModel()
{
return new Modelname();
}
public function index()
{
if (request()->ajax()) {
$data = $this->eloquentModel()->with('category:id,name,deleted_at')
->select('id', 'title', 'slug', 'category_id', 'status', 'created_at')
->filterBy($value);
return DataTables::of($data)
->addIndexColumn()
->addColumn('action', fn($row) => getActionButtons($this->route_name, $row))
->make(true);
}
$example_plugin = Exampleplugin::select('id', 'name')->withCount('example_plugins')->get();
return view("{$this->view}.index", compact('example_plugin'));
}
public function validation($id = 0)
{
request()->validate([
'title' => "required|min:3|max:255|unique:{$this->table_name},title",
'description' => "required",
'status' => "required|in:0,1",
]);
}
public function store()
{
$this->validation();
$data = request()->only($this->eloquentModel()->fillable);
$result = $this->eloquentModel()->create($data);
return redirect()->route("{$this->route_name}index")
->with('success', 'Record created successfully');
}
}
This controller demonstrates common patterns used in SITS CMS plugins:
- Uses traits for common functionality like soft deletes
- Shares common data with all views via constructor
- Implements DataTables for AJAX-powered listings
- Includes standard CRUD operations with validation
- Follows RESTful controller conventions
# Models
Models define the data structure and business logic for your plugin. They are located in the
src/Models directory.
Example:
sits/plugins/example-plugin/src/Models/Exampleplugin.php
Here's an example of a typical model class for a example_plugin plugin:
namespace Sits\Exampleplugin\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Exampleplugin extends Model
{
use SoftDeletes, CreatedByUpdatedBy;
protected $table = "example_plugins";
protected $file_paths = [
'profile_path' => 'example_plugins/example'
];
protected $fillable = [
'title',
'slug',
'description',
'featured_image',
'status',
'category_id'
];
}
Key aspects of plugin models include:
- Use of traits for common functionality like soft deletes
- Clear definition of fillable fields
- Relationship methods to other models
- Helper methods for accessing and formatting data
- Custom accessors and mutators as needed
# Development Guidelines
- Use proper namespacing to avoid conflicts with other plugins
- Follow Laravel's coding standards and conventions
- Implement proper validation and error handling
- Create comprehensive documentation for your plugin
- Test your plugin thoroughly before deployment
- Keep plugin dependencies minimal and documented
On this Page
On this Page


