Plugin Hooks

Add new API methods

Kanboard uses this library JSON-RPC to handle API calls.

To add a new method, you can do something like this from your plugin:

$this->api->getProcedureHandler()->withCallback('my_method', function() {
    return 'foobar';
});

$this->container['api'] or $this->api expose an instance of the object JsonRPC\Server.

Read the library documentation for more information.

Add new console commands

Kanboard uses the library Symfony Console to handle local command lines.

Kanboard exposes an instance of the object Symfony\Component\Console\Application via $this->cli. You can add new commands from your plugin:

$this->cli->add(new MyCommand());

Read the library documentation for more information.

Add new task filters

Since the task lexer is a factory that returns a new instance each time, you have to extend the taskLexer container with the method extend() of Pimple.

Here is an example:

public function initialize()
{
    $this->container->extend('taskLexer', function($taskLexer, $c) {
        $taskLexer->withFilter(TaskBoardDateFilter::getInstance($c)->setDateParser($c['dateParser']));
        return $taskLexer;
    });
}

For the filter class implementation, there are several examples in the source code under the namespace Kanboard\Filter.

Application Hooks

Hooks can extend, replace, filter data or change the default behavior. Each hook is identified with a unique name, example: controller:calendar:user:events

Listen on hook events

In your initialize() method you need to call the method on() of the class Kanboard\Core\Plugin\Hook:

$this->hook->on('hook_name', $callable);

The first argument is the name of the hook and the second is a PHP callable.

Hooks executed only once

Some hooks can have only one listener: model:subtask-time-tracking:calculate:time-spent

  • Override time spent calculation when sub-task timer is stopped
  • Arguments:
    • $user_id (integer)
    • $start (DateTime)
    • $end (DateTime)

Merge hooks

“Merge hooks” act in the same way as the function array_merge. The hook callback must return an array. This array will be merged with the default one.

Example to add events in the user calendar:

class Plugin extends Base
{
    public function initialize()
    {
        $container = $this->container;

        $this->hook->on('controller:calendar:user:events', function($user_id, $start, $end) use ($container) {
            $model = new SubtaskForecast($container);
            return $model->getCalendarEvents($user_id, $end); // Return new events
        });
    }
}

Example to override default values for task forms:

class Plugin extends Base
{
    public function initialize()
    {
        $this->hook->on('controller:task:form:default', function (array $default_values) {
            return empty($default_values['score']) ? array('score' => 4) : array();
        });
    }
}

List of merging hooks:

  • controller:task:form:default

    • Override default values for task forms
    • Arguments:
      • $default_values: actual default values (array)
  • controller:calendar:project:events

    • Add more events to the project calendar
    • Arguments:
      • $project_id (integer)
      • $start Calendar start date (string, ISO-8601 format)
      • $end Calendar end date (string, ISO-8601 format)
  • controller:calendar:user:events

    • Add more events to the user calendar
    • Arguments:
      • $user_id (integer)
      • $start Calendar start date (string, ISO-8601 format)
      • $end Calendar end date (string, ISO-8601 format)

Asset Hooks

Asset hooks can be used to add a new stylesheet easily or a new JavaScript file in the layout. You can use this feature to create a theme and override all Kanboard default styles.

Example to add a new stylesheet:

<?php

namespace Kanboard\Plugin\Css;

use Kanboard\Core\Plugin\Base;

class Plugin extends Base
{
    public function initialize()
    {
        $this->hook->on('template:layout:css', array('template' => 'plugins/Css/skin.css'));
    }
}

List of asset Hooks:

  • template:layout:css
  • template:layout:js

Reference hooks

Reference hooks are passing a variable by reference.

Example:

$this->hook->on('formatter:board:query', function (\PicoDb\Table &$query) {
    $query->eq(TaskModel::TABLE.'color_id', 'red');
});

The code above will show only tasks in red on the board.

List of reference hooks:

HookDescription
formatter:board:queryAlter database query before rendering board
pagination:dashboard:project:queryAlter database query for projects pagination on the dashboard
pagination:dashboard:task:queryAlter database query for tasks pagination on the dashboard
pagination:dashboard:subtask:queryAlter database query for subtasks pagination on the dashboard
model:task:creation:prepareAlter form values before to save a task
model:task:creation:aftersaveRetrieve Task ID after creating a task
model:task:modification:prepareAlter form values before to edit a task
model:task:duplication:aftersaveAfter task duplication
model:color:get-listAlter default_colors values
model:subtask:modification:prepareAlter form values before to save a subtask
model:subtask:creation:prepareAlter form values before to edit a subtask
model:subtask:count:queryAlter database query for subtask count

Template Hooks

Template hooks allow additional content in existing templates.

Example to add new content in the dashboard sidebar:

$this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/sidebar');

Example to attach a template with local variables:

$this->template->hook->attach('template:dashboard:sidebar', 'myplugin:dashboard/sidebar', [
    'variable' => 'foobar',
]);

Example to attach a template with a callable:

$this->template->hook->attachCallable('template:dashboard:sidebar', 'myplugin:dashboard/sidebar', function($hook_param1, $hook_param2) {
    return ['new_template_variable' => 'foobar']; // Inject a new variable into the plugin template
});

This call is usually defined in the initialize() method. The first argument is the name of the hook and the second argument is the template name.

Template names prefixed with the plugin name and colon indicate the location of the template.

Example with myplugin:dashboard/sidebar:

  • myplugin is the name of your plugin (lowercase)
  • dashboard/sidebar is the template name
  • On the filesystem, the plugin will be located here: plugins\Myplugin\Template\dashboard\sidebar.php
  • Templates are written in pure PHP (don’t forget to escape data)

Template names without prefix are core templates.

List of template hooks:

HookDescription
template:analytic:sidebarSidebar on analytic pages
template:app:filters-helper:beforeFilter helper dropdown (top)
template:app:filters-helper:afterFilter helper dropdown (bottom)
template:auth:login-form:beforeLogin page (top)
template:auth:login-form:afterLogin page (bottom)
template:board:private:task:before-titleTask in private board before title
template:board:private:task:after-titleTask in private board after title
template:board:public:task:before-titleTask in public board before title
template:board:public:task:after-titleTask in public board after title
template:board:task:footerTask in board: footer
template:board:task:iconsTask in board: tooltip icon
template:board:table:column:before-header-rowRow before board column header
template:board:table:column:after-header-rowRow after board column header
template:board:column:dropdownDropdown menu in board columns
template:board:column:headerBoard column header
template:board:tooltip:subtasks:header:before-assigneeHeader of Subtask table on tootip before Assignee
template:board:tooltip:subtasks:rowsColumn on row of Subtask table on tooltip
template:config:sidebarSidebar on settings page
template:config:applicationApplication settings form
template:config:boardBoard settings form
template:config:emailEmail settings page
template:config:integrationsIntegration page in global settings
template:dashboard:showMain page of the dashboard
template:dashboard:page-header:menuDashboard submenu
template:dashboard:project:after-titleDashboard project after title
template:dashboard:project:before-titleDashboard project before title
template:dashboard:show:after-filter-boxDashboard after filter box
template:dashboard:show:before-filter-boxDashboard before filter box
template:dashboard:task:footerTask in dashboard: footer
template:dashboard:sidebarDashboard sidebar
template:export:headerExport header
template:header:dropdownPage header dropdown menu (user avatar icon)
template:header:creation-dropdownPage header dropdown menu (plus icon)
template:layout:headPage layout <head/> tag
template:layout:topPage layout top header
template:layout:bottomPage layout footer
template:project:dropdown“Actions” menu on left in different project views
template:project:header:beforeProject filters (before)
template:project:header:afterProject filters (after)
template:project:integrationsIntegration page in projects settings
template:project:sidebarSidebar in project settings
template:project-user:sidebarSidebar on project user overview page
template:project-list:menu:beforeProject list: before menu entries
template:project-list:menu:afterProject list: after menu entries
template:project-overview:before-descriptionProject overview: before description
template:project-overview:images:dropdownProject overview: image dropdown
template:project-permission:after-adduserProject permission: after user
template:project-header:view-switcherProject view switcher
template:project-header:view-switcher-before-project-overviewProject view switcher before overview
template:project-header:view-switcher-before-board-viewProject view switcher before board
template:project-header:view-switcher-before-task-listProject view switcher before list
template:search:task:footerTask in results: footer
template:task:layout:topTask layout top (after page header)
template:task:details:topTask summary top
template:task:details:bottomTask summary bottom
template:task:details:first-columnTask summary first column
template:task:details:second-columnTask summary second column
template:task:details:third-columnTask summary third column
template:task:details:fourth-columnTask summary fourth column
template:task:dropdown:before-actionsTask dropdown: top of menu
template:task:dropdown:after-basic-actionsTask dropdown: after “add subtask”
template:task:dropdown:after-add-linksTask dropdown: after “add ext. link”
template:task:dropdown:after-add-commentTask dropdown: after “add comment”
template:task:dropdown:after-add-attachmentsTask dropdown: after “add screenshot”
template:task:dropdown:after-duplicate-taskTask dropdown: after “duplicate to …”
template:task:dropdown:after-send-mailTask dropdown: after “send by mail”
template:task:dropdownTask dropdown: bottom of menu
template:task:sidebar:informationTask sidebar: section information
template:task:sidebar:before-actionsTask sidebar: section actions: top
template:task:sidebar:after-basic-actionsTask sidebar: after “add subtask”
template:task:sidebar:after-add-linksTask sidebar: after “add ext. link”
template:task:sidebar:after-add-commentTask sidebar: after “add comment”
template:task:sidebar:after-add-attachmentsTask sidebar: after “add screenshot”
template:task:sidebar:after-duplicate-taskTask sidebar: after “duplicate to …”
template:task:sidebar:after-send-mailTask sidebar: after “send by mail”
template:task:sidebar:actionsTask sidebar: bottom Task image dropdown
template:task-file:images:before-thumbnail-descriptionTask image attachment desciption
template:task:form:first-column1st column in task form
template:task:form:second-column2nd column in task form
template:task:form:third-column3nd column in task form
template:task:form:bottom-before-buttonsbefore form submit/cancel buttons
template:task:show:topShow task page: top
template:task:show:bottomShow task page: bottom
template:task:show:before-descriptionShow task page: before description
template:task:show:before-tasklinksShow task page: before tasklinks
template:task:show:before-subtasksShow task page: before subtasks
template:task:show:before-external-linksShow task page: before external links
template:task:show:before-internal-linksShow task page: before internal links
template:task:show:before-timetrackingShow task page: before timetracking
template:task:show:before-attachmentsShow task page: before attachments
template:task:show:before-commentsShow task page: before comments
template:subtask:form:createCreate Subtask form
template:subtask:form:editEdit Subtask form
template:subtask:table:header:before-timetrackingSubtask table header before Time Tracking
template:subtask:table:rowsColumn on row of subtasks table
template:user:authentication:form“Edit authentication” form in user profile
template:user:create-remote:form“Create remote user” form
template:user:external“External authentication” page in user profile
template:user:integrationsIntegration page in user profile
template:user:sidebar:actionsSidebar in user profile (section actions)
template:user:sidebar:informationSidebar in user profile (section information)
template:user:show:profile:infoUser profile information