-
Notifications
You must be signed in to change notification settings - Fork 41
migration wp package globals
Who this affects: plugins whose widget, native window, command, or
any other lazily-loaded script touches wp.apiFetch, wp.element,
wp.data, wp.components or any other @wordpress/* global.
What to do: declare the package as a dependency of your script. That is all — and it was always the documented contract. What changed is that failing to do it used to work anyway.
Until 1.1.3, Core's ⌘K command palette was enqueued on every admin
page, and its dependency chain is the whole Gutenberg runtime. As a
side effect, wp.apiFetch, wp.element, wp.data and wp.components
were on every admin page whether anything asked for them or not.
That runtime is now deferred to the first time the palette is actually invoked. On a fresh boot those globals are undefined until the user presses ⌘K, and the shell no longer carries ~10 MB of Gutenberg it mostly never used.
A script registered like this:
wp_register_script( 'acme-widget', $url, array(), $ver, true );…that then calls wp.apiFetch( … ) throws
TypeError: wp.apiFetch is undefined at mount, and mysteriously starts
working later in the same session — once the user happens to open the
palette and the runtime lands.
In-tree bundles are self-contained and were unaffected, which is why the test suite did not catch this.
Declare what you use:
wp_register_script(
'acme-widget',
$url,
array( 'wp-api-fetch', 'wp-element' ), // ← every package you touch
$ver,
true
);WordPress resolves declared dependencies when your script is enqueued, so the packages are present before your code runs — no timing assumptions, no waiting on the palette.
Because they were never a contract, and putting them back means putting back the cost: on a plain Settings screen the palette chain was 43 files, 10.66 MB raw / 1.94 MB gzipped — 73.6% of everything the window downloaded — parsed and executed again in every window's own JavaScript realm, where an HTTP cache hit buys nothing.
WordPress resolves a script's dependencies when it enqueues it. A handle that OpenStation only ever fetches lazily never goes through that pass: the loader injects one URL and nothing else, so a declared dependency is not on the page when the bundle runs. A declared dependency still resolves normally whenever WordPress itself enqueues the handle — the gap is specific to handles only ever fetched lazily.
Widget bundles close that gap. openstation_register_widget()
resolves the handle's dependency closure server-side and ships it in
the payload, and the loader executes those handles in order before the
widget's own — each with its wp_localize_script /
wp_add_inline_script / wp_set_script_translations data attached.
Declare your packages and it works.
No other lazy path does this yet. Native-window scripts, command
scripts, settings-tab scripts, wallpapers, games and desktop-file
openers all travel the same loader, but their payload builders do not
resolve a closure. If one of those needs a @wordpress/* package,
either enqueue the handle normally so WordPress resolves it, or load
the package yourself before use — do not rely on load order.
The loader side of the mechanism is generic, so extending the remaining builders is a payload change rather than a new mechanism.
This wiki is generated from the docs/ directory — edits made here are overwritten by the next sync.
To change a page, open a pull request against docs/.
Guides
- Development guide
- Releasing openstation
- Agents security model
- API Index
- Architecture
- Bridge protocol — wiring overview
- <os-*> component reference
- Native Desktop Host — Experimental
- Desktop themes
- Dock customization — two registries, one mental model
- The event-driven framework
- Files on the Desktop
- Folder sharing
- Getting Started
- Hooks Reference
- Icons
- JavaScript Reference
- The Living Tree — algorithm definition
- Mio
- Native Windows & Framework Interop
- Plugin compatibility layer
- Progressive Web App (PWA)
- Station Home
- Using openstation from your own plugin
Migration notes
- Migration: built-in activity channels move to the os/ namespace
- Migration: window, wallpaper and widget bundles load on demand
- Migration — the navigation model
- Migration: a native window's tabs move to the window chrome
- Migration — WordPress package globals are no longer ambient
All examples
- AI Agents — extend and invoke from a plugin
- wp.os.ai.ask() — programmatic AI Copilot
- Tune the AI model config
- Custom arrange-menu action
- Open a child window its owner can't cover
- Style a specific admin page inside the iframe
- Code Blue — register your plugin's log file
- Open a file in the Code editor (deep-link from any window)
- Connect to a window — title-bar button + iframe pub/sub
- Content changes — live-refresh every window listing your type
- Custom window chrome (Experimental)
- Register a custom unfocused-window effect
- Example: render a data table
- Real file storage — react to uploads, gate policy, share from PHP
- React to a window being set free onto the real desktop
- Cross-window devtools — instrumentation primitives
- Add a dock item with a badge
- Decorate the dock without forking the renderer
- Replace the dock rail entirely
- Retune the Drafts widget's AI writing assistant
- Gate OpenStation by role
- Iframe-initiated window opens
- Build a feed reader without the bookkeeping
- Inject data into openStationConfig
- Render a list without losing clicks — renderKeyedList()
- Example: layout primitives (body → panel → row → col)
- Use <os-*> components from a plugin that ships as a zip
- Restyle and drive Mio
- Add an action that works on a whole selection
- WP Explorer — custom post types and their folder
- Add an action button to a WP Explorer preview pane
- Example: native Posts window
- Example: native window with tabs
- Native windows
- Customize note → post conversion
- Send a notification
- OAuth relay — connect to an external service
- OS-file drop
- <os-flyout> — window-scoped sliding card
- Plugins window — extras
- Track who's around — wp.os.presence
- Example: progress bar
- PWA install — surface your own button
- React to window events
- Example: extend the Trash
- Register a slash-command
- Register a desktop theme from a plugin
- Register a game
- Example: register a desktop icon (Jorvy)
- Register a wallpaper
- Register a widget
- Related entities — extend the title bar's "Related" menu
- The native-window render ctx
- Programmatic folder sharing
- Share state across multi-bundle plugins — wp.os.createSharedStore()
- Example: loading spinner
- Add an opt-in card to Station Home
- Accept drops on your desktop icon
- Give a tile two icons, one per state
- Add a row to a window's ⋯ menu
- Example: window activity & the status ring
- Window controls
- Subscribe to window lifecycle events
- Window links — relate windows and restyle the ties (Experimental)
- Window loading state — spinner overlay & ready signal
- Show a banner at the top of a window
- Pulse a window's icon — Window.requestAttention()
- Register a custom window reveal
- Window slots
- Window themes
- Native window with bundle-bound config