Menu Manager Public Targets
Menu Manager consumes destinations. It should not discover addon pages by reading addon tables or guessing routes.
Current Rule
Use public target providers for addon-owned destinations that admins should be able to select in menus.
Do not paste protected admin URLs into public menus.
Current Drift
Final intended rule: addons expose public targets through a governed provider contract, and Menu Manager consumes providers generically.
Current behavior: Menu Manager target discovery is still wired to known providers such as Pages, Content Manager, Wiki, Categories, Articles, and Ticket Support. A new third-party addon may need a future registry/handoff before its provider appears automatically.
Document and build the provider contract anyway. It is the expected addon boundary.
Provider Contract
A provider should expose:
- provider key
- provider label
- list function
- resolve function
- supported target levels
- stable target identifiers
Example provider metadata:
function amv_example_notes_public_target_provider(): array
{
return [
'provider_key' => 'example_notes',
'label' => 'Example Notes',
'list_function' => 'amv_example_notes_public_targets',
'resolve_function' => 'amv_example_notes_public_target_for_identifier',
'target_levels' => ['example_notes_home', 'example_notes_note'],
];
}Target Shape
Each target should include:
- `identifier`: stable target identifier
- `provider_key`: addon/provider key
- `target_type`: usually `application_target`
- `target_level`: home/list/detail kind
- `label`: admin-facing label
- `kind_label`: human-readable target kind
- `url`: resolved public URL
- `preview_url`: admin preview URL when different
- `available`: whether the target can be used now
- `metadata`: small supporting context
Example:
[
'identifier' => 'note:' . $note['note_uuid'],
'provider_key' => 'example_notes',
'target_type' => 'application_target',
'target_level' => 'example_notes_note',
'label' => $note['title'],
'kind_label' => 'Example Note',
'url' => '/example-notes/' . $note['slug'],
'preview_url' => '/example-notes/' . $note['slug'],
'available' => $note['state_key'] === 'published',
'metadata' => ['note_uuid' => $note['note_uuid']],
]Resolve Function
The resolve function should accept a stable identifier and return one target or `null`.
Do not require Menu Manager to know the addon's tables.
Verification
- Home target resolves.
- Published record targets resolve.
- Draft/private records are not exposed as public menu targets.
- URLs match public route declarations.
- Provider metadata matches `frontend_contract` in the manifest.
Related: Addon Development/Public Routes, Addon Development/Build Your First Addon.
Updated: 2026-05-07 02:18:09