#09 FilamentPHP基礎

グローバル検索とナビゲーション——使いやすいUIを整える

グローバル検索とは

Filamentの管理画面の上部にある検索ボックスは、複数のリソースをまたいで横断検索できるグローバル検索機能です。有効にするとCMDキー(またはCtrl)を押しながらKを押してもアクセスできます。

┌─────────────────────────────────────┐
│ 🔍 検索...          ⌘K             │
└─────────────────────────────────────┘

globallySearchable を有効にする

リソースクラスに $globallySearchable = true を設定するか、getGlobalSearchResultTitle() を実装することで有効になります。

<?php
// 📁 app/Filament/Resources/PostResource.php

class PostResource extends Resource
{
    // グローバル検索の対象にする
    protected static bool $globallySearchable = true;

    // 検索結果に表示するタイトル
    public static function getGlobalSearchResultTitle(\Illuminate\Database\Eloquent\Model $record): string
    {
        return $record->title;
    }

    // 検索結果に表示する補足情報
    public static function getGlobalSearchResultDetails(\Illuminate\Database\Eloquent\Model $record): array
    {
        return [
            'カテゴリ' => $record->category?->name ?? '未分類',
            '公開'     => $record->is_published ? '公開済み' : '下書き',
        ];
    }

    // 検索結果をクリックしたときに開くページ
    public static function getGlobalSearchResultUrl(\Illuminate\Database\Eloquent\Model $record): ?string
    {
        return static::getUrl('edit', ['record' => $record]);
    }

    // グローバル検索で使用するアクション
    public static function getGlobalSearchResultActions(\Illuminate\Database\Eloquent\Model $record): array
    {
        return [
            \Filament\GlobalSearch\Actions\Action::make('edit')
                ->label('編集')
                ->url(static::getUrl('edit', ['record' => $record])),
        ];
    }
}

検索するカラムを指定

デフォルトではモデルのすべてのfillableカラムが対象になります。絞り込む場合は getGloballySearchableAttributes() を使います。

public static function getGloballySearchableAttributes(): array
{
    // タイトルと本文だけを検索対象にする
    return ['title', 'content'];
}

検索結果の最大件数

protected static int $globalSearchResultsLimit = 10; // デフォルトは50

ナビゲーションのカスタマイズ

getNavigationLabel / getNavigationIcon / getNavigationSort

class PostResource extends Resource
{
    // サイドバーに表示するラベル
    protected static ?string $navigationLabel = '記事管理';

    // アイコン(Heroicons v2)
    protected static ?string $navigationIcon = 'heroicon-o-document-text';

    // アクティブ時のアイコン
    protected static ?string $activeNavigationIcon = 'heroicon-s-document-text'; // solid版

    // 並び順(数値が小さいほど上)
    protected static ?int $navigationSort = 1;

    // 所属するナビゲーショングループ
    protected static ?string $navigationGroup = 'コンテンツ管理';
}

使えるHeroiconsは heroicon-o-*(Outline)と heroicon-s-*(Solid)の2種類があります。一覧は heroicons.com で確認できます。


ナビゲーションバッジ

サイドバーのメニュー項目の右側に数値バッジを表示できます。「未承認コメントが3件ある」などのUX改善に役立ちます。

class PostResource extends Resource
{
    // バッジに表示する値
    public static function getNavigationBadge(): ?string
    {
        // 下書き記事の数を表示
        $count = static::getModel()::where('is_published', false)->count();
        return $count > 0 ? (string) $count : null;
    }

    // バッジの色
    public static function getNavigationBadgeColor(): string | array | null
    {
        $count = static::getModel()::where('is_published', false)->count();
        return $count > 5 ? 'danger' : 'warning';
    }
}
class CommentResource extends Resource
{
    public static function getNavigationBadge(): ?string
    {
        $pending = \App\Models\Comment::where('is_approved', false)->count();
        return $pending > 0 ? (string) $pending : null;
    }

    public static function getNavigationBadgeColor(): string | array | null
    {
        return 'danger'; // 常に赤バッジ
    }
}

// 📁 app/Providers/Filament/AdminPanelProvider.php

use Filament\Navigation\NavigationGroup;

->navigationGroups([
    NavigationGroup::make()
        ->label('コンテンツ管理')
        ->icon('heroicon-o-document-text')
        ->collapsed(false),    // デフォルトで展開

    NavigationGroup::make()
        ->label('ユーザー管理')
        ->icon('heroicon-o-users')
        ->collapsed(),         // デフォルトで折りたたむ

    NavigationGroup::make()
        ->label('システム設定')
        ->icon('heroicon-o-cog-6-tooth')
        ->collapsed()
        ->collapsible(false),  // ユーザーが折りたためないようにする
])

PanelProvider でロゴ・カラー・フォントをカスタマイズ

// 📁 app/Providers/Filament/AdminPanelProvider.php

->brandName('My Blog Admin')          // ブランド名

->brandLogo(asset('images/logo.svg')) // ロゴ画像
->brandLogoHeight('2rem')             // ロゴの高さ

->favicon(asset('images/favicon.ico')) // ファビコン

->colors([
    // テーマカラー(primary)を変更
    'primary' => Color::Indigo,

    // カスタムカラー(16進数でも指定可能)
    'primary' => [
        50  => '238, 242, 255',
        100 => '224, 231, 255',
        200 => '199, 210, 254',
        300 => '165, 180, 252',
        400 => '129, 140, 248',
        500 => '99,  102, 241',
        600 => '79,  70,  229',
        700 => '67,  56,  202',
        800 => '55,  48,  163',
        900 => '49,  46,  129',
        950 => '30,  27,  75',
    ],
])

->font('Noto Sans JP')  // Google Fontsのフォント名

ダークモードを有効化

// 📁 app/Providers/Filament/AdminPanelProvider.php

->darkMode(true)   // ダークモードの切り替えボタンを表示

特定モードに固定する場合:

->darkMode(false)  // ダークモードボタンを非表示(ライトモード固定)

トップナビゲーションに変更

デフォルトはサイドバーナビゲーションですが、トップバーに変更できます。

// 📁 app/Providers/Filament/AdminPanelProvider.php

->topNavigation()  // トップナビゲーションに変更

ナビゲーション全体をカスタマイズ

NavigationItem を使って、リソース以外の外部リンクや静的ページをナビゲーションに追加できます。

// 📁 app/Providers/Filament/AdminPanelProvider.php

use Filament\Navigation\NavigationItem;

->navigationItems([
    NavigationItem::make('フロントページを開く')
        ->url('/', shouldOpenInNewTab: true)
        ->icon('heroicon-o-arrow-top-right-on-square')
        ->sort(99),

    NavigationItem::make('ドキュメント')
        ->url('https://filamentphp.com/docs', shouldOpenInNewTab: true)
        ->icon('heroicon-o-book-open')
        ->group('ヘルプ'),
])

ユーザーメニューをカスタマイズ

右上のユーザーアバターをクリックしたときのドロップダウンメニューに項目を追加できます。

// 📁 app/Providers/Filament/AdminPanelProvider.php

use Filament\Navigation\MenuItem;

->userMenuItems([
    MenuItem::make()
        ->label('プロフィール設定')
        ->url(fn () => route('filament.admin.pages.profile'))
        ->icon('heroicon-o-user-circle'),

    MenuItem::make()
        ->label('フロントページ')
        ->url('/')
        ->icon('heroicon-o-home')
        ->openUrlInNewTab(),

    'logout' => MenuItem::make()
        ->label('ログアウト'),
])

グローバル検索の見た目を整える完成例

最終的なPostResourceのグローバル検索設定をまとめます。

<?php
// 📁 app/Filament/Resources/PostResource.php

class PostResource extends Resource
{
    protected static ?string $model = Post::class;
    protected static ?string $navigationLabel = '記事';
    protected static ?string $navigationIcon  = 'heroicon-o-document-text';
    protected static ?string $navigationGroup = 'コンテンツ管理';
    protected static ?int    $navigationSort  = 1;

    // グローバル検索設定
    protected static bool $globallySearchable = true;
    protected static int  $globalSearchResultsLimit = 5;

    public static function getGloballySearchableAttributes(): array
    {
        return ['title'];
    }

    public static function getGlobalSearchResultTitle(\Illuminate\Database\Eloquent\Model $record): string
    {
        return $record->title;
    }

    public static function getGlobalSearchResultDetails(\Illuminate\Database\Eloquent\Model $record): array
    {
        return [
            'カテゴリ' => $record->category?->name ?? '未分類',
            '状態'     => $record->is_published ? '公開済み' : '下書き',
            '作成日'   => $record->created_at->format('Y/m/d'),
        ];
    }

    public static function getGlobalSearchResultUrl(\Illuminate\Database\Eloquent\Model $record): ?string
    {
        return static::getUrl('edit', ['record' => $record]);
    }

    // ナビゲーションバッジ
    public static function getNavigationBadge(): ?string
    {
        $count = static::getModel()::where('is_published', false)->count();
        return $count > 0 ? (string) $count : null;
    }

    public static function getNavigationBadgeColor(): string | array | null
    {
        return 'warning';
    }
}

まとめ

  • $globallySearchable = true でグローバル検索の対象にする
  • getGlobalSearchResultTitle() / getGlobalSearchResultDetails() で検索結果の表示内容を設定
  • getGloballySearchableAttributes() で検索対象カラムを絞り込む
  • getNavigationBadge() / getNavigationBadgeColor() でサイドバーのバッジを設定
  • getNavigationLabel() / getNavigationIcon() / getNavigationSort() でサイドバーの表示を制御
  • PanelProvider の ->brandLogo() / ->colors() / ->font() でテーマをカスタマイズ
  • ->darkMode(true) でダークモードトグルを有効化

次回はFilamentを本番環境へデプロイするための最終確認と最適化を行います。