-
Notifications
You must be signed in to change notification settings - Fork 41
example window notice
A window notice is a tone-coded banner pinned to the top of one
or more windows — between the title bar and the content area, full
width. The user can dismiss it (default), and the dismissal is
remembered per-user in localStorage so the same banner never
re-appears for them.
Notices are pure declarative data: tone, message (HTML), an optional
dashicons glyph, and an optional match selector. The shell renders
each entry as a <os-notice> web component inside the matching
window's after-titlebar slot.
<?php
defined( 'ABSPATH' ) || exit;
add_action( 'init', function () {
openstation_register_window_notice( array(
'id' => 'my-plugin/welcome-posts',
'tone' => 'info',
'message' => __(
'<strong>Welcome to My Plugin.</strong> Try the new <a href="…">bulk-edit overlay</a>.',
'my-plugin'
),
'icon' => 'dashicons-info',
'match' => array( 'window' => 'edit-php' ), // Posts window
) );
} );openstation_register_window_notice( array(
'id' => 'my-plugin/holiday-banner',
'tone' => 'warning',
'message' => __( 'Holiday freeze in effect — content edits are read-only.', 'my-plugin' ),
'match' => array(
'windows' => array(
'edit-php', // Posts
'edit-php-page', // Pages
'upload-php', // Media
),
),
) );For plugin pages whose window id is derived from a long URL (e.g.
admin.php?page=wc-admin&path=/analytics), match by URL substring
instead of trying to predict the slug:
openstation_register_window_notice( array(
'id' => 'my-plugin/wc-promo',
'tone' => 'success',
'message' => __( 'Black Friday rate now available on the API.', 'my-plugin' ),
'match' => array( 'urlContains' => 'wc-admin' ),
) );Three selector types are accepted: window (single id), windows
(list of ids), and urlContains. Their combination rules:
-
Within
windows, ids are OR'd — the window matches if its id is any of the entries. -
Across selector types, the semantics is AND — the window must satisfy every selector that was set. For example, this notice appears only on the Posts window whose URL also contains
wc-admin:openstation_register_window_notice( array( 'id' => 'my-plugin/wc-posts', // … 'match' => array( 'windows' => array( 'edit-php' ), 'urlContains' => 'wc-admin', ), ) );
It does not mean "every Posts window OR every wc-admin URL." To get OR across selector types, register two separate notices (they can share the same
idonly if you want one to replace the other — use different ids otherwise).
The same API is exposed on wp.os with a fully-flexible match
predicate (any synchronous function of the Window instance):
const unregister = wp.os.registerWindowNotice( {
id: 'my-plugin/welcome',
tone: 'info',
message: 'Welcome! <a href="/wp-admin/">Open admin home</a>.',
match: ( win ) => win.id === 'edit-php',
} );
// Later — remove the notice declaratively:
unregister();// Mark a notice as dismissed for the current user.
wp.os.dismissWindowNotice( 'my-plugin/welcome' );
// Clear the dismissal so it shows again on next mount.
wp.os.undismissWindowNotice( 'my-plugin/welcome' );
// Snapshot for debugging:
console.log( wp.os.listWindowNotices() );info (default), success, warning, error (alias danger),
neutral. Plugins that need a brand color can override the
underlying CSS variables on the <os-notice> host:
os-notice[ tone='info' ] {
--os-ui-notice-info: #6a4af5;
--os-ui-notice-info-bg: rgba( 106, 74, 245, 0.08 );
}PHP-registered messages pass through wp_kses_post() — links,
inline formatting (<strong>, <em>, <br>, <code>), and
<span>s with class names survive; <script> and other unsafe
markup are stripped.
JS-registered messages are written via innerHTML as-is. Treat the
field as a trusted string: include only content you author, and run
any user-supplied data through an HTML sanitizer first.
Pass dismissible: false (PHP) or the not-dismissible attribute
(component-level) for a banner the user can't dismiss — useful for
hard-coded state messages like "Read-only mode."
openstation_register_window_notice( array(
'id' => 'my-plugin/read-only',
'tone' => 'warning',
'dismissible' => false,
'message' => __( 'This window is in read-only mode.', 'my-plugin' ),
) );Each call to openstation_register_window_notice() /
wp.os.registerWindowNotice() registers an independent slot
renderer. When multiple notices match the same window, they stack in
order ascending (default 100). Set order explicitly to control
the visual hierarchy.
Plugins can mutate the final list right before it ships to the shell — handy for request-time banners (e.g. "your trial expires today"):
add_filter( 'openstation_window_notices', function ( $entries ) {
if ( my_plugin_trial_expires_today() ) {
$entries[] = array(
'id' => 'my-plugin/trial-expires',
'tone' => 'warning',
'message' => __( 'Your trial expires today.', 'my-plugin' ),
);
}
return $entries;
} );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