The main dashboard (Dashboard, the landing page after login) is built from widgets — the plan card, quick actions, analytics summary, stat cards, recent-content lists, and feature-contributed cards. Sites choose which widgets appear via the Customize button in the page header, and enabled feature modules (E-Commerce, Online Booking, …) contribute their own cards automatically, so a paid install's dashboard gets richer without any per-site configuration.
What's on the dashboard
In default order:
| Widget | Key | Default | Contents |
|---|---|---|---|
| Your Plan | plan |
On | The install's Membership plan (Core (free) / Pro / …) with an Upgrade CTA for free installs and a Manage link to the Tools page. Admins only. |
| Quick Actions | quick_actions |
On | Shortcut buttons (New Page, New Post, Upload Media, …) with their own Customize modal (dashboard.quick_actions Setting). |
| Analytics | analytics |
On | 7-day page views, unique visitors, delta vs. the previous week, and a sparkline. Only when the Analytics feature is enabled. |
| Pages card | stat_pages |
On | Public page count. |
| Content card | stat_content |
On | Content-item count across all content types with a published / draft / unlisted / scheduled breakdown. |
| Form Submissions card | stat_submissions |
On | Submissions received in the last 7 days (the actionable number), with the form count as a sub-line. |
| Media card | stat_media |
On | Media library item count. |
| Users card | stat_users |
Off | User count — off by default because most small installs have 1–3 users. |
| Recent Content | recent_content |
On | Latest 5 content items across all types, with type + status badges and edit links. |
| Recently Updated Pages | recent_pages |
On | Latest 5 edited public pages with editor links. |
| Drafts Needing Attention | drafts |
On | Up to 5 unpublished/draft items across all types with an Edit & Publish shortcut. |
| Orders card | ecommerce_orders |
On | Paid orders + revenue over the last 7 days. Only while E-Commerce is enabled. |
| Appointments card | booking_today |
On | Today's confirmed appointments + the next upcoming one. Only while Online Booking is enabled. |
| Rentals card | venue_rentals |
On | Upcoming venue rentals (confirmed + awaiting payment), with the number of inquiries and quotes still waiting on staff as the sub-line — "no open inquiries" when the pipeline is clear. Only while Venue & Facility Rental is enabled. |
| Tickets card | ticketing_sales |
On | Tickets sold + ticket revenue over the last 7 days. Only while Event Ticketing is enabled. |
| Donations card | donations_recent |
On | Paid donations + amount over the last 7 days. Only while Donations is enabled. |
| Listings card | real_estate_listings |
On | Active listings + new leads over the last 7 days. Only while Real Estate is enabled. |
| Buyer activity card | real_estate_buyer_activity |
On | Visitors who saved at least one home + homes saved over the last 7 days. Only while Real Estate is enabled. |
| SEO Health card | seo_health |
On | The latest completed scan's 0–100 score with its health band. Only while the SEO Scanner is enabled. |
| Accessibility card | accessibility_issues |
Off | Issue count from the latest accessibility report. Off by default because reports are generated manually. |
| New Contacts card | crm_contacts |
On | CRM contacts added in the last 7 days + total. Only while CRM is enabled. |
| New Subscribers card | marketing_subscribers |
On | Marketing subscribers added in the last 7 days + active total. Only while Marketing is enabled. |
| Members card | memberships_members |
On | Active members + new sign-ups over the last 7 days. Only while Memberships is enabled. |
| Affiliate Sales card | affiliates_conversions |
On | Affiliate conversions + commission over the last 7 days. Only while Affiliates is enabled. |
| Popups card | popups_active |
On | Popups/bars active right now, with a scheduled-to-start count as the sub-line. Only while Popups & Announcement Bars is enabled. |
| Projects card | projects_open |
On | Open projects (in progress + on hold), with an overdue count as the sub-line — "All on track" when none. Only while Project Tracking is enabled. |
| Gift Cards card | gift_cards_outstanding |
On | Outstanding gift-card balance, with active card count + total store credit as the sub-line. Only while Gift Cards & Store Credit is enabled. |
| Loyalty card | loyalty_points |
On | Points outstanding across members. Only while Loyalty Points is enabled. |
| Server card | server_health |
On | 1-minute load average + free disk space, linking to the Server page. |
| Fleet card | fleet_installs |
On | Managed installs reporting in, with a count of those needing attention (behind the latest build, silent 30+ days, or failing the uptime probe) — "All installs healthy" when quiet. Links to the Fleet dashboard. Only on a fleet server (Membership::isFleetServer() — the license server, or the Enterprise Fleet Management feature), so it is invisible on ordinary installs rather than feature-gated. |
| AI Credits card | managed_ai_credits |
On | Managed-AI credit burned by the fleet this calendar month, with the number of installs it came from as the sub-line. Links to the AI rate card. Only where the install actually brokers managed AI (ManagedAi::enabled(), plus the rate-card route's own memberships-or-fleet any-of gate) and only for admins, matching that page's role:admin gate — so it is invisible on ordinary installs and to Managers. |
The CMS-update banner is not a widget — it always shows to admins when an update is pending.
Users below the Manager role see a minimal "You're logged in" screen instead of the widget dashboard.
Customizing
Dashboard → Customize (header button, Manager+) opens a checkbox modal listing every available widget. The selection is stored site-wide in the dashboard.widgets Setting (persisted in catalog order; unknown keys are dropped on save). When the Setting has never been saved, the default set above applies. Feature-gated widgets disappear from both the dashboard and the modal while their feature is off — and reappear, still honouring the saved selection, when it's turned back on.
Quick Actions keeps its own separate Customize modal (dashboard.quick_actions) for choosing which shortcut buttons appear inside that widget.
Free vs. paid installs
There is deliberately one dashboard, not a free and a paid variant. Tier differences express through feature flags:
- Free (Core) installs see the Your Plan card with an Upgrade button linking to
config('cms.pricing_url')(CMS_PRICING_URL, defaulthttps://www.webprocms.com/pricing). - Member installs see their tier (from the
membership.tierSetting, populated by the daily phone-home) and the renewal date when known. - Paid features contribute their widgets automatically when enabled, so a Pro install's dashboard differentiates itself without a separate layout.
For developers: contributing a widget from a feature module
Widgets live in app/Support/DashboardWidgetRegistry.php (a container singleton, same pattern as PresetRegistry). A feature module registers its card from its service provider — no blade partial needed; the dashboard renders it through the standard stat-card markup:
$this->app->afterResolving(DashboardWidgetRegistry::class, function (DashboardWidgetRegistry $registry): void {
$registry->register([
'key' => 'ecommerce_orders',
'label' => 'Orders card', // Customize-modal label; untranslated, the modal wraps it in __()
'feature' => 'ecommerce', // hidden while this feature flag is off
'icon' => 'shopping-bag', // heroicon shown in the card header
'title' => 'Orders', // card header; untranslated, the card wraps it in __()
'data' => fn (): array => [ // lazy; runs only when the card renders
'value' => number_format($count), // the big number
'subline' => __('…· last 7 days'), // optional small line under the number
'href' => route('dashboard.shop.orders'), // optional "See all →" target
],
]);
});
Requirements and options:
- The
datacallable runs on every dashboard render while the widget is visible — keep it to a couple of cheap queries. - Translate sublines inside the callable with
__(); it executes at render time so the admin locale applies. (These PHP-side strings are not picked up by the dashboard lang scanner — add them tolang/{code}.jsonmanually or via the translation catch-up.) - Add
'default' => falsewhen the card would show a permanent empty state on a fresh install (see the Accessibility card). - Visibility that isn't a plain feature flag: pass a
visiblecallable instead of (or alongside)feature— it is evaluated at catalog time and hides the widget from both the dashboard and the Customize modal when it returns false. The Fleet card uses this because the fleet surface followsMembership::isFleetServer(), so the license server must get the card without the Fleet Management feature being on. Keep the callable cheap (catalog() runs every render) and lazy — registration happens during provider boot, where DB access is banned. - Custom shapes: pass a
viewkey (a namespaced blade partial) instead of relying on the standard renderer — the partial receives the resolved data array as variables and replaces the standard card entirely. Register a plain view namespace withloadViewsFrom()and keep the partial under the module'sresources/views/dashboard/so the dashboard CSS bundle scans it. - Core widgets render inline in ⚡dashboard.blade.php gated by
$this->isWidgetVisible('{key}'); only add a new core entry to the registry'sboot()list when the dashboard blade gains a new section.