{{ $employee->name }}
{{ $employee->email }}
php artisan make:filament-page BestEmployeeEver
This command creates two files:
* ''app/Filament/Pages/BestEmployeeEver.php'' - The page class
* ''resources/views/filament/pages/best-employee-ever.blade.php'' - The view template
php artisan make:filament-page BestEmployeeEver --panel=admin
employee = User::find(42); // Replace with your ID
// Handle case where employee doesn't exist
if (!$this->employee) {
abort(404, 'Employee not found');
}
}
/**
* Optional: Pass data to the view
* Use this if you need additional processing
*/
protected function getViewData(): array
{
return [
'employee' => $this->employee,
// Add any other computed data here
];
}
}
==== Understanding the Page Class Properties ====
^ Property ^ Type ^ Purpose ^
| ''$navigationIcon'' | string | Icon from Heroicons (heroicon-o-* for outline, heroicon-s-* for solid) |
| ''$view'' | string | Path to Blade template (dots replace slashes) |
| ''$navigationLabel'' | string | Text shown in sidebar navigation |
| ''$title'' | string | Page heading displayed at top |
| ''$navigationGroup'' | string | Groups related pages in navigation |
| ''$navigationSort'' | int | Controls order in navigation (ascending) |
===== Step 3: Create the Blade View =====
Edit ''resources/views/filament/pages/best-employee-ever.blade.php'':
{{-- Hero Section with Employee Photo/Avatar --}}
@if($employee->avatar ?? null)
@else
{{ substr($employee->name, 0, 1) }}
@endif
{{ $employee->name }}
{{ $employee->email }}
{{-- Two Column Layout for Details --}}
{{-- Personal Information Card --}}
Personal Information
- Full Name
- {{ $employee->name }}
- Email
- {{ $employee->email }}
@if($employee->phone ?? null)
- Phone
- {{ $employee->phone }}
@endif
@if($employee->department ?? null)
- Department
- {{ $employee->department }}
@endif
{{-- Statistics Card --}}
Statistics
- Member Since
-
{{ $employee->created_at->format('F j, Y') }}
- Years of Service
-
{{ $employee->created_at->diffInYears(now()) }} years
- Total Projects
-
{{ $employee->projects->count() ?? 0 }}
{{-- Full Width Description Section --}}
Why This Employee is the Best
{{ $employee->bio ?? 'This employee has demonstrated exceptional performance, dedication, and commitment to excellence.' }}
==== Understanding the Blade Template ====
=== Main Wrapper ===
This component provides the standard Filament page layout with proper styling and dark mode support.
=== Filament CSS Classes ===
Filament uses specific CSS classes that integrate with its design system:
^ Class ^ Purpose ^
| ''fi-section'' | Container for content sections |
| ''fi-section-header'' | Header area of a section |
| ''fi-section-content'' | Content area of a section |
| ''space-y-6'' | Vertical spacing between elements |
| ''dark:bg-gray-900'' | Dark mode background |
| ''dark:text-white'' | Dark mode text color |
===== Step 4: Advanced Configurations =====
==== Hide from Navigation ====
If you want the page accessible via URL but not shown in the sidebar:
protected static bool $shouldRegisterNavigation = false;
==== Custom URL Slug ====
Change the URL path for the page:
protected static string $slug = 'our-best-employee';
// Access via: /admin/our-best-employee
==== Add Navigation Badge ====
Show a badge next to the navigation item:
public static function getNavigationBadge(): ?string
{
return 'Featured';
}
protected static ?string $navigationBadgeColor = 'success';
==== Restrict Access with Policies ====
Control who can view the page:
public static function canAccess(): bool
{
return auth()->user()->can('view_best_employee');
}
===== Step 5: Dynamic Employee ID Configuration =====
Instead of hardcoding the employee ID, use environment configuration:
==== Method 1: Environment Variable ====
Add to ''.env'':
BEST_EMPLOYEE_ID=42
In your page class:
public function mount(): void
{
$employeeId = env('BEST_EMPLOYEE_ID', 1);
$this->employee = User::find($employeeId);
}
==== Method 2: Config File ====
Add to ''config/app.php'':
'best_employee_id' => env('BEST_EMPLOYEE_ID', 1),
In your page class:
public function mount(): void
{
$this->employee = User::find(config('app.best_employee_id'));
}
==== Method 3: Database Setting ====
Create a settings table and fetch dynamically:
public function mount(): void
{
$employeeId = Setting::where('key', 'best_employee_id')->value('value');
$this->employee = User::find($employeeId);
}
===== Common Customizations =====
==== Display Related Data ====
Show related models (e.g., projects, tasks):
public function mount(): void
{
$this->employee = User::with(['projects', 'tasks', 'achievements'])
->find(42);
}
In your view:
@if($employee->projects->isNotEmpty())
Recent Projects
@foreach($employee->projects as $project)
- {{ $project->name }}
@endforeach
@endif
==== Add Computed Properties ====
Calculate data on-the-fly:
public function getCompletedProjectsProperty(): int
{
return $this->employee->projects()
->where('status', 'completed')
->count();
}
Access in view:
{{ $this->completedProjects }}
==== Add Actions/Buttons ====
Include interactive buttons:
// In your page class
use Filament\Actions\Action;
protected function getHeaderActions(): array
{
return [
Action::make('sendCongratulations')
->label('Send Congratulations')
->icon('heroicon-o-envelope')
->action(function () {
// Send email logic
Notification::make()
->title('Congratulations sent!')
->success()
->send();
}),
];
}
===== Troubleshooting =====
==== Page Not Appearing in Navigation ====
Check:
* ''$shouldRegisterNavigation'' is not set to ''false''
* User has proper permissions (''canAccess()'' method)
* Cache is cleared: ''php artisan filament:cache-components''
==== 404 Error When Accessing Page ====
* Verify the view file path matches the ''$view'' property
* Ensure the view file exists in the correct directory
* Check file naming (kebab-case in filesystem, dot notation in class)
==== Styling Issues ====
* Always wrap content in ''
company = Company::find(1);
if (!$this->company) {
abort(404, 'Company not found');
}
// Calculate statistics
$this->totalOrders = Order::count();
$this->totalRevenue = Order::sum('total_amount');
}
}
**View:** ''resources/views/filament/pages/company-stats.blade.php''
Company Name
{{ $company->name }}
Total Orders
{{ number_format($totalOrders) }}
Total Revenue
${{ number_format($totalRevenue, 2) }}
===== Additional Resources =====
* [[https://filamentphp.com/docs/3.x/panels/pages|Official Filament Pages Documentation]]
* [[https://heroicons.com/|Heroicons - Icon Library]]
* [[https://tailwindcss.com/docs|Tailwind CSS Documentation]]
===== Summary =====
To create a custom page displaying a single record in Filament v4:
- Generate page with ''php artisan make:filament-page''
- Configure the page class with navigation settings
- Fetch your specific record in the ''mount()'' method
- Create a Blade view using Filament's component and CSS classes
- Access the page via the navigation menu or direct URL
This pattern works for any scenario where you need to display predetermined, specific data outside of standard CRUD operations.