Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Pirsch Laravel Package

jeffersongoncalves/filament-pirsch

Filament Pirsch brings privacy-friendly Pirsch analytics into your Laravel Filament admin panel, adding dashboard widgets and reports for visitors, pageviews, and traffic sources so you can monitor site performance without leaving Filament.

View on GitHub
Deep Wiki
Context7

Getting Started

This release (3.1.0) adds one fluent setter, Plugin::make()->navigationGroup(string|Closure), which places the plugin's settings page inside one of your panel's existing navigation groups instead of the default translated group. It is a small, additive change — nothing to migrate, nothing to un-learn. If you already register the plugin, adoption is a one-line edit.

Minimal steps to get productive:

  1. composer require the plugin alongside filament-analytics-core:^3.1 (the new method depends on that core version — see Gotchas).
  2. Register the plugin in your PanelProvider:
public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(
            Plugin::make()
                ->navigationGroup('Analytics'),
        );
}
  1. php artisan filament:optimize:clear (or a full optimize:clear) and reload the panel — the settings page should now sit under your own group.

Where to look first:

  • The Plugin class itself — it is the whole public surface of this package. Read its setters top to bottom before anything else; that is the API you will actually live in.
  • The settings page class it registers — that is where the navigation label, icon, sort and slug live if you need to change more than the group.
  • Your PanelProvider's existing ->navigationGroups([...]) call — the string you pass to navigationGroup() must line up with a group declared there, otherwise you are creating an orphan group.

First use case: an admin panel that already has a curated set of navigation groups ("Content", "Settings", "Analytics"). By default the plugin drops its settings page into a translated group of its own, which looks like a stray section in the sidebar. One call to navigationGroup('Settings') folds it into the group you already maintain, which is exactly the everyday reason you would reach for this.

Implementation Patterns

Static group for a single panel. The common case: hardcode the group name in the panel provider.

Plugin::make()->navigationGroup('Settings')

Use the exact string used in ->navigationGroups(). Filament matches by label, so 'settings' and 'Settings' are two different groups.

Closure for per-panel or per-tenant grouping. Pass a Closure when the group depends on runtime state — the current tenant, the panel, or a feature flag:

Plugin::make()->navigationGroup(
    fn () => filament()->getTenant()?->isEnterprise() ? 'Enterprise' : 'Settings'
)

This is the pattern to reach for in multi-tenant apps where a shared panel provider serves several contexts.

Localised grouping. If your panel is translated and you already group by __('admin.groups.settings'), return the same translated string from the closure so the plugin's page and your own pages always land together across locales:

Plugin::make()->navigationGroup(fn () => __('admin.groups.settings'))

This is the intended replacement for relying on the plugin's built-in translated group — you keep translation, but you control which translation key.

Multi-panel setups. Register the plugin per panel with a different group per panel ('Settings' in admin, 'Configuration' in the vendor panel). Panel providers are separate classes, so this needs no conditionals — resist the urge to build a shared base provider just to centralise one string.

Keeping configuration out of the provider. If you already have a config/analytics.php-style file, resolve the group from config and let the closure do the lookup. That keeps the group tweakable per environment without touching the provider, and makes it easy to assert in tests.

Testing. Filament panel tests can assert navigation state, but the cheap check is to assert the plugin object itself:

$plugin = Plugin::make()->navigationGroup('Settings');

$this->assertSame('Settings', $plugin->getNavigationGroup());

For anything visual, hit the settings page route in a panel test and assert assertSee('Settings') in the sidebar — this catches label mismatches that unit tests on the plugin will not.

Integration tip: treat navigationGroup() as presentation-layer configuration and keep it next to your other navigation calls. Do not bury it in a service provider or a helper — the person debugging the sidebar six months from now will look at the panel provider first.

Gotchas and Tips

Version constraint is the first failure mode. The method requires filament-analytics-core 3.1. If you upgrade the plugin but your lockfile still pins core 3.0, the call will fail (missing method / undefined behaviour) at panel boot rather than at install time. Bump both together:

composer require the-plugin:^3.1 filament-analytics-core:^3.1

Not calling it is not a regression. Without navigationGroup(), the translated group is deliberately kept. If your panel is English-only and the default group name is fine, do nothing — adding an override for its own sake gives you a string to maintain and a translation to lose.

Group must exist (or you accept a new one). Filament will happily render a group that is not in ->navigationGroups(); it just appears wherever the sort order lands, often at the bottom. If the page shows up in an unexpected position, this is the cause nine times out of ten. Declare the group in ->navigationGroups() with an explicit ordering and pass the identical string.

Closures are evaluated late. Do not expect the closure to run once at boot. Anything it captures — tenant, locale, user — must be safe to resolve at render/serialisation time. In particular, avoid touching the authenticated user in the closure if the panel is ever warmed by a queue worker or a cache-warming command; guard with auth()->check() or fall back to a static string.

Caches and optimised panels. After changing the group, clear Filament's cached components/optimize:clear. A stale component cache makes it look like the setter did nothing, and you will spend twenty minutes re-reading the release notes.

Closure returning null. Treat a null return as "fall back", not "hide" — verify the behaviour you get with the core version you are on before relying on it for conditional grouping; if you need the page hidden, use the plugin's visibility/authorisation hooks rather than an empty group name.

Extension point to prefer. If you find yourself overriding the settings page class just to change its navigation group, stop — this setter exists precisely so you do not have to subclass. The same applies to label/icon tweaks: check the plugin's own fluent setters before reaching for a subclass, and keep subclasses to genuine behaviour changes.

Debugging checklist for "it did not move": (1) is the plugin actually registered on this panel, (2) is the core version ≥ 3.1, (3) do the strings match byte-for-byte including case, (4) did you clear caches, (5) is the closure returning null in this context. That order resolves almost every report.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core