-
Notifications
You must be signed in to change notification settings - Fork 41
example notify
Stable.
wp.os.notify( opts ) is the one call you need. v1 ships local
notifications (browser Notification API on the current page) with a
toast fallback when permission is denied or unsupported. The same
shape will route through Web Push in v2 — your plugin code won't
change.
wp.os.notify( { title: 'Backup complete' } );That's it. No permission dance, no prompt-then-call branching: the
first notify() call requests permission lazily; if the user declines,
the framework falls back to a toast.
wp.os.notify( {
title: 'New comment on “Hello World”',
body: 'Anna: I have a question…',
icon: '/wp-content/uploads/2025/avatar-anna.png',
tag: 'comments/47',
requireInteraction: false,
onClick: ( notification ) => {
window.focus();
notification.close();
wp.os.openWindow( 'desktop-mode-comments' );
},
} );The tag collapses repeat notifications — if a second comment lands on
the same post, the new notification replaces the old one rather than
stacking. Use it for unread-count alerts.
For a UX where the user explicitly toggles "Enable notifications" in settings, prompt up front rather than during a real notification:
const result = await wp.os.pwa.requestNotificationPermission();
// 'granted' | 'denied' | 'default' | 'unsupported'
if ( result === 'granted' ) {
wp.os.showToast( { message: 'Notifications enabled.' } );
} else if ( result === 'denied' ) {
wp.os.showToast( {
message: 'Notifications blocked. You can re-enable them in your browser settings.',
} );
}Synchronous read of the current state:
const perm = wp.os.pwa.getNotificationPermission();
// 'granted' | 'denied' | 'default' | 'unsupported'A "Do not disturb" plugin can subscribe to the activity bus and either filter the notification intent (cancel before render) or just observe that one was shown:
wp.hooks.addFilter(
'os.activity.os.notification-requested',
'my-plugin/dnd',
( intent ) => {
if ( isDoNotDisturbActive() ) {
return { ...intent, cancel: true };
}
return intent;
},
);
wp.os.activity.subscribe(
'os/notification-shown',
( payload ) => {
// payload.fallback === 'toast' means permission was denied
// and the user only saw the in-shell toast version.
analytics.track( 'notification.shown', payload );
},
);Note the asymmetry: filter registration goes through
wp.hooks.addFilter on the os.activity.<channel> hook
name, writing the channel's separator as a period.
wp.os.activity.filter( channel, value ) is the
publisher-side apply call — it runs the registered filters against
value and returns the result; passing it a callback registers
nothing.
notify() returns a dismiss function. Useful when the state your
notification reflects changes before the user dismisses it:
const dismiss = wp.os.notify( {
title: 'Connecting…',
requireInteraction: true,
} );
connection.once( 'ready', () => dismiss() );
connection.once( 'error', () => {
dismiss();
wp.os.notify( { title: 'Connection failed' } );
} );- Local notifications only fire while the page is open. Phase 4 will
route the same
notify()call through the service worker so a notification can fire from a closed tab. - Safari (macOS / iOS) requires a user gesture for the first
Notificationconstructor call. The framework catches the gesture exception and falls back to a toast — so your code never has to branch on browser. -
Notification.permission === 'default'(never asked) lazy-requests on firstnotify(). If you don't want that, callrequestNotificationPermission()first and act on the result.
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