A comprehensive guide to the Advanced Kanban plugin for Filament 4.x
Advanced Kanban is a premium Filament PHP plugin that provides a production-ready, highly customizable Kanban board. It enables teams to visualize workflows, move tasks between statuses with drag & drop, and enhance productivity with rich actions, search, and filtering.
Advanced Kanban is perfect for:
Welcome to Advanced Kanban - Thank you for choosing our premium solution!
Advanced Kanban use AnyStack to provide you with payment processing, professional license management, and reliable software distribution.
During the purchasing process, AnyStack will provide you with a license key. You will also be asked by AnyStack to activate your license by providing a domain. This is usually the domain of where your final project will live. You'll use this same domain to install locally and in production. Once you have provided a domain, your license key will be activated and you can proceed with installing with composer below.
First, add the Advanced Kanban private repository to your composer.json file:
{ "repositories": [ { "type": "composer", "url": "https://filament-advanced-kanban.composer.sh" } ]}
Run the following command in your project root:
composer require asmit/advanced-kanban
During installation, you will be prompted to provide authentication credentials:
Loading composer repositories with package informationAuthentication required (filament-advanced-kanban.composer.sh):Username: [your-email-address]Password: [your-license-key]
Authentication Details:
Example: If your license details are:
john@example.com
8c21df8f-6273-4932-b4ba-8bcc723ef500
example.com
You would enter:
Username: john@example.comPassword: 8c21df8f-6273-4932-b4ba-8bcc723ef500:example.com
Important Notes:
Register the kanban builder on your Filament panel by adding it to the plugins array:
<?php use Asmit\AdvancedKanban\KanbanBuilder;use Filament\Panel; public function panel(Panel $panel): Panel{ return $panel ->plugins([ KanbanBuilder::make() // Other plugins if any ]);}
Run the following command to publish the required assets:
php artisan filament:assets
After completing the installation, you should be able to:
php artisan make:filament-page YourKanbanPage
KanbanPage class in your Filament pagesTo add a kanban board, create a new Filament page:
php artisan make:filament-page TasksKanban
The package provides a quick and easy way to set up a kanban board in your Filament admin panel. It assumes that you have title and description fields in your kanban card. Initially, it provides basic card design and functionality which includes title and description fields.
You can change these fields using the ->titleField() and ->descriptionField() methods.
Important: You must extend KanbanPage and provide the model and status field.
Note: Don't set a $view property - KanbanPage has its own view built-in.
<?php namespace App\Filament\Pages; use App\Models\Task;use Asmit\AdvancedKanban\Columns\KanbanColumn;use Asmit\AdvancedKanban\Pages\KanbanPage;use Asmit\AdvancedKanban\Kanban; class TasksKanban extends KanbanPage // ← Must extend KanbanPage{ // Other properties like $navigationIcon, $navigationGroup, etc. public function kanban(Kanban $kanban): Kanban { return $kanban ->model(Task::class) // ← Pass your model ->statusField('status') // ← Pass the status field ->columns([ KanbanColumn::make('todo') // ← Pass required column ->label('To Do'), KanbanColumn::make('in_progress') ->label('In Progress'), KanbanColumn::make('completed') ->label('Completed'), ]) ->searchableFields(['title', 'description']) ->recordsPerColumn(10); }}
Your kanban board is ready! The page will automatically appear in your Filament navigation and display your tasks organized by status columns.
Key Requirements:
KanbanPage
->model(YourModel::class)
->statusField('your_status_field')
$view - KanbanPage has its own viewA kanban board consists of:
Every kanban board requires:
public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(YourModel::class) // The model to display ->statusField('status') // The status field name ->columns([ // Define your columns KanbanColumn::make('todo')->label('To Do'), KanbanColumn::make('in_progress')->label('In Progress'), KanbanColumn::make('completed')->label('Completed'), ]);}
->model(Task::class)->model(\App\Models\Task::class)
->statusField('status')->statusField('state')->statusField('phase')
->titleField('title') // default title field->titleField('name')->titleField('subject') ->descriptionField('description') // default description field->descriptionField('content')->descriptionField('notes')
use Asmit\AdvancedKanban\Columns\KanbanColumn; ->columns([ KanbanColumn::make('todo') ->label('To Do') ->color('gray'), KanbanColumn::make('in_progress') ->label('In Progress') ->color('blue'), KanbanColumn::make('completed') ->label('Completed') ->color('green'),])
<?phpuse Asmit\AdvancedKanban\Columns\KanbanColumn; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->columns([ KanbanColumn::make('todo') ->label('To Do') ->color('gray'), KanbanColumn::make('in_progress') ->label('In Progress') ->color('blue'), KanbanColumn::make('completed') ->label('Completed') ->color('green'), ]);}
KanbanColumn::make('todo') ->label('To Do') ->color('green'); // Supports hex, rgb, hsl, and Tailwind colors
KanbanColumn::make('todo') ->label('To Do') -->icon(Heroicon::OutlinedRectangleStack) ->iconColor(Color::Red[500]) ->iconSize(IconSize::Medium); // Use any Heroicon name
KanbanColumn::make('todo') ->label('To Do') ->extraColumnHeadingClass('text-lg font-bold'); // Add custom classes
KanbanColumn::make('todo') ->label('To Do') ->description('Tasks that need to be started') ->color('gray');
Define allowed transitions between columns to control record movement:
use Asmit\AdvancedKanban\Columns\KanbanColumn; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->columns([ KanbanColumn::make('todo') ->label('To Do') ->allowedTransitions(['in_progress']), // Can only move to 'In Progress' KanbanColumn::make('in_progress') ->label('In Progress') ->allowedTransitions(['todo', 'review']), // Can move back to 'To Do' or forward to 'Review' KanbanColumn::make('review') ->label('Review') ->allowedTransitions(['in_progress', 'completed']), // Can move back to 'In Progress' or forward to 'Completed' KanbanColumn::make('completed') ->label('Completed') ->allowedTransitions([]), // No transitions allowed from 'Completed' ]);}
Lock cards in specific columns to prevent them from being moved:
use Asmit\AdvancedKanban\Columns\KanbanColumn; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->columns([ KanbanColumn::make('todo') ->label('To Do') ->lockCardUsing(fn($record) => $record->id === 1), // Lock specific record KanbanColumn::make('completed') ->label('Completed') ->lockCardUsing(fn($record) => true), // Lock all cards in this column ]);}
KanbanColumn::make('completed') ->label('Completed') ->lockCardUsing(fn($record) => true) ->lockedIcon('heroicon-o-lock-closed') // Use any Heroicon name ->lockLabel('Completed - Cannot be moved'); // Custom label for the lock icon
public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->searchableFields(['title', 'description', 'assignedTo.name']) // ← Add searchable fields here ->columns([ // Your columns here ]);}
<?phpuse Illuminate\Database\Eloquent\Builder; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->applySearchUsing(function(Builder $query, string $search) { return $query->where('title', 'like', '%' . $search . '%') ->orWhere('description', 'like', '%' . $search . '%') ->orWhereHas('assignedTo', function($q) use ($search) { $q->where('name', 'like', '%' . $search . '%'); }); }) ->columns([ // Your columns here ]);}
->enableLoadingIndicator()
Advanced Kanban does not provide built-in filters like other Filament resources. However, you can implement custom filtering logic in your kanban page.
<?phpuse Filament\Forms\Components\Select;use Illuminate\Contracts\Database\Eloquent\Builder; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->searchableFields(['title', 'description']) ->filterFormSchema([ Select::make('priority') ->options([ 'low' => 'Low', 'medium' => 'Medium', 'high' => 'High', ]) ->placeholder('All Priorities'), Select::make('assigned_to') ->options(User::pluck('name', 'id')) ->placeholder('All Users'), ]) ->applyFiltersUsing(function(Builder $query, array $data) { if (!empty($data['priority'])) { $query->where('priority', $data['priority']); } if (!empty($data['assigned_to'])) { $query->where('assigned_to', $data['assigned_to']); } return $query; }) ->columns([ // Your columns here ]);}
You can use Filament tabs to scope the Kanban board query, mirroring Filament's resource tabs behavior. Define tabs with modifyQueryUsing(...), and the active tab will automatically filter the Kanban data.
Resource/Relation Manager example:
use Asmit\AdvancedKanban\Concerns\HasKanbanRelatedRecords;use Asmit\AdvancedKanban\Contracts\HasKanban;use Filament\Schemas\Components\Tabs\Tab;use Illuminate\Database\Eloquent\Builder; class ManageProjectTask extends ManageRelatedRecords implements HasKanban{ use HasKanbanRelatedRecords; public function getTabs(): array { return [ 'all' => Tab::make(), 'complete' => Tab::make() ->modifyQueryUsing(fn (Builder $query) => $query->where('status', 'complete')), 'pending' => Tab::make() ->modifyQueryUsing(fn (Builder $query) => $query->where('status', 'pending')), ]; } public function kanban(Kanban $kanban): Kanban { return $kanban ->model(Task::class) ->statusField('status') // ... other Kanban config ; }}
Standalone Kanban page example:
use Asmit\AdvancedKanban\Pages\KanbanPage;use Filament\Resources\Concerns\HasTabs;use Filament\Schemas\Components\Tabs\Tab;use Illuminate\Database\Eloquent\Builder; class TaskKanban extends KanbanPage{ use HasTabs; public function getTabs(): array { return [ 'All' => Tab::make('All'), 'High Priority' => Tab::make('High Priority') ->modifyQueryUsing(fn (Builder $query) => $query->where('priority', 'high')), ]; } public function kanban(Kanban $kanban): Kanban { return $kanban ->model(Task::class) ->statusField('status') // ... other Kanban config ; }}
Notes:
Add actions to each record using the ->recordActions() method:
<?phpuse Asmit\AdvancedKanban\Kanban;use Asmit\AdvancedKanban\RecordAction\Action;use Asmit\AdvancedKanban\RecordAction\DeleteAction; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->recordActions([ Action::make('edit') ->label('Edit') ->icon('heroicon-o-pencil') ->action(fn($record) => $this->editTask($record)), Action::make('view') ->label('View') ->icon('heroicon-o-eye') ->action(fn($record) => $this->viewTask($record)) ->openUrlInNewTab(), ]) ->columns([ // Your columns here ]);}
use Asmit\AdvancedKanban\RecordAction\Action;use Asmit\AdvancedKanban\RecordAction\DeleteAction;use Asmit\AdvancedKanban\Actions\ActionGroup; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->recordActions([ Action::make('edit') ->label('Edit') ->icon('heroicon-o-pencil') ->action(fn($record) => $this->editTask($record)), ActionGroup::make([ Action::make('view') ->label('View Details') ->icon('heroicon-o-eye') ->action(fn($record) => $this->viewTask($record)), Action::make('duplicate') ->label('Duplicate') ->icon('heroicon-o-document-duplicate') ->action(fn($record) => $this->duplicateTask($record)), DeleteAction::make('delete') ->label('Delete') ->icon('heroicon-o-trash') ->color('danger') ->action(fn($record) => $this->deleteTask($record)), ]) ->label('More Actions') ->icon('heroicon-o-ellipsis-vertical') ->dropdownPlacement('bottom-end'), ]) ->columns([ // Your columns here ]);}
Add actions to column headers using the ->columnHeaderActions() method:
<?phpuse Filament\Actions\Action; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->columns([ // Your columns here ]) ->columnHeaderActions([ Action::make('add_task') ->label('Add Task') ->icon('heroicon-o-plus') ->color('primary') ->action(function($arguments) { // $arguments contains the current column status $this->addTaskToColumn($arguments['status']); }), ]);}
use Filament\Actions\Action;use Asmit\AdvancedKanban\Actions\ActionGroup; public function kanban(Kanban $kanban): Kanban{ return $kanban ->model(Task::class) ->statusField('status') ->columns([ // Your columns here ]) ->columnHeaderActions([ ActionGroup::make([ Action::make('add_task') ->label('Add Task') ->icon('heroicon-o-plus') ->action(fn($arguments) => $this->addTask($arguments['status'])), Action::make('bulk_edit') ->label('Bulk Edit') ->icon('heroicon-o-pencil') ->action(fn($arguments) => $this->bulkEdit($arguments['status'])), Action::make('export_column') ->label('Export Column') ->icon('heroicon-o-arrow-down-tray') ->action(fn($arguments) => $this->exportColumn($arguments['status'])), ]) ->label('More Actions') ->icon('heroicon-o-ellipsis-vertical') ->color('gray'), ]);}
The Kanban board is made up of two main components: Column Headers and Cards (Records). You can customize these components by generating your own components.
php artisan make:kanban-components --resource=YourResource
This command will create two Blade files in the resources/views/components/kanban/your-resource/ directory:
column-header.blade.php - Custom column header componentcard.blade.php - Custom card component<?php namespace App\Filament\Pages; use Asmit\AdvancedKanban\Pages\KanbanPage; class TasksKanban extends KanbanPage{ protected static string $columnHeaderComponent = 'kanban.tasks.column-header'; protected static string $cardComponent = 'kanban.tasks.card'; public function kanban(Kanban $kanban): Kanban { return $kanban ->model(Task::class) ->statusField('status') ->columns([ // Your columns here ]); }}
Override the handleRecordMove method in your Kanban page class:
<?php namespace App\Filament\Pages; use App\Models\Task;use Illuminate\Database\Eloquent\Model; class TasksKanban extends KanbanPage{ public function handleRecordMove(string $newStatus, Model $record): void { // Update the record's status $record->update(['status' => $newStatus]); // Log the move activity() ->performedOn($record) ->log("Task moved to {$newStatus}"); }}
public function beforeRecordMove(string $newStatus, Model $record): void{ // Perform actions before the record is moved if ($newStatus === 'completed') { // Validate that the task can be completed if (!$record->all_subtasks_completed) { throw new \Exception('Cannot complete task: all subtasks must be finished'); } } // Log the move attempt \Log::info("Attempting to move task {$record->id} to {$newStatus}");}
public function afterRecordMove(mixed $oldStatus, string $newStatus, Model $record): void{ // Perform actions after the record is moved if ($newStatus === 'completed') { // Send notification $record->assignee->notify(new TaskCompletedNotification($record)); // Update completion timestamp $record->update(['completed_at' => now()]); } // Log the successful move \Log::info("Task {$record->id} moved from {$oldStatus} to {$newStatus}");}
use Asmit\AdvancedKanban\Kanban; Kanban::make() ->modifyQueryUsing(function ($query) { return $query->where('is_active', true); });
use Asmit\AdvancedKanban\Columns\KanbanColumn; KanbanColumn::make() ->modifyRecordQueryUsing(function ($query) { return $query->where('status', 'to_do')->orderBy('created_at', 'asc'); });
Advanced Kanban provides render hooks that allow you to add custom views before the search and at the board footer.
KanbanRenderHook::KANBAN_SEARCH_BEFORE - Add content before the search barKanbanRenderHook::KANBAN_PAGE_FOOTER - Add content at the bottom of the pageIf you have a custom action that you would like to render inside a card component, call:
{{ $this->evaluateAction($this->yourAction(), ['recordId' => $record->getKey()]) }}
Example:
use Filament\Actions\Action;use Filament\Forms\Components\TextInput; public function addDocsAction(): Action{ return Action::make('docs') ->schema(function (array $arguments): array { return [ TextInput::make('title')->default($arguments['recordId']), ]; });}
Example:
{{ $this->evaluateAction($this->addDocsAction(), ['recordId' => $record->getKey()]) }}
| Method | Description | Parameters |
|---|---|---|
model() |
Set the Eloquent model for the kanban board | string|Model $model |
statusField() |
Set the status field name that determines column placement | string $field |
titleField() |
Set the title field name to display on cards | string $field |
descriptionField() |
Set the description field name to display on cards | string $field |
columns() |
Set the kanban columns configuration | array|Closure $columns |
searchableFields() |
Set fields that can be searched | bool|Closure $fields |
enableLoadingIndicator() |
Enable or disable loading indicator | Closure|bool $condition = true |
filterFormSchema() |
Set the filter form schema | array|Closure $schema |
recordActions() |
Set actions available on individual records | array|Closure $actions |
columnHeaderActions() |
Set actions available in column headers | array|Closure $actions |
recordsPerColumn() |
Set maximum number of records per column | int $count |
modifyQueryUsing() |
Modify the base query for fetching records | Closure $callback |
modifyRecordQueryUsing() |
Modify query for specific column records | Closure $callback |
applyFiltersUsing() |
Set custom filter application logic | Closure $callback |
applySearchUsing() |
Set custom search application logic | Closure $callback |
emptyStateMessage() |
Set custom empty state message | string $title, string $description |
| Method | Description | Parameters |
|---|---|---|
make() |
Create a new KanbanColumn instance | string $status |
label() |
Set the display label for the column | string|Closure $label |
description() |
Set the column description | string $description |
icon() |
Set the column icon | string|Closure|ScalableIcon $icon |
iconColor() |
Set the icon color | string|Closure $color |
hidden() |
Hide or show the column | bool|Closure $hidden = true |
allowedTransitions() |
Set allowed status transitions | array|Closure $transitions |
lockCardUsing() |
Set card locking condition | string|Closure $icon |
lockedIcon() |
Set locked icon | bool|Closure|ScalableIcon $icon = true |
lockedLabel() |
Set locked label | string|Closure $label = true |
modifyRecordQueryUsing() |
Modify query for column records | Closure $callback |
To manage related records in a kanban board, use the MRR (Manage Related Records) feature.
php artisan make:filament-page ManageUserTasks --resource=UserResource --type=ManageRelatedRecords``` #### 2. Implement HasKanban Interface```php<?php namespace App\Filament\Pages; use App\Filament\Resources\UserResource;use App\Models\Task;use Asmit\AdvancedKanban\Concerns\HasKanbanRelatedRecords;use Asmit\AdvancedKanban\Contracts\HasKanban;use Asmit\AdvancedKanban\Kanban;use Asmit\AdvancedKanban\Columns\KanbanColumn;use Filament\Resources\Pages\ManageRelatedRecords; class UserTasks extends ManageRelatedRecords implements HasKanban{ use HasKanbanRelatedRecords; // ← Must use this trait protected static string $resource = UserResource::class; // ← Set your resource protected static string $relationship = 'tasks'; // ← Set your relationship public function kanban(Kanban $kanban): Kanban { return $kanban ->model(Task::class) // ← Pass your model ->statusField('status') // ← Pass the status field ->titleField('title') ->descriptionField('description') ->columns([ KanbanColumn::make('To Do'), // ← Pass required column KanbanColumn::make('In Progress'), ]) ->searchableFields(['title', 'description']) ->recordsPerColumn(10); }}
Your MRR kanban board is ready! It will show only the related records for the current parent record.
Key Requirements for MRR:
HasKanban interfaceHasKanbanRelatedRecords trait$resource to your parent resource$relationship to your relationship name->model(YourModel::class)
->statusField('your_status_field')
⚠️ Important: This feature is not available for regular Relation Managers, only for MRR pages.
Issue: Package not found during installation
composer require asmit/advanced-kanban
Solution:
Issue: Assets not loading properly
php artisan filament:assets
Solution:
php artisan cache:clear
php artisan view:clear
Issue: Kanban page not appearing in navigation
Solution:
KanbanPage
Issue: Records not displaying in columns
Solution:
Issue: Slow loading with many records
Solution:
->recordsPerColumn()
"Column not found"
"Model not found"
Advanced Kanban is a premium plugin that requires a valid license for production use.
Advanced Kanban is designed to be flexible and powerful while remaining easy to use. Whether you're building a simple task board or a complex workflow system, these features provide the tools you need to create effective kanban boards.
For more information, examples, and community support, contact at mail2asmitnepali@gmail.com.
This documentation covers all the features and capabilities of Advanced Kanban. For the most up-to-date information, please refer to the official documentation and release notes.