Amvionlie CMS
Where the Future Begins

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