Skip to Content
PluginsWayfinderArchitecture

Architecture

Wayfinder has two layers: PHP backend builds item tree, React frontend renders it.

PHP Side

Item Tree

Renderer (classes/output/renderer.php) builds this tree:

page (root) ├── group "Course module" → navnode items from secondarynav ├── group "Course" → navnode items from secondarynav ├── group "Navigation" → navnode items from primarynav (excludes siteadminnode) ├── group "My profile" → link items from user_get_user_navigation_info() ├── separator ├── command "Language" → submenu page → language options (redirect actions) └── group "Admin" ├── command "Site administration" → submenu page → recursive admin categories └── command "Purge all caches" → submenu page → cache options (form actions)

Item Types

Classtype in JSONDescription
item(abstract)Base. Access check via check_access().
commandcommandHas name, description, keywords, action, hotkey. Main interactable unit.
pagecommand (subtype page)Command with children. Action is always submenu.
groupgroupNamed container. Access passes if any child accessible.
separatorseparatorVisual divider.
linkcommand (subtype link)Command with redirect action (to URL) + optional keywords.
navnodecommandWraps a Moodle navigation_node. Children become submenu.

Action Types

Classid in JSONBehavior
redirectredirectwindow.location.assign(url)
submenusubmenuPush page to nav stack, drill down
formformPOST to URL with data (used for cache purge)

Serialization

All items/actions implement JsonSerializable. Renderer encodes the entire tree as JSON into data-react-props on a <wayfinder-root> element.

<wayfinder-root data-react-component="@moodle/lms/local_wayfinder/root" data-react-props='{"icon":{...},"strings":{...},"root":{...}}'> <!-- skeleton HTML --> </wayfinder-root>

React Side

Moodle’s core detects data-react-component and mounts the component.

Component (root.tsx)

  • Uses cmdk library for the command menu UI (dialog, input, list, items)
  • Uses @tanstack/react-hotkeys for keyboard shortcuts
  • Uses lucide-react for icons

State

  • pages[] — stack of pages (breadcrumb nav, starts with [root])
  • open — dialog visibility
  • value — cmdk search value
  • input — local input state (aria workaround)

Flow

  1. User presses Mod+K or / -> palette opens
  2. Type filters items via cmdk fuzzy search
  3. Select item:
    • submenu action / page subtype -> push page to pages[], reset search
    • redirect -> window.location.assign(url)
    • form -> create hidden <form>, POST, submit
  4. Back button or backspace (when empty) -> pop pages[]
  5. Escape -> close palette

String Handling

strings.tsx provides React context with all language strings. Required strings passed as JSON from PHP renderer.

Icons

ScenarioIcon
Item with no actionDot
Submenu / pageChevronRight
RedirectLink2
Form actionPlay