Documentation Plugin Development
When to use this skill
Use this skill when:
- Adding markdown-based documentation pages inside a Filament admin panel
- Configuring the documentation sidebar navigation, slug, and icons
- Writing documentation with YAML frontmatter and nested directories
- Setting up authorization for documentation access
- Customizing caching, link resolution, or markdown parsing
- Troubleshooting page rendering, navigation, or routing issues
Architecture
Namespace
JeffersonGoncalves\FilamentDocumentation
Key Classes
| Class | Path | Description |
|---|---|---|
FilamentDocumentationPlugin |
src/FilamentDocumentationPlugin.php |
Plugin class implementing Filament\Contracts\Plugin |
DocumentationPage |
src/Pages/DocumentationPage.php |
Filament page extending Filament\Pages\Page |
DocumentationParser |
src/Services/DocumentationParser.php |
Parses .md files with frontmatter, GFM, and heading permalinks |
NavigationBuilder |
src/Services/NavigationBuilder.php |
Builds sidebar navigation tree from the docs directory |
InstallCommand |
src/Commands/InstallCommand.php |
docs:install artisan command |
FilamentDocumentationServiceProvider |
src/FilamentDocumentationServiceProvider.php |
Service provider for config, views, commands |
Dependencies
filament/filament: ^5.0league/commonmark: ^2.4(Markdown parsing with GFM and extensions)spatie/yaml-front-matter: ^2.0(YAML frontmatter extraction)spatie/laravel-package-tools: ^1.16
Configuration
Install Command
php artisan docs:install
This command:
- Publishes the config file
- Optionally publishes example documentation files to
resources/docs/
Manual Publishing
# Config only
php artisan vendor:publish --tag=filament-documentation-config
# Example docs only
php artisan vendor:publish --tag=filament-documentation-docs
Config File
// config/filament-documentation.php
return [
'title' => env('DOCS_TITLE', 'Documentation'),
'docs_path' => resource_path('docs'),
'home' => 'home.md',
'cache_minutes' => env('DOCS_CACHE', 10), // 0 to disable
'login_route' => null,
];
Features
Plugin Registration
use JeffersonGoncalves\FilamentDocumentation\FilamentDocumentationPlugin;
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentDocumentationPlugin::make()
->slug('docs')
->navigationLabel('Documentation')
->navigationIcon('heroicon-o-book-open')
->navigationGroup('Help')
->navigationSort(99)
->withAuthorization(false),
]);
}
Plugin API Reference
| Method | Type | Default | Description |
|---|---|---|---|
slug(string $slug) |
string |
'docs' |
URL path: /admin/{slug} |
navigationLabel(string $label) |
string |
'Documentation' |
Sidebar label |
navigationIcon(string|BackedEnum $icon) |
string|BackedEnum |
Heroicon::OutlinedBookOpen |
Sidebar icon |
navigationGroup(?string $group) |
?string |
null |
Sidebar group |
navigationSort(int $sort) |
int |
99 |
Sort order |
withAuthorization(bool $enabled) |
bool |
false |
Enable viewDocumentation gate check |
Writing Documentation
Place .md files in resources/docs/ (configurable via docs_path).
Frontmatter
---
title: "Getting Started"
path: home
order: 1
---
| Key | Description |
|---|---|
title |
Page title (overrides first H1 heading) |
path |
Custom URL slug |
order |
Sort order in sidebar navigation |
Nested Directories
Subdirectories become collapsible groups in the sidebar:
resources/docs/
├── home.md
├── installation.md
├── configuration.md
└── advanced/
├── overview.md
├── authorization.md
└── customization.md
Directory names are formatted automatically: advanced becomes Advanced, getting-started becomes Getting Started.
Relative Links
Link between docs using relative .md paths -- they auto-convert to panel routes:
- [Installation](installation.md)
- [Advanced](advanced/overview.md)
Authorization
Enable authorization to restrict documentation access:
FilamentDocumentationPlugin::make()
->withAuthorization(true)
Then define a gate in your AuthServiceProvider or a policy:
use Illuminate\Support\Facades\Gate;
Gate::define('viewDocumentation', function ($user) {
return $user->hasRole('admin');
});
When authorization is enabled, DocumentationPage::canAccess() checks auth()->user()->can('viewDocumentation').
Internal Behavior
DocumentationParser
The parser uses League CommonMark with these extensions:
CommonMarkCoreExtension-- Standard MarkdownGithubFlavoredMarkdownExtension-- Tables, strikethrough, autolinks, task listsFrontMatterExtension-- YAML frontmatter extractionHeadingPermalinkExtension-- Anchor links on headings
Processing pipeline:
- Extract YAML frontmatter via regex
- Strip frontmatter from raw content
- Convert Markdown to HTML via
MarkdownConverter - Extract title from frontmatter or first H1
- Add
data-langattributes to code blocks for syntax highlighting - Convert relative
.mdlinks to panel routes viaDocumentationPage::getUrl()
Caching
// Cache key includes file path + modification time
$cacheKey = 'filament_docs_' . md5($filePath . filemtime($filePath));
// Cached for configured minutes (default: 10)
Cache::remember($cacheKey, now()->addMinutes($cacheMinutes), fn () => $this->parseFile($filePath));
Set DOCS_CACHE=0 to disable caching during development.
NavigationBuilder
Builds a recursive navigation tree by scanning the docs directory:
- Lists all
.mdfiles and subdirectories - Parses each file to extract title, order, path, and slug
- Subdirectories become
type: 'directory'nodes withchildren - Files become
type: 'file'nodes - Sorts by
order(from frontmatter, default:999) markActive()setsactiveandopenflags based on current slug
Navigation node structure:
[
'type' => 'file', // 'file' or 'directory'
'title' => 'Getting Started',
'slug' => 'home',
'order' => 1,
'path' => 'home',
'active' => true,
'children' => [],
]
DocumentationPage
The page component:
- Route:
{slug}/{pageSlug?}withwhere('pageSlug', '.*')for nested paths mount(): Resolves the default slug from confighomesetting, loads document and navigationnavigateTo(string $slug): Livewire method for SPA-like navigation withwindow.history.pushStateresolveFilePath(): Tries{slug}.mdfirst, then{slug}/index.md, then falls back tohome.md
File Resolution Order
// 1. Direct file match
$docsPath . '/' . $slug . '.md'
// 2. Directory index
$docsPath . '/' . $slug . '/index.md'
// 3. Fallback to home
$docsPath . '/' . config('filament-documentation.home', 'home.md')
Troubleshooting
Page Not Found / Shows "Page not found" Message
Cause: The .md file does not exist at the expected path.
Solution: Verify the file exists in resources/docs/ (or your configured docs_path). Check the slug matches the filename without .md extension.
Navigation Sidebar Empty
Cause: No .md files in the configured docs_path, or directory does not exist.
Solution: Run php artisan docs:install to publish example docs, or create .md files in resources/docs/.
Stale Content After Editing
Cause: Cached parsed content.
Solution: Set DOCS_CACHE=0 in .env during development, or clear cache with php artisan cache:clear.
Relative Links Not Working
Cause: Linked .md file does not exist, or path is outside the docs root.
Solution: Ensure the linked file exists and the relative path resolves within resources/docs/. The link converter uses realpath() and validates the result is within docs_path.
Authorization Blocking Access
Cause: withAuthorization(true) is enabled but no viewDocumentation gate is defined.
Solution: Define the gate in your AuthServiceProvider:
Gate::define('viewDocumentation', fn ($user) => true);
Route Conflicts
Cause: The slug conflicts with another Filament page route.
Solution: Change the slug: FilamentDocumentationPlugin::make()->slug('documentation').
Source: jeffersongoncalves/filament-documentation — distributed by TomeVault.