Plugin Registration
Project Skeleton Generator
You can use cookiecutter
to automatically create the project structure for your plugin.
Install Cookiecutter
pip install -U cookiecutter
Run Kanboard Cookiecutter
cookiecutter gh:kanboard/cookiecutter-plugin
plugin_name [My Plugin]: Some Plugin
plugin_namespace [MyPlugin]: SomePlugin
plugin_author [Plugin Author]: Me
plugin_description [My plugin is awesome]:
plugin_homepage [https://github.com/kanboard/plugin-myplugin]:
Directory Structure
Plugins are stored in the plugins
subdirectory. Below is an example of a plugin directory structure:
plugins
└── Budget <= Plugin name
├── Asset <= JavaScript/CSS files
├── Controller
├── LICENSE <= Plugin license
├── Locale
│ ├── fr_FR
│ ├── it_IT
│ ├── ja_JP
│ └── zh_CN
├── Model
├── Plugin.php <= Plugin registration file
├── README.md
├── Schema <= Database migrations
├── Template
└── Test <= Unit tests
Only the registration file Plugin.php
is required. Other folders are optional.
The first letter of the plugin name must be capitalized.
Plugin Registration File
Kanboard scans the plugins
directory and automatically loads everything under it. The file Plugin.php
is used to load and register the plugin.
Example of a Plugin.php
file (plugins/Foobar/Plugin.php
):
<?php
namespace Kanboard\Plugin\Foobar;
use Kanboard\Core\Plugin\Base;
class Plugin extends Base
{
public function initialize()
{
$this->template->hook->attach('template:layout:head', 'theme:layout/head');
}
public function getCompatibleVersion()
{
// Examples:
// >=1.0.37
// <1.0.37
// <=1.0.37
return '1.0.37';
}
}
This file must contain a Plugin
class defined under the namespace Kanboard\Plugin\Yourplugin
and extend Kanboard\Core\Plugin\Base
.
The only required method is initialize()
. This method is called for each request when the plugin is loaded.
Plugin Methods
Available methods from Kanboard\Core\Plugin\Base
:
initialize()
: Executed when the plugin is loaded.getClasses()
: Returns all classes that should be stored in the dependency injection container.on($event, $callback)
: Listens to internal events.getPluginName()
: Returns the plugin name (must match theplugins.json
"title":
entry for “Plugin Directory” version update notifications to work).getPluginAuthor()
: Returns the plugin author.getPluginVersion()
: Returns the plugin version.getPluginDescription()
: Returns the plugin description.getPluginHomepage()
: Returns the plugin homepage (link).setContentSecurityPolicy(array $rules)
: Overrides default HTTP CSP rules.onStartup()
: If present, this method is executed automatically when the eventapp.bootstrap
is triggered.getCompatibleVersion()
: Specifies the Kanboard version compatible with the plugin.
Your plugin registration class can also inherit from Kanboard\Core\Base
, allowing you to access all classes and methods of Kanboard easily.
For example, to fetch user #123:
$this->user->getById(123);
Plugin Translations
Plugins can be translated in the same way as the rest of the application. You must load the translations yourself when the session is created:
public function onStartup()
{
Translator::load($this->languageModel->getCurrentLanguage(), __DIR__.'/Locale');
}
Translations must be stored in the file plugins/Myplugin/Locale/xx_XX/translations.php
(replace xx_XX
with the language code, e.g., fr_FR
, en_US
).
Translations are stored in a dictionary. To override an existing string, use the same key in your translation file.
Dependency Injection Container
Kanboard uses Pimple, a simple PHP Dependency Injection Container. However, Kanboard can easily register any class in the container.
These classes are available throughout the application, and only one instance is created.
Here is an example of registering your own models in the container:
public function getClasses()
{
return array(
'Plugin\Budget\Model' => array(
'HourlyRateModel',
'BudgetModel',
)
);
}
Now, if you use a class that extends Core\Base
, you can directly access those class instances:
$this->hourlyRateModel->remove(123);
$this->budgetModel->getDailyBudgetBreakdown(456);
// This is equivalent to using the container:
$this->container['hourlyRateModel']->getAll();
Keys in the container are unique across the application. If you override an existing class, you will change its default behavior.