{"id":23219203,"url":"https://github.com/solutionforest/filament-tree","last_synced_at":"2026-04-08T04:01:52.766Z","repository":{"id":153682600,"uuid":"621747124","full_name":"solutionforest/filament-tree","owner":"solutionforest","description":"Filament Tree is a plugin for Filament Admin that creates a model management page with a heritage tree structure view. This plugin can be used to create menus and more.","archived":false,"fork":false,"pushed_at":"2026-02-02T09:44:22.000Z","size":524,"stargazers_count":184,"open_issues_count":4,"forks_count":62,"subscribers_count":4,"default_branch":"4.x","last_synced_at":"2026-02-02T20:23:08.413Z","etag":null,"topics":["filament-plugin","filamentadmin","filamentphp","treeview"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solutionforest.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-03-31T09:49:39.000Z","updated_at":"2026-02-02T09:43:59.000Z","dependencies_parsed_at":"2023-11-22T05:23:38.609Z","dependency_job_id":"08c5a951-6007-4f44-af09-cb2d371f66fd","html_url":"https://github.com/solutionforest/filament-tree","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/solutionforest/filament-tree","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solutionforest%2Ffilament-tree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solutionforest%2Ffilament-tree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solutionforest%2Ffilament-tree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solutionforest%2Ffilament-tree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solutionforest","download_url":"https://codeload.github.com/solutionforest/filament-tree/tar.gz/refs/heads/4.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solutionforest%2Ffilament-tree/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31539229,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filament-plugin","filamentadmin","filamentphp","treeview"],"created_at":"2024-12-18T21:20:09.573Z","updated_at":"2026-04-08T04:01:52.758Z","avatar_url":"https://github.com/solutionforest.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!IMPORTANT]\n\u003e Please note that we will only be updating to version 4.x, excluding any bug fixes.\n\n# Filament Tree\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/solution-forest/filament-tree.svg?style=flat-square)](https://packagist.org/packages/solution-forest/filament-tree)\n[![Total Downloads](https://img.shields.io/packagist/dt/solution-forest/filament-tree.svg?style=flat-square)](https://packagist.org/packages/solution-forest/filament-tree)\n\nFilament Tree is a plugin for Filament Admin that creates hierarchical tree management with drag-and-drop functionality. Perfect for building menus, categories, organizational structures, and any nested data relationships.\n\n**🎯 Key Features:**\n\n- Drag-and-drop tree interface with unlimited depth\n- Support for Widgets, Pages, and Resources\n- Customizable actions, icons, and styling\n- Translation support with Spatie Translatable\n- Built-in create, edit, delete, and view actions\n- Toolbar actions for global operations\n\n**🚀 Demo:** [https://filament-cms-website-demo.solutionforest.net/admin](https://filament-cms-website-demo.solutionforest.net/admin)  \n**Credentials:** `demo@solutionforest.net` / `12345678` (Auto-reset every hour)\n\n## Version Compatibility\n\n| Filament Version | Plugin Version |\n| ---------------- | -------------- |\n| v3               | 2.x.x          |\n| v4               | 3.x.x          |\n| v5               | 4.x.x          |\n\n\u003e [!IMPORTANT]\n\u003e We only provide updates for versions 3.x, excluding bug fixes for older versions.\n\n## Installation\n\n1. **Install the package:**\n\n   ```bash\n   composer require solution-forest/filament-tree\n   ```\n\n2. **Publish and register assets:**\n\n   ```bash\n   php artisan filament:assets\n   ```\n\n3. **Publish configuration (optional):**\n\n   ```bash\n   php artisan vendor:publish --tag=\"filament-tree-config\"\n   ```\n\n4. **For custom themes:** Add to your `tailwind.config.js`:\n   ```css\n   @import '\u003cpath-to-vendor\u003e/solution-forest/filament-tree/resources/css/jquery.nestable.css';\n   @import '\u003cpath-to-vendor\u003e/solution-forest/filament-tree/resources/css/button.css';\n   @import '\u003cpath-to-vendor\u003e/solution-forest/filament-tree/resources/css/custom-nestable-item.css';\n   @source '\u003cpath-to-vendor\u003e/solution-forest/filament-tree/resources/**/*.blade.php';\n   ```\n\n## Quick Start\n\n### 1. Database Setup\n\nCreate your migration with the required tree structure:\n\n```php\nSchema::create('categories', function (Blueprint $table) {\n    $table-\u003eid();\n    $table-\u003etreeColumns(); // Adds parent_id, order, title columns\n    $table-\u003etimestamps();\n});\n\n// Or manually:\nSchema::create('categories', function (Blueprint $table) {\n    $table-\u003eid();\n    $table-\u003einteger('parent_id')-\u003edefault(-1)-\u003eindex(); // Must default to -1!\n    $table-\u003einteger('order')-\u003edefault(0);\n    $table-\u003estring('title');\n    $table-\u003etimestamps();\n});\n```\n\n### 2. Model Setup\n\nAdd the `ModelTree` trait to your Eloquent model:\n\n```php\n\u003c?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse SolutionForest\\FilamentTree\\Concern\\ModelTree;\n\nclass Category extends Model\n{\n    use ModelTree;\n\n    protected $fillable = ['parent_id', 'title', 'order'];\n\n    protected $casts = [\n        'parent_id' =\u003e 'integer'\n    ];\n}\n```\n\n### 3. Generate Tree Components\n\nChoose your implementation:\n\n```bash\n# For a standalone tree widget\nphp artisan make:filament-tree-widget CategoryWidget --model=Category\n\n# For a tree page\nphp artisan make:filament-tree-page CategoryTree --model=Category\n\n# For a resource tree page\nphp artisan make:filament-tree-page CategoryTree --resource=Category\n```\n\n![Tree Widget Example](https://github.com/user-attachments/assets/1f09d707-b6ac-4d68-9009-55dade707c43)\n\n![Tree Widget Example](https://github.com/user-attachments/assets/1f09d707-b6ac-4d68-9009-55dade707c43)\n\n## Implementation Options\n\n### Tree Widgets\n\nPerfect for embedding trees within existing resource pages or dashboard.\n\n**1. Generate the widget:**\n\n```bash\nphp artisan make:filament-tree-widget CategoryWidget --model=Category\n```\n\n**2. Configure the widget:**\n\n```php\n\u003c?php\n\nnamespace App\\Filament\\Widgets;\n\nuse App\\Models\\Category;\nuse Filament\\Forms\\Components\\TextInput;\nuse SolutionForest\\FilamentTree\\Widgets\\Tree as BaseWidget;\n\nclass CategoryWidget extends BaseWidget\n{\n    protected static string $model = Category::class;\n    protected static int $maxDepth = 3;\n    protected ?string $treeTitle = 'Categories';\n    protected bool $enableTreeTitle = true;\n\n    protected function getFormSchema(): array\n    {\n        return [\n            TextInput::make('title')-\u003erequired(),\n            // Add more form fields as needed\n        ];\n    }\n}\n```\n\n**3. Display in resource pages:**\n\n```php\n// In your resource's ListRecords page\nprotected function getHeaderWidgets(): array\n{\n    return [CategoryWidget::class];\n}\n```\n\n### Tree Pages\n\nStandalone pages dedicated to tree management.\n\n**1. Generate the page:**\n\n```bash\nphp artisan make:filament-tree-page CategoryTree --model=Category\n```\n\n**2. Register the page:**\n\n```php\n// In your PanelProvider\npublic function panel(Panel $panel): Panel\n{\n    return $panel\n        -\u003epages([\n            CategoryTree::class,\n        ]);\n}\n```\n\n### Resource Tree Pages\n\nIntegrated tree pages within Filament resources.\n\n**1. Generate for resource:**\n\n```bash\nphp artisan make:filament-tree-page CategoryTree --resource=Category\n```\n\n**2. Register in resource:**\n\n```php\n// In your CategoryResource\npublic static function getPages(): array\n{\n    return [\n        'index' =\u003e Pages\\ListCategories::route('/'),\n        'create' =\u003e Pages\\CreateCategory::route('/create'),\n        'edit' =\u003e Pages\\EditCategory::route('/{record}/edit'),\n        'tree' =\u003e Pages\\CategoryTree::route('/tree'), // Add this line\n    ];\n}\n```\n\n## Tree Customization\n\n### Record Display\n\nCustomize how records appear in the tree:\n\n**Custom record titles:**\n\n```php\npublic function getTreeRecordTitle(?\\Illuminate\\Database\\Eloquent\\Model $record = null): string\n{\n    if (!$record) return '';\n\n    return \"[{$record-\u003eid}] {$record-\u003etitle}\";\n}\n```\n\n**Record icons:**\n\n```php\npublic function getTreeRecordIcon(?\\Illuminate\\Database\\Eloquent\\Model $record = null): ?string\n{\n    if ($record-\u003eparent_id != -1) {\n        return null; // No icon for child records\n    }\n\n    return match ($record-\u003etitle) {\n        'Categories' =\u003e 'heroicon-o-tag',\n        'Products' =\u003e 'heroicon-o-shopping-bag',\n        'Settings' =\u003e 'heroicon-o-cog',\n        default =\u003e 'heroicon-o-folder',\n    };\n}\n```\n\n![Tree with Icons](https://github.com/user-attachments/assets/f5d2fcb8-f366-47e9-956d-6b81c8edd2ac)\n\n### Tree Actions\n\nConfigure actions that appear for each tree record:\n\n**Quick setup with boolean methods:**\n\n```php\nprotected function hasDeleteAction(): bool { return true; }\nprotected function hasEditAction(): bool { return true; }\nprotected function hasViewAction(): bool { return false; }\n```\n\n**Advanced action configuration:**\n\n```php\nprotected function configureEditAction(EditAction $action): EditAction\n{\n    return $action\n        -\u003eslideOver()\n        -\u003emodalHeading('Edit Category')\n        -\u003emodalSubmitActionLabel('Save Changes');\n}\n\nprotected function configureDeleteAction(DeleteAction $action): DeleteAction\n{\n    return $action\n        -\u003erequiresConfirmation()\n        -\u003emodalDescription('This will permanently delete the category and all subcategories.');\n}\n\nprotected function configureViewAction(ViewAction $action): ViewAction\n{\n    return $action\n        -\u003eslideOver()\n        -\u003emodalWidth('2xl');\n}\n```\n\n### Toolbar Actions\n\nAdd global actions displayed above the tree (v3.1.0+):\n\n```php\nprotected function getTreeToolbarActions(): array\n{\n    return [\n        \\SolutionForest\\FilamentTree\\Actions\\CreateAction::make()\n            -\u003elabel('Add Category')\n            -\u003eicon('heroicon-o-plus'),\n        \\Filament\\Actions\\ExportAction::make()\n            -\u003elabel('Export Tree'),\n        \\Filament\\Actions\\ImportAction::make()\n            -\u003elabel('Import Categories'),\n    ];\n}\n```\n\n\u003e **Note**: Toolbar actions are only supported in version 3.1.0 and later.\n\n### Icons and Styling\n\n**Tree depth control:**\n\n```php\nprotected static int $maxDepth = 4; // Limit nesting depth\n```\n\n**Node collapsed state:**\n\n```php\npublic function getNodeCollapsedState(?\\Illuminate\\Database\\Eloquent\\Model $record = null): bool\n{\n    return true; // Start with all nodes collapsed\n}\n```\n\n### Form Schemas\n\nDefine forms for different operations:\n\n```php\n// Used for all operations (fallback)\nprotected function getFormSchema(): array\n{\n    return [\n        TextInput::make('title')-\u003erequired(),\n        Textarea::make('description'),\n    ];\n}\n\n// Specific schemas for different actions\nprotected function getCreateFormSchema(): array { /* ... */ }\nprotected function getEditFormSchema(): array { /* ... */ }\nprotected function getViewFormSchema(): array { /* ... */ }\n```\n\n## Advanced Features\n\n### Translation Support\n\nIntegration with [Spatie Laravel Translatable](https://github.com/spatie/laravel-translatable):\n\n**1. Setup your model:**\n\n```php\nuse Filament\\Actions\\LocaleSwitcher;\nuse SolutionForest\\FilamentTree\\Concern\\ModelTree;\nuse Spatie\\Translatable\\HasTranslations;\n\nclass Category extends Model\n{\n    use HasTranslations, ModelTree;\n\n    protected $translatable = ['title'];\n}\n```\n\n**2. Configure your tree page:**\n\n```php\nuse SolutionForest\\FilamentTree\\Concern\\TreeRecords\\Translatable;\n\nclass CategoryTree extends TreePage\n{\n    use Translatable;\n\n    public function getTranslatableLocales(): array\n    {\n        return ['en', 'fr', 'es'];\n    }\n\n    protected function getActions(): array\n    {\n        return [LocaleSwitcher::make()];\n    }\n}\n```\n\n### Customizing Data Display in Tree Widgets\n\nFor advanced use cases, you may want to limit or customize the data displayed in your tree widget: for example, showing only items matching specific criteria or related to a parent resource.\n\nYou can achieve this by overriding the getTreeQuery method in your widget, allowing full control over the Eloquent query used to fetch records.\n\n```php\nuse App\\Models\\Menuitem;\nuse Illuminate\\Database\\Eloquent\\Builder;\nclass MenuItemsWidget extends Tree\n{\n    // Accessing the current record in the widget\n    public ?Model $record = null;\n\n    protected function getTreeQuery(): Builder\n    {\n        return MenuItem::query()\n            -\u003ewhere('menu_id', $this-\u003erecord?-\u003eid); // Filter by the current menu ID\n    }\n```\n\n### Custom Column Names\n\nOverride default column names if your table structure differs:\n\n```php\nclass Category extends Model\n{\n    use ModelTree;\n\n    public function determineOrderColumnName(): string\n    {\n        return 'sort_order'; // Instead of 'order'\n    }\n\n    public function determineParentColumnName(): string\n    {\n        return 'parent_category_id'; // Instead of 'parent_id'\n    }\n\n    public function determineTitleColumnName(): string\n    {\n        return 'name'; // Instead of 'title'\n    }\n\n    public static function defaultParentKey(): int\n    {\n        return 0; // Instead of -1\n    }\n}\n```\n\n### Node State Management\n\n**Performance optimization for large trees:**\n\n```php\n// Pre-collapse deep nodes to improve initial load\npublic function getNodeCollapsedState(?\\Illuminate\\Database\\Eloquent\\Model $record = null): bool\n{\n    return $record \u0026\u0026 $record-\u003egetDepth() \u003e 2;\n}\n\n// Custom tree depth per implementation\nprotected static int $maxDepth = 5;\n```\n\n**Conditional record display:**\n\n```php\npublic function getTreeRecordTitle(?\\Illuminate\\Database\\Eloquent\\Model $record = null): string\n{\n    if (!$record) return '';\n\n    $title = $record-\u003etitle;\n\n    // Add indicators\n    if ($record-\u003echildren()-\u003ecount() \u003e 0) {\n        $title .= \" ({$record-\u003echildren()-\u003ecount()})\";\n    }\n\n    if (!$record-\u003eis_active) {\n        $title = \"🚫 \" . $title;\n    }\n\n    return $title;\n}\n```\n\n## Configuration\n\nThe configuration file `config/filament-tree.php` allows you to customize default behavior:\n\n```php\n\u003c?php\n\nreturn [\n    /**\n     * Default column names for tree structure\n     */\n    'column_name' =\u003e [\n        'order' =\u003e 'order',\n        'parent' =\u003e 'parent_id',\n        'title' =\u003e 'title',\n    ],\n\n    /**\n     * Default parent ID for root nodes\n     */\n    'default_parent_id' =\u003e -1,\n\n    /**\n     * Default children relationship key\n     */\n    'default_children_key_name' =\u003e 'children',\n];\n```\n\n**Publish additional resources:**\n\n```bash\n# Publish views for customization\nphp artisan vendor:publish --tag=\"filament-tree-views\"\n\n# Publish translations\nphp artisan vendor:publish --tag=\"filament-tree-translations\"\n```\n\n## Best Practices\n\n### Database Design\n\n- **Always use `-1` as default for `parent_id`** - required for proper tree functionality\n- Index the `parent_id` and `order` columns for better performance\n- Consider adding `is_active` or `status` columns for soft filtering\n\n### Performance\n\n- Limit tree depth with `$maxDepth` for better user experience\n- Use eager loading when accessing tree relationships in custom code\n- Consider starting with collapsed nodes for large trees\n\n### User Experience\n\n- Provide clear icons to distinguish node types\n- Use descriptive action labels and confirmation dialogs\n- Group related toolbar actions logically\n\n### Development\n\n- Use the Artisan generators for consistent code structure\n- Extend configuration methods rather than overriding entire actions\n- Test with deeply nested data to ensure performance\n\n## Development\n\n### Frontend Build Process\n\n```bash\n# Development with watch mode\nnpm run dev\n\n# Production build\nnpm run build\n\n# CSS only\nnpm run build:styles\n\n# JavaScript only\nnpm run build:scripts\n```\n\n### Testing\n\n```bash\n# Run all tests\ncomposer test\n\n# Code analysis\ncomposer analyse\n\n# Code formatting\ncomposer lint\n```\n\n### Contributing\n\nSee [CONTRIBUTING](.github/CONTRIBUTING.md) for development guidelines.\n\n## Changelog\n\nSee the [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nSee [CONTRIBUTING](.github/CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nIf you discover any security related issues, please email info+package@solutionforest.net instead of using the issue tracker.\n\n## Credits\n\n- [Carly]\n- [All Contributors](../../contributors)\n\n## License\n\nFilament Tree is open-sourced software licensed under the [MIT license](LICENSE.md).\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://solutionforest.com\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/solutionforest/.github/blob/main/docs/images/sf.png?raw=true\" width=\"200\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n## About Solution Forest\n\n[Solution Forest](https://solutionforest.com) Web development agency based in Hong Kong. We help customers to solve their problems. We Love Open Soruces.\n\nWe have built a collection of best-in-class products:\n\n- [VantagoAds](https://vantagoads.com): A self manage Ads Server, Simplify Your Advertising Strategy.\n- [GatherPro.events](https://gatherpro.events): A Event Photos management tools, Streamline Your Event Photos.\n- [Website CMS Management](https://filamentphp.com/plugins/solution-forest-cms-website): Website CMS Management - Filament CMS Plugin\n- [Filaletter](https://filaletter.solutionforest.net): Filaletter - Filament Newsletter Plugin\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolutionforest%2Ffilament-tree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolutionforest%2Ffilament-tree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolutionforest%2Ffilament-tree/lists"}