The interface
Implementation
src/PlanConfigExtension.php
Register it
src/Plugin.php
config.extensions.{key}.
The editor template
The plan editor is an Alpine form bound to amodel object. Your template receives key and defaults, and binds inputs into model.config.extensions[key]:
templates/plan.twig
getDefaults() when a plan doesn’t have it yet, so you can bind directly without guarding for missing keys.
The snapshot template
Snapshots are historical copies of a plan, so the template is read-only, and the data may predate your extension:templates/plan-snapshot.twig
Read the settings at runtime
Your settings travel with the plan and its snapshots, so read them from the workspace’s subscription:Design notes
- Use
nullfor unlimited, and say so in the field’s help text. - Default to off. A new extension must not silently enable a paid capability on every existing plan.
- Keep keys stable. They’re written into every plan snapshot, and renaming one orphans historical data.
- Keep it small. Per-plan settings belong here; global configuration belongs on your settings page.
Testing
Your section appears in the plan editor, both for new and existing plans.
Saving a plan persists your values, and reopening shows them.
A snapshot of the plan shows your read-only summary.
A workspace on a plan with the capability disabled is blocked by your checks.
A cap is enforced at the limit, not one over.