Creating Custom Addons
Learn how to create custom addons to extend Cockpit CMS functionality.
- Overview
- Basic Addon Structure
- Directory Structure
- Required Files
- 1. bootstrap.php
- 2. admin.php (Optional)
- 3. Controller/YourModule.php
- Addon Location
- Configuration
- Addon Configuration
- Access Configuration in Addon
- Events and Hooks
- Assets and Frontend Integration
- Asset Structure
- Loading Assets
- Permissions
- API Endpoints
- api.php
- Controller/Api.php
- Best Practices
- 1. Namespace Your Code
- 2. Check Permissions
- 3. Handle Configuration Gracefully
- 4. Use Proper Error Handling
- Next Steps
Overview
Cockpit CMS allows you to extend its functionality through custom addons. Addons are feature-rich extensions that can provide specific functionality, integrate with external services, and include their own dependencies.
Basic Addon Structure
Directory Structure
YourAddon/
|-- bootstrap.php # Addon initialization
|-- admin.php # Admin interface setup (optional)
|-- api.php # API endpoints (optional)
|-- icon.svg # Addon icon
|-- Controller/ # Controllers directory
| `-- YourAddon.php # Main controller
|-- Helper/ # Helper classes (optional)
| `-- YourAddon.php
|-- assets/ # Frontend assets (optional)
| |-- js/
| |-- css/
| `-- vue-components/
`-- views/ # View templates (optional)
`-- index.php
Required Files
1. bootstrap.php
The bootstrap.php
file is the entry point for your addon. It handles initialization and registers event listeners:
<?php
// Load admin interface when admin is initialized
$this->on('app.admin.init', function() {
include(__DIR__.'/admin.php');
});
// Extend the addon with custom methods
$this->module('youraddon')->extend([
'config' => function(?string $key = null, $default = null) {
$config = array_replace_recursive([
'enabled' => true,
'option1' => 'default_value',
'option2' => null
], $this->app->retrieve('youraddon', []) ?? []);
return $key ? ($config[$key] ?? $default) : $config;
},
'isEnabled' => function() {
return $this->config('enabled', true);
},
'customMethod' => function($param) {
// Your custom functionality
return $param;
}
]);
2. admin.php (Optional)
The admin.php
file sets up the admin interface integration:
<?php
// Only load for users with appropriate permissions
if ($this->helper('acl')->hasPermission('youraddon/manage')) {
// Bind controller to routes
$this->bindClass('YourAddon\\Controller\\YourAddon', '/youraddon');
// Add to settings menu
$this->on('app.settings.collect', function($settings) {
$settings['Extensions'][] = [
'icon' => 'youraddon:icon.svg',
'route' => '/youraddon',
'label' => 'Your Addon',
'permission' => 'youraddon/manage'
];
});
}
3. Controller/YourModule.php
The main controller handles HTTP requests:
<?php
namespace YourModule\Controller;
use App\Controller\Base;
class YourModule extends Base {
protected $layout = 'app:layouts/app.php';
public function before() {
// Check permissions
if (!$this->helper('acl')->hasPermission('youraddon/manage')) {
$this->stop(401);
}
}
public function index() {
return $this->render('youraddon:views/index.php', [
'config' => $this->module('youraddon')->config()
]);
}
public function save() {
// Handle form submissions
$data = $this->app->request->body;
// Validate and save configuration
$this->app->storage->setKey('youraddon', $data);
return ['success' => true];
}
}
Addon Location
Addons should be placed in /cockpit/addons/YourAddon/
Addons can include:
- External dependencies via Composer
- Custom helpers and services
- Complex initialization patterns
- Integration with external APIs
Configuration
Addon Configuration
Addons can read configuration from the main Cockpit configuration:
// In config/config.php
'youraddon' => [
'enabled' => true,
'api_endpoint' => 'https://api.example.com',
'timeout' => 30
]
Access Configuration in Addon
// In bootstrap.php
$this->module('youraddon')->extend([
'config' => function(?string $key = null, $default = null) {
$config = array_replace_recursive([
'enabled' => true,
'api_endpoint' => null,
'timeout' => 30
], $this->app->retrieve('youraddon', []) ?? []);
return $key ? ($config[$key] ?? $default) : $config;
}
]);
Events and Hooks
Cockpit provides various events you can hook into:
// Application events
$this->on('app.admin.init', function() {
// Admin interface initialization
});
$this->on('app.layout.init', function() {
// Layout initialization - add theme variables
$this->helper('theme')->vars('customVar', 'value');
});
// Content events
$this->on('content.save.before', function($name, &$data) {
// Modify data before saving
});
$this->on('content.save.after', function($name, $data) {
// React to content being saved
});
// User events
$this->on('app.user.login', function($user) {
// User logged in
});
Assets and Frontend Integration
Asset Structure
assets/
|-- js/
| `-- youraddon.js
|-- css/
| `-- youraddon.css
|-- vue-components/
| `-- your-component.js
`-- dialogs/
`-- your-dialog.js
Loading Assets
// In admin.php or views
$this->script([
'youraddon:assets/js/youraddon.js'
], 'youraddon');
$this->style([
'youraddon:assets/css/youraddon.css'
], 'youraddon');
Permissions
Define custom permissions for your addon:
// In admin.php
$this->helper('acl')->addPermissions([
'youraddon' => [
'manage' => 'Manage Your Addon',
'view' => 'View Your Addon Data',
'edit' => 'Edit Your Addon Settings'
]
]);
API Endpoints
Create REST API endpoints for your addon:
api.php
<?php
// API routes
$this->bindClass('YourAddon\\Controller\\Api', '/api/youraddon');
// Helper method for API access
$this->module('youraddon')->extend([
'getApiData' => function($params = []) {
// Return API data
return [];
}
]);
Controller/Api.php
<?php
namespace YourAddon\Controller;
use App\Controller\Base;
class Api extends Base {
public function data() {
// Return JSON data
return $this->module('youraddon')->getApiData(
$this->app->request->query
);
}
}
Best Practices
1. Namespace Your Code
Always use proper namespaces to avoid conflicts:
namespace YourAddon\Controller;
namespace YourAddon\Helper;
2. Check Permissions
Always verify user permissions:
if (!$this->helper('acl')->hasPermission('youraddon/manage')) {
$this->stop(401);
}
3. Handle Configuration Gracefully
Provide sensible defaults and validation:
'config' => function(?string $key = null, $default = null) {
$config = array_replace_recursive([
// Sensible defaults
'enabled' => true,
'timeout' => 30
], $this->app->retrieve('yourmodule', []) ?? []);
return $key ? ($config[$key] ?? $default) : $config;
}
4. Use Proper Error Handling
Handle errors gracefully:
try {
// Your code
} catch (Exception $e) {
$this->app->trigger('error', ['error' => $e->getMessage()]);
return ['error' => 'Operation failed'];
}
Next Steps
- Review addon implementations in
/cockpit/addons/
for advanced patterns - Check the Cockpit documentation for available helpers and APIs
- Test your addon thoroughly with different user permissions
- Consider using Composer for external dependencies
This guide covers the basic setup for creating custom addons. The modular architecture of Cockpit allows for extensive customization while maintaining clean separation of concerns.