-
Notifications
You must be signed in to change notification settings - Fork 41
example dock badge
Adds a new "Pending Orders" icon to the dock, with a live badge showing the current count.
<?php
/**
* Plugin Name: My Order Badge
*/
defined( 'ABSPATH' ) || exit;
add_filter( 'openstation_dock_items', function ( $items ) {
$pending = (int) get_option( 'my_pending_order_count', 0 );
$items[] = array(
'id' => 'my-orders',
'title' => __( 'Orders', 'my-ext' ),
'icon' => 'dashicons-cart',
'url' => admin_url( 'admin.php?page=my-orders' ),
'badge' => $pending, // 0 hides the badge
'submenu' => array(),
);
return $items;
} );Stable.
Use the platform API instead of poking the DOM. The framework
exposes the same setBadge( id, count ) shape on three rails —
dock (bottom), sideDock (Classic-layout left rail), and
icons (wallpaper shortcuts) — so a plugin author can fan a
count to whichever rail happens to host the tile without
branching:
function setOrdersBadge( count ) {
wp.os.dock?.setBadge?.( 'my-orders', count );
wp.os.sideDock?.setBadge?.( 'my-orders', count );
wp.os.icons?.setBadge?.( 'my-orders', count );
}
setOrdersBadge( 7 );
setOrdersBadge( 0 ); // clearThree calls, one painted tile. The two rails that don't own the id silently no-op — the rail that does paints, records the override (so a live menu refresh re-applies it), and emits exactly once.
The id is the dock item's id, the system tile's id, or the
desktop icon's id — same id space across rails. Idempotent:
applying the same count twice does not mutate the DOM, does not
re-emit.
Every change publishes on the activity bus with a rail
discriminator — one subscription, every rail composed:
wp.os.activity.subscribe(
'os/badge-changed',
( { itemId, count, rail } ) => {
console.log( `${ rail }:${ itemId } → ${ count }` );
},
);Per-rail hooks are also available for callers that only care about one surface:
// Icon rail only — also carries the previous count.
wp.os.hooks.addAction(
wp.os.HOOKS.ICON_BADGE_CHANGED,
'my-plugin/track-icon-badges',
( { iconId, count, previousCount } ) => { /* … */ },
);The framework does NOT auto-suppress badges based on window state — that decision belongs to the app. A "5 unread" badge should hide while the inbox window is focused; a "5 failed deploys" badge probably shouldn't. Subscribe to the relevant window-lifecycle hook and decide for yourself:
const WINDOW_ID = 'my-orders';
function repaintBadge() {
const total = myPlugin.getPendingCount();
const active = wp.os.windowManager.isActive( WINDOW_ID );
setOrdersBadge( active ? 0 : total );
}
[
wp.os.HOOKS.WINDOW_FOCUSED,
wp.os.HOOKS.WINDOW_BLURRED,
wp.os.HOOKS.WINDOW_MINIMIZED,
wp.os.HOOKS.WINDOW_RESTORED,
wp.os.HOOKS.WINDOW_CLOSED,
wp.os.HOOKS.WINDOW_OPENED,
].forEach( ( h ) =>
wp.os.hooks.addAction( h, 'my-plugin/badge', ( p ) => {
if ( p.windowId === WINDOW_ID ) repaintBadge();
} )
);
repaintBadge();For attention-grabbing animations (pulse / shake / bounce on the
tile), see
window-request-attention.md.
-
window-request-attention.md— pulse / shake / bounce a tile -
../event-driven-framework.md— the mental model - Hooks Reference —
openstation_dock_items - Hooks Reference —
openstation_dock_item
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
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