Plugin Permissions
Define custom permissions for your plugin in plugin.json.
Permission Structure
{
"permissions": [
{
"id": "manage_plugin",
"label": "Manage Plugin",
"description": "Full access to plugin settings and configuration"
},
{
"id": "view_plugin_logs",
"label": "View Plugin Logs",
"description": "View plugin activity and error logs"
},
{
"id": "export_plugin_data",
"label": "Export Plugin Data",
"description": "Export plugin data to CSV or JSON"
}
]
}
Permission Properties
| Property | Type | Description |
|---|---|---|
id | string | Unique permission identifier |
label | string | Human-readable permission name |
description | string | Detailed explanation of what permission allows |
Checking Permissions
In routes and controllers, verify user permissions:
<?php
namespace MyVendor\MyPlugin\Http\Controllers;
use Illuminate\Http\Request;
class SettingsController
{
public function index(Request $request)
{
// Authorize user
$request->user()->authorize('my-plugin:manage_plugin');
// Get settings
$settings = get_plugin_settings('my-plugin');
return view('my-plugin::settings', ['settings' => $settings]);
}
public function store(Request $request)
{
// Authorize user
$request->user()->authorize('my-plugin:manage_plugin');
// Validate and save
$validated = $request->validate([
'api_key' => 'required|string',
'webhook_url' => 'required|url',
]);
save_plugin_settings('my-plugin', $validated);
return redirect()->back()->with('success', 'Settings saved');
}
}
Authorization Middleware
Create a custom middleware for permission checking:
<?php
namespace MyVendor\MyPlugin\Http\Middleware;
use Closure;
class CheckPluginPermission
{
public function handle($request, Closure $next, $permission)
{
if (!$request->user()->can('my-plugin:' . $permission)) {
abort(403, 'Unauthorized');
}
return $next($request);
}
}
Use in routes:
Route::middleware(['auth', 'check-plugin-permission:manage_plugin'])->group(function () {
Route::get('/admin/my-plugin/settings', 'SettingsController@index');
});
Role-Based Permissions
Assign permissions to roles:
// In plugin bootstrap or migration
$admin = Role::where('slug', 'administrator')->first();
$admin->attachPermissions([
'my-plugin:manage_plugin',
'my-plugin:view_plugin_logs',
'my-plugin:export_plugin_data',
]);
$editor = Role::where('slug', 'editor')->first();
$editor->attachPermission('my-plugin:view_plugin_logs');
Plugin Settings
Store plugin configuration in the database.
Default Settings
Define defaults in plugin.json:
{
"settings": {
"api_key": "",
"webhook_url": "",
"enable_notifications": true,
"max_retries": 3,
"timeout_seconds": 30
}
}
Getting Settings
// Get all settings
$settings = get_plugin_settings('my-plugin');
// Get specific setting
$apiKey = get_plugin_setting('my-plugin', 'api_key');
// Get with default value
$timeout = get_plugin_setting('my-plugin', 'timeout_seconds', 30);
Saving Settings
// Save all settings
save_plugin_settings('my-plugin', [
'api_key' => 'new-key',
'webhook_url' => 'https://example.com/webhook',
'enable_notifications' => false,
]);
// Update single setting
update_plugin_setting('my-plugin', 'api_key', 'updated-key');
Settings UI
Create a settings form in your view:
<form action="{{ route('my-plugin.settings.store') }}" method="POST">
@csrf
<div class="form-group">
<label for="api_key">API Key</label>
<input type="text" id="api_key" name="api_key" value="{{ $settings['api_key'] ?? '' }}" />
</div>
<div class="form-group">
<label for="webhook_url">Webhook URL</label>
<input type="url" id="webhook_url" name="webhook_url" value="{{ $settings['webhook_url'] ?? '' }}" />
</div>
<div class="form-group">
<label>
<input type="checkbox" name="enable_notifications" {{ ($settings['enable_notifications'] ?? false) ? 'checked' : '' }} />
Enable Notifications
</label>
</div>
<button type="submit">Save Settings</button>
</form>
Plugin Data Storage
Store plugin-specific data using Laravel models or the plugin data table.
Using Plugin Data Table
Store key-value data:
// Save data
save_plugin_data('my-plugin', 'key', 'value');
// Get data
$value = get_plugin_data('my-plugin', 'key');
// Delete data
delete_plugin_data('my-plugin', 'key');
// Get all data
$allData = get_plugin_data('my-plugin');
Using Eloquent Models
Create plugin models for structured data:
<?php
namespace MyVendor\MyPlugin\Models;
use Illuminate\Database\Eloquent\Model;
class PluginCampaign extends Model
{
protected $table = 'plugin_campaigns';
protected $fillable = ['plugin_id', 'name', 'config'];
protected $casts = ['config' => 'json'];
}
Database Migrations
Create tables in migrations:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePluginCampaignsTable extends Migration
{
public function up()
{
Schema::create('plugin_campaigns', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->json('config')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('plugin_campaigns');
}
}
Data Relationships
Link plugin data to core entities:
<?php
namespace MyVendor\MyPlugin\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PluginCampaign extends Model
{
protected $table = 'plugin_campaigns';
public function campaign(): BelongsTo
{
return $this->belongsTo(\App\Models\Campaign::class, 'campaign_id');
}
public function user(): BelongsTo
{
return $this->belongsTo(\App\Models\User::class, 'user_id');
}
}
Data Export & Cleanup
Implement data management for plugin lifecycle.
Exporting Data
Create export functionality:
<?php
namespace MyVendor\MyPlugin\Services;
use Illuminate\Support\Facades\Storage;
class ExportService
{
public function exportToCSV()
{
$campaigns = PluginCampaign::all();
$csv = "Name,Config\n";
foreach ($campaigns as $campaign) {
$csv .= "{$campaign->name}," . json_encode($campaign->config) . "\n";
}
$filename = 'plugin-export-' . now()->format('Y-m-d-His') . '.csv';
Storage::disk('local')->put("exports/{$filename}", $csv);
return "exports/{$filename}";
}
}
Cleanup on Uninstall
In your uninstall() method, clean up all data:
public function uninstall(): void
{
// Delete tables (via migrations rollback)
Artisan::call('migrate:rollback', [
'--path' => __DIR__ . '/../../database/migrations',
]);
// Clean plugin data
DB::table('plugin_data')->where('plugin', $this->getName())->delete();
// Delete exported files
Storage::disk('local')->deleteDirectory('plugins/' . $this->getName());
}
Best Practices
Security
- Validate inputs: Always validate settings and data from users
- Use CSRF tokens: Include
@csrfin all forms - Escape output: Use Laravel's escaping helpers
- Hash sensitive data: Use bcrypt for passwords, hash for API keys
Performance
- Cache settings: Cache plugin settings to avoid repeated database queries
- Index tables: Add indexes to frequently queried plugin data
- Paginate results: Use pagination for large data sets
Testing
Write tests for permissions and data access:
public function test_unauthorized_user_cannot_access_settings()
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/admin/my-plugin/settings');
$response->assertStatus(403);
}
Next Steps
- Hooks Reference — Plugin hooks
- Menus, Assets & Routes — UI integration
Still stuck?
Our support team is ready to help you get set up.

