The dashboard is direct orientation for this API: registered overview stats and Filament widgets resolve into its configured buckets.
Use this guide when a package or app needs to register dashboard Filament widgets, add overview stats, or adjust dashboard defaults in code. For the admin/operator view of the feature, see Admin dashboard Filament widgets.
| Need | Use |
|---|---|
| Add a compact metric to the Capell overview | CapellAdmin::registerOverviewStat(...) |
| Add a standalone Filament widget | CapellAdmin::registerDashboardFilamentWidget(...) |
| Register package admin surfaces through one bridge | AdminBridgeRegistrar::filamentDashboardWidget(...) or extensionDashboardFilamentWidget(...) |
| Add a widget to a resource or page surface | CapellAdmin::contributeToAdminSurface(...) or an AdminBridge |
| Supply labels/descriptions for dashboard settings | A class tagged with DashboardSettingsContributor::TAG |
| Read dashboard Filament widgets for a dashboard bucket | CapellAdmin::getDashboardFilamentWidgets($dashboard) |
| Filter legacy/core built-in widgets | CapellAdmin::getWidgets(...) |
Prefer overview stats for small package counters. Use a standalone dashboard Filament widget for tables, charts, calendars, health panels, setup panels, or anything with its own actions.
DashboardEnum controls where a widget can render:
<?php
declare(strict_types=1);
namespace Capell\Admin\Enums;
enum DashboardEnum: string
{
case Main = 'main';
case MarketingStudio = 'marketing_studio';
case Extensions = 'extensions';
case NotInstalled = 'not_installed';
case SystemHealth = 'system_health';
}Each bucket maps to an admin surface:
| Dashboard enum | Surface |
|---|---|
DashboardEnum::Main |
Installed admin dashboard at /admin. |
DashboardEnum::MarketingStudio |
Marketing Studio dashboard at /admin/marketing-studio. |
DashboardEnum::Extensions |
Extensions dashboard at /admin/extensions. |
DashboardEnum::SystemHealth |
Reserved for system-health dashboard integrations. |
DashboardEnum::NotInstalled |
Setup/empty state before Admin has an installed site. |
The main dashboard page is Capell\Admin\Filament\Pages\CapellDashboard.
Register against the most specific dashboard. Extension management widgets belong on DashboardEnum::Extensions; Marketing Studio widgets belong on DashboardEnum::MarketingStudio.
The Admin service provider and Filament plugin register the default dashboard Filament widgets. Registration decides which dashboard can use a widget. Settings decide whether a settings-gated widget is visible.
| Widget | Default state | Purpose |
|---|---|---|
CapellAccountFilamentWidget |
Enabled | Filament account welcome card. |
CapellInfoFilamentWidget |
Enabled | Filament version and documentation links. |
ListPagesFilamentWidget |
Enabled | Recently updated pages filtered by dashboard date range. |
RecentActivityFilamentWidget |
Enabled | Recent admin activity when activity exists for the site. |
UpdateAdvisoryFilamentWidget |
Enabled | Package/update advisory panel. |
MyWorkQueueFilamentWidget |
Available | Editor work queue from the configured data provider. |
RecentlyPublishedFilamentWidget |
Available | Recently published page list from the configured data provider. |
PageStatusFilamentWidget |
Available | Page status panel. |
SiteStatsOverviewFilamentWidget |
Available | Site stats overview. |
Resource pages can have their own alert widgets, such as page, site, blueprint, language, and theme alerts. Those widgets live on the resource screens rather than the main dashboard.
| Widget | Purpose |
|---|---|
MarketingStudioQuickActionsFilamentWidget |
Package-contributed marketing actions. |
MarketingStudioWorkQueueFilamentWidget |
Marketing work queue. |
MarketingStudioLaunchReadinessFilamentWidget |
Launch-readiness status. |
MarketingStudioTimelineFilamentWidget |
Marketing timeline. |
MarketingStudioAdvancedFilamentWidget |
Advanced marketing actions. |
| Widget | Purpose |
|---|---|
ExtensionStatsOverviewFilamentWidget |
Installed/uninstalled/attention/update/block counts. |
ExtensionHealthFilamentWidget |
Extension health summary. |
ExtensionDiagnosticsFilamentWidget |
Extension diagnostics. |
ExtensionUpdateReadinessFilamentWidget |
Update readiness checks. |
ExtensionDependencyGraphFilamentWidget |
Extension dependency graph. |
ExtensionRuntimeCompatibilityFilamentWidget |
Runtime compatibility checks. |
ExtensionActionsFilamentWidget |
Extension quick actions. |
RecentlyChangedExtensionsFilamentWidget |
Recent extension state changes. |
InstalledExtensionsFilamentWidget |
Installed extension table. |
FilamentWidgetEnum is the legacy/core list used by CapellAdmin::getWidgets(). Each enum value is a fully-qualified widget class name.
<?php
declare(strict_types=1);
namespace Capell\Admin\Enums;
enum FilamentWidgetEnum: string implements HasLabel
{
case AccountWidget = CapellAccountFilamentWidget::class;
case FilamentInfoWidget = CapellInfoFilamentWidget::class;
case ListPagesFilamentWidget = ListPagesFilamentWidget::class;
case MyWorkQueueFilamentWidget = MyWorkQueueFilamentWidget::class;
case PageStatusFilamentWidget = PageStatusFilamentWidget::class;
case RecentlyPublishedFilamentWidget = RecentlyPublishedFilamentWidget::class;
case SiteStatsOverviewFilamentWidget = SiteStatsOverviewFilamentWidget::class;
case UpdateAdvisoryFilamentWidget = UpdateAdvisoryFilamentWidget::class;
}Core dashboard pages now use registerDashboardFilamentWidget() plus widget settingsKey() values for layout settings. Add package-owned widgets through a service provider or admin bridge rather than adding new enum cases.
| Method | Use |
|---|---|
registerOverviewStat(...) |
Registers one small stat inside the Capell overview widget. Stats can share a settingsKey so one toggle controls a group. |
getOverviewStats(bool $onlyEnabled = true) |
Resolves registered overview stats for rendering. |
getOverviewStatKeys() |
Returns the unique settings keys used by registered overview stats. |
registerDashboardFilamentWidget(string $widgetClass, DashboardEnum ...$dashboards) |
Registers a Filament widget class with one or more dashboard buckets. |
getDashboardFilamentWidgets(DashboardEnum $dashboard) |
Returns registered widget classes for that dashboard, sorted by pinned/default/configured order. |
getWidgets(null|bool|Closure $filter = null) |
Returns legacy/core FilamentWidgetEnum widgets. Use null for all classes, true or false for enabled/disabled enum cases, or a callable filter. |
setEnabledWidgets(array<string|FilamentWidgetEnum> $widgets) |
Legacy helper for replacing the enabled set used by getWidgets(). Prefer settings-key based dashboard settings for new package widgets. |
registerDashboardFilamentWidget() only registers availability. Runtime visibility still depends on the widget's canView() method and, for settings-aware widgets, AdminSettings::enabled_widgets[$settingsKey].
Overview stats are best for small counts, percentages, current status values, and links into package resources.
<?php
declare(strict_types=1);
namespace Capell\Blog\Providers;
use Capell\Admin\Facades\CapellAdmin;
use Capell\Blog\Models\Article;
use Illuminate\Support\ServiceProvider;
final class AdminServiceProvider extends ServiceProvider
{
public function boot(): void
{
CapellAdmin::registerOverviewStat(
key: 'blog_overview.articles',
label: fn (): string => __('capell-blog::dashboard.articles'),
value: fn (): int => Article::query()->count(),
group: fn (): string => __('capell-blog::dashboard.group'),
description: fn (): string => __('capell-blog::dashboard.articles_description'),
sort: 100,
defaultEnabled: false,
settingsKey: 'blog_overview',
settingsLabel: fn (): string => __('capell-blog::dashboard.blog_overview'),
settingsDescription: fn (): string => __('capell-blog::dashboard.blog_overview_description'),
);
}
}Multiple stats can share the same settingsKey. The settings UI then shows one toggle while the overview widget renders every enabled stat in that group.
Create a Filament widget. Implement CapellFilamentWidgetContract and use GatedByRoleAndSettings when the widget should support dashboard settings and Capell role gating.
<?php
declare(strict_types=1);
namespace Vendor\Package\Filament\Widgets;
use Capell\Admin\Contracts\CapellFilamentWidgetContract;
use Capell\Admin\Filament\Concerns\GatedByRoleAndSettings;
use Filament\Widgets\Widget;
final class PackageStatusWidget extends Widget implements CapellFilamentWidgetContract
{
use GatedByRoleAndSettings;
/** @var list<string> */
protected static array $rolesConfigKeys = ['admin', 'super_admin'];
protected static string $settingsKey = 'vendor_package.status';
protected static ?int $sort = 80;
protected string $view = 'vendor-package::widgets.status';
}Then register the widget in a service provider:
<?php
declare(strict_types=1);
namespace Vendor\Package\Providers;
use Capell\Admin\Enums\DashboardEnum;
use Capell\Admin\Facades\CapellAdmin;
use Illuminate\Support\ServiceProvider;
use Vendor\Package\Filament\Widgets\PackageStatusWidget;
final class PackageServiceProvider extends ServiceProvider
{
public function boot(): void
{
CapellAdmin::registerDashboardFilamentWidget(PackageStatusWidget::class, DashboardEnum::Main);
}
}For extension-management widgets, use the bridge registrar when the package already has an admin bridge:
$registrar->extensionDashboardFilamentWidget(PackageStatusWidget::class);That registers the widget against DashboardEnum::Extensions.
Dashboard settings can infer labels from widget headings, but package docs and admin screens read better when widgets expose explicit metadata.
Use DashboardSettingsContributor to provide the label, group, and description for a widget settings key:
<?php
declare(strict_types=1);
namespace Vendor\Package\Admin;
use Capell\Admin\Contracts\DashboardSettingsContributor;
final class PackageDashboardSettingsContributor implements DashboardSettingsContributor
{
public function settingsKeys(): array
{
return [
[
'key' => 'vendor_package.status',
'label' => (string) __('vendor-package::dashboard.status_widget'),
'group' => (string) __('vendor-package::dashboard.group'),
'description' => (string) __('vendor-package::dashboard.status_widget_description'),
],
];
}
}Tag it from the package service provider:
$this->app->tag([PackageDashboardSettingsContributor::class], DashboardSettingsContributor::TAG);Use package-prefixed keys, for example vendor_package.status. If two contributors provide the same key, the later-loaded contributor wins.
Dashboard settings store two arrays on Capell\Admin\Settings\AdminSettings:
| Setting | Purpose |
|---|---|
enabled_widgets |
Boolean visibility by widget settings key, such as list_pages or extensions.stats. |
widget_order |
Sort order by widget settings key. |
Settings entries are discovered from:
- Registered dashboard Filament widgets that expose
settingsKey(). - Legacy built-in
FilamentWidgetEnumvalues. - Overview stat groups registered with
CapellAdmin::registerOverviewStat(). - Contributors tagged with
DashboardSettingsContributor::TAG.
Dashboard settings are normalised by SyncDashboardFilamentWidgetSettingsAction.
- Missing known keys are added to
enabled_widgets. - Keys in
AdminSettings::defaultWidgetOrder()are treated as default-enabled. - Package widgets that are known but not part of the default order are added as available, not force-enabled.
- Removed keys, such as retired legacy widgets, are cleaned up.
- If every known default was disabled during setup, the action can repair the default layout.
NormalizeDashboardFilamentWidgetSettingsAction handles submitted dashboard layout state. It updates only the keys for the dashboard being customised and preserves settings for other dashboards.
The built-in numeric settings (my_work_queue_limit, recently_published_limit, and friends) are documented on the admin Customize your dashboard page.
Avoid using setEnabledWidgets() for new package dashboards. It stores legacy enum/class values for getWidgets() and does not express the settings-key layout used by the current dashboard customiser.
Dashboard Filament widget order is resolved in this order:
- Widgets with negative Filament sort values stay pinned first.
AdminSettings::widget_order[$settingsKey]wins when present.- The widget's Filament sort value is used as the default.
- Class name order breaks ties.
Use a stable, package-prefixed settingsKey() before relying on configured order. Widgets without a settings key can render, but users cannot reliably enable, disable, or reorder them through the dashboard settings UI.
If canView() and widget hydration need the same expensive data, put that lookup behind AdminDashboardDataRequestCache or a package equivalent. Visibility checks run before rendering, so repeating the same queries there can make dashboards feel slow.
| File | Purpose |
|---|---|
../src/Filament/Pages/CapellDashboard.php |
Main dashboard page and date filter. |
../src/Support/CapellAdminManager.php |
Widget and overview stat registration. |
../src/Enums/DashboardEnum.php |
Dashboard buckets. |
../src/Enums/FilamentWidgetEnum.php |
Legacy/core built-in widget enum. |
../src/Settings/AdminSettings.php |
Stored dashboard settings. |
../src/Filament/Settings/Schemas/DashboardSettingsSchema.php |
Settings UI metadata aggregation. |
../src/Actions/SyncDashboardFilamentWidgetSettingsAction.php |
Default setting repair/sync. |
../src/Actions/NormalizeDashboardFilamentWidgetSettingsAction.php |
Dashboard layout normalisation. |
../src/Contracts/DashboardSettingsContributor.php |
Settings metadata contribution contract. |
