#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'; // 常に赤バッジ
}
}
NavigationGroup でグループ化
// 📁 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を本番環境へデプロイするための最終確認と最適化を行います。