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

Statamic Features Laravel Package

edalzell/statamic-features

A lightweight Statamic addon for defining and managing feature flags. Toggle features via configuration, check availability in your templates, and roll out functionality safely across environments. Ideal for gradual releases, beta access, and environment-specific behavior.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install the package alongside edalzell/laravel-features and statamic/cms, then read the feature base class / trait that wires a laravel-feature into Statamic — that class is the map for everything else in v1.0.0. The statamic.* config options it exposes (asset handles, Vite settings) are the second place to look.
  • The mental shift: a Statamic "addon" can now be a laravel-feature. Everything an addon's addon.php config + ServiceProvider used to declare — tags, fieldtypes, modifiers, scopes, actions, widgets, dictionaries, subscribers, update scripts, blueprint/fieldset namespaces — can live inside a feature folder instead.
  • First use case: take one existing custom addon (or one loose pile of Statamic::tag() calls in AppServiceProvider) and move it into a feature. Create the feature, list its tags/modifiers in the feature's registration arrays, delete the old manual registrations, and confirm the site still renders.
  • Minimal shape (illustrative — confirm method names against the package README):
class EventsFeature extends Feature
{
    public function tags(): array       { return [Tags\UpcomingEvents::class]; }
    public function modifiers(): array  { return [Modifiers\GroupByDay::class]; }
    public function fieldtypes(): array { return [Fieldtypes\VenuePicker::class]; }
}
  • Once that works, add routes/web.php and resources/cp to the same feature to see the routes/assets story in one place.

Implementation Patterns

One feature = one domain. Group by what the editor sees ("Events", "Directory", "Donations"), not by class type. Tags, fieldtype, modifier, widget and the CP JS for that widget usually ship together and change together.

Registration lists are the primary API. Every component type in the release (tags, fieldtypes, modifiers, scopes, actions, widgets, dictionaries, subscribers, update scripts) is a declarative list on the feature. This replaces the scattered Statamic::tag() / Modifier::register() calls and the config/statamic/ overrides you'd otherwise maintain.

Namespaces replace file-path juggling. Blueprint and fieldset namespaces let a feature own resources/blueprints and resources/fieldsets and be referenced as namespace::handle from any other feature. This is the cleanest way to let site-specific features extend an addon's blueprints without copying YAML.

Routes split by intent — use them deliberately:

File What it's for
routes/web.php Front-end routes on the site's domain (feeds, detail pages, webhooks)
routes/cp.php Control panel routes, loaded through Statamic so they get the CP prefix + middleware — no manual auth wiring
routes/actions.php Action endpoints called from the CP (modals, bulk actions) where you want Statamic's action/CSRF handling

Keep closures out of all three if you plan to route:cache.

Assets: resources/cp by default, statamic.* when you need control. Drop resources/cp/js/cp.js and resources/cp/css/cp.css and they get registered with the CP. Reach for the config when you need a custom handle, extra entry files, or a Vite build instead of plain files. For Vite, point the config at your build directory and make sure npm run build runs in deploy — not just locally.

Migration workflow that keeps the site up: create the feature → move one component type → delete the old registration → deploy → move the next. Don't move registrations and route files in the same step; a broken route file gives a 500 that looks like a broken fieldtype.

Testing: CP routes are ordinary Laravel routes, so actingAs() a super user and hitting /cp/... works. Test the feature boundary (does the tag resolve? does the blueprint namespace resolve?), not Statamic internals.

Gotchas and Tips

  • Register early, not late. Namespaces and fieldtypes must exist before anything resolves a blueprint or a field. Put namespace/fieldtype registration in register()-time code, not deep in boot(), or you'll get "blueprint not found" only on cold requests — and never in tests that booted something else first.
  • Silent duplicates. If a tag/fieldtype/modifier is registered both in a feature and in config/statamic/* (or an old ServiceProvider), one silently wins. Grep for the handle before you assume a registration is broken.
  • Stache is a cache. After changing namespaces, widgets, or dictionaries, run php please stache:clear (or php artisan statamic:stache:clear). "Fieldtype not found" after a correct registration is almost always stale stache.
  • Update scripts are version-gated. They run once per version. Editing the body without bumping the version means it never re-runs locally — this trips people up when testing migrations.
  • Vite in the CP: the hot file and dev server URL must be reachable from the browser, not just the container. In production, a missing manifest or unbuilt assets shows up as a blank/white CP panel with a 404 in the console — check the network tab before debugging PHP.
  • Publishing matters. CP assets have to exist under public/ on the server. Keep the publish step in your deploy script alongside migrate and stache:clear.
  • Route cache + feature routes. Re-run route:cache after enabling/disabling a feature; a cached route table can keep serving routes for a feature you've since turned off (or miss new ones).
  • Don't duplicate the addon. Anything this extension doesn't cover — permissions, nav items, preferences, listeners that must fire earliest — still belongs in the normal ServiceProvider. Mixing the two is fine; registering the same thing twice is not.
  • Subscribers need to be registered before the event fires. Register in the feature's boot/register path and confirm with a real save, not just a unit test.
  • Widgets need their view. If the widget renders blank, check the feature's view namespace and that the CP JS entry actually loaded (resources/cp) — a widget with a broken JS component looks like an empty card, not an error.
  • Debugging order that works: does the handle appear in php please stache:doctor/the CP? → is the class autoloadable? → is the feature enabled? → is stache cleared? Almost every "the feature isn't working" report resolves at step 3 or 4.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib