====== Creating Custom Pages in Filament v4 to Display Single Records ====== ===== Overview ===== This guide explains how to create custom pages in Filament v4 that display a single, predetermined record. This is useful when you need to show specific data that doesn't fit the standard CRUD pattern, such as: * Featured employee/user profiles * System configuration displays * Dashboard-style pages with specific data * Report pages for particular records ===== Prerequisites ===== * Laravel application with Filament v4 installed * Basic understanding of Laravel Blade templates * Familiarity with Eloquent models ===== Step 1: Generate the Custom Page ===== Use Artisan to generate a new Filament page: 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 If you're using a custom panel (not the default admin panel), add the panel name: php artisan make:filament-page BestEmployeeEver --panel=admin ===== Step 2: Configure the Page Class ===== Open ''app/Filament/Pages/BestEmployeeEver.php'' and configure it: 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) {{ $employee->name }} @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 '''' * Use Filament's CSS classes (''fi-section'', etc.) for consistency * Check dark mode classes are included (''dark:*'') ==== Data Not Loading ==== * Verify the ''mount()'' method is public * Check database connection and model relationships * Add error handling for missing records ===== Complete Working Example ===== Here's a full working example for a "Company Statistics" page: **Page Class:** ''app/Filament/Pages/CompanyStats.php'' 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.