Plugin Registration
Project skeleton generator
You can use cookiecutter
to create the project structure of your
plugin automatically.
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. 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 will scan the directory plugins
and load automatically
everything under this directory. The file Plugin.php
is used to load
and register the plugin.
Example of 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 should contain a class Plugin
defined under the namespace Kanboard\Plugin\Yourplugin
and extends 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 loadedgetClasses()
: Return all classes that should be stored in the dependency injection containeron($event, $callback)
: Listen on internal eventsgetPluginName()
: Should return plugin name (must match plugins.json"title":
entry for “Plugin Directory” version update notifications to work)getPluginAuthor()
: Should return plugin authorgetPluginVersion()
: Should return plugin versiongetPluginDescription()
: Should return plugin descriptiongetPluginHomepage()
: Should return plugin Homepage (link)setContentSecurityPolicy(array $rules)
: Override default HTTP CSP rulesonStartup()
: If present, this method is executed automatically when the event “app.bootstrap” is triggeredgetCompatibleVersion()
: You may want to specify the Kanboard version compatible with the plugin
Your plugin registration class can also inherit from Kanboard\Core\Base
, that way you can access all classes and methods of Kanboard easily.
This example will fetch the user #123:
$this->user->getById(123);
Plugin Translations
Plugin 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');
}
The translations must be stored in the file plugins/Myplugin/Locale/xx_XX/translations.php
(replace xx_XX
by the language code fr_FR
, en_US
…).
Translations are stored in a dictionary, if you would like to override an existing string, you just need to use the same key in your translation file.
Dependency Injection Container
Kanboard uses Pimple, a simple PHP Dependency Injection Container. However, Kanboard can register any class in the container easily.
Those classes are available everywhere in the application and only one instance is created.
Here an example to register 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 from Core\Base
, you can access
directly to those class instance:
$this->hourlyRateModel->remove(123);
$this->budgetModel->getDailyBudgetBreakdown(456);
// It's the same thing as using the container:
$this->container['hourlyRateModel']->getAll();
Keys of the containers are unique across the application. If you override an existing class, you will change the default behavior.