WP Desktop Mode
A WordPress plugin that reimagines /wp-admin as a desktop operating system. Admin screens open as draggable, resizable, minimizable windows on a desktop, with a left-edge dock built from the admin menu. Purely opt-in per user — the classic admin stays untouched for everyone else, and deactivating the plugin restores vanilla Core exactly.
Zero Core patches. Every feature is wired through public WordPress hooks.
Demo
Contents
- Demo
- Current State
- Still ahead
- Repository layout
- How to run it
- Requirements
- For plugin authors
- License
Current State
-
Per-user opt-in Admin-bar toggle sets the
desktop_mode_modeuser meta. A dedicated/desktop-mode/portal URL auto-enables desktop mode for first-time visitors (gated bydesktop_mode_portal_auto_enable) and theadmin_initredirect sends opted-in users from/wp-admin/to the portal (desktop_mode_admin_redirect_to_portal). -
Desktop shell Fixed-viewport desktop that overlays
/wp-admin: wallpaper area, unified dock (placement picked in OS Settings — left / right / bottom, default bottom), right-column widget layer, and full windowing system.desktop_mode_mode_init,desktop_mode_shell_before/_after, and thedesktop_mode_shell_configfilter are the main extension points. -
Window system — iframe + native Iframe windows load admin pages with
?wp_desktop=1(chromeless mode). Native windows render directly in the parent DOM viadesktop_mode_register_window()/wp.desktop.registerWindow()— multi-tab native windows are supported throughdesktop_mode_register_window_tab(). Both types share drag, resize, minimize, maximize, close, fullscreen, and detach-to-new-tab. -
Dock One unified rail hosting every admin menu — core and plugin alike — plus shell-level system tiles. Placement (left / right / bottom) is the user's OS Settings preference. Core menus are ordered before plugin menus; per-item hiding via
desktop_mode_dock_placement('hidden'). Per-item multi-window support viadesktop_mode_dock_item_multi. Letter-badge icon fallback for plugins without icon art. -
Virtual desktops (“Spaces”) Multiple desktops per user, each with its own window set. Overview grid (zoom-out view) surfaces the Spaces switcher, thumbnails, and create/close controls.
-
Arrange & snap Admin-bar Arrange menu: Cascade, Tile, Overview, Snap to grid. Plugins contribute custom entries via
desktop_mode_arrange_menu_itemsand react to clicks viadesktop-mode.arrange.custom-action. Tile grid dimensions and snap cell size are both filterable. -
Wallpaper registry Server- and client-side registration (
desktop_mode_register_wallpaper()/wp.desktop.registerWallpaper()). CSS presets + canvas (WebGL/2D) wallpapers with collision-aware surface data (wp.desktop.getWallpaperSurfaces()) for snow/rain/physics effects. In-panelrenderEditorcallback for custom controls, shared vendor-module loader (pixijspre-registered). -
Widgets Right-column floating cards, optionally draggable / resizable outside the column.
desktop_mode_register_widget()/wp.desktop.registerWidget(). Built-in clock. User placement persists per-user inlocalStorage. -
Desktop icons Wallpaper-layer shortcuts via
desktop_mode_register_icon()— targets a registered native window or an admin URL. -
AI Assistant + slash commands Cmd+K palette backed by an OpenAI agentic loop whose
search_posts/search_pages/search_commentstools run WordPress's native keyword search. Admin-configured API key + model picker. The only automatic AI analysis is comment spam scoring (on comment save), which feeds the comments-window spam score; posts, pages, and terms are not analyzed.wp.desktop.registerCommand()adds slash commands with autocomplete (suggest()), confirm dialogs (ctx.confirm()), and full lifecycle hooks (before-run/after-run/error). Built-in/open [window]is extensible viadesktop-mode.open-command.items. -
Palette registry Cmd+K cycles through all registered palettes (
wp.desktop.registerPalette()) — the AI assistant is palette 0 by default; additional plugin overlays share the shortcut. -
Cross-frame drag bridge Media-library attachments drag across iframe boundaries via coordinated postMessage. Site-wide toggle through the Extended Options REST endpoint.
-
Toast notifications Shell-level toasts rendered via the
<wpd-toast>component. Plugins register their own tone/icon via thedesktop_mode_toast_typesfilter. Iframe pages raise a toast through thedesktop-mode-notificationbridge message — it survives the iframe's own lifecycle. -
OS Settings Native-window settings panel: wallpaper picker (with HD-only media filter), accent color swatches + custom gradient editor, dock size slider, AI platform config, and per-user default-on-startup window. Persisted via
/desktop-mode/v1/os-settings. -
Session persistence Full window stack (including desktops, focus, state) is debounce-saved to
/desktop-mode/v1/sessionand restored without layout flicker. Viewport-shrink clamping keeps off-screen windows reachable. -
postMessage bridge Typed messages for title changes, navigation (same-origin validated), focus, color-scheme sync, screen-meta panels (Screen Options / Help), external-link capture, iframe-ready handshake, and observability (
iframe-error,iframe-network). -
UI component library ~25
<wpd-*>web components (wpd-button,wpd-menu,wpd-panel,wpd-range-field,wpd-swatch,wpd-toast,wpd-tabs, …) available to plugin authors — rendered server-side viadesktop_mode_component()or imported in TS. -
i18n Full gettext coverage across PHP and TypeScript; Spanish translation shipped. Strings go through
wp.i18n(__,_x,_n,sprintf) directly — no shell-specific re-export. -
Component registration API Stable
desktop_mode_register_*functions for windows, widgets, wallpapers, icons, and window tabs. All returntrue/WP_Errorwith documented error codes. -
Public hook API Comprehensive PHP and JS hook surface — dock items, placement, multi-window, native-window lifecycle, widget lifecycle, wallpaper lifecycle + surfaces, window lifecycle, iframe observability, arrange actions, virtual-desktop transitions, palette registration, command lifecycle, batch close, AI prompt + model + post-type filters, accents, toast types, default wallpaper. See
docs/hooks-reference.mdanddocs/javascript-reference.md.
Still ahead
- Mobile (phone OS) — purpose-built home-screen grid, full-screen apps, app switcher, gesture nav, bottom tab bar.
- Tablet hybrid — split view, slide-over, horizontal dock.
wp.desktop.mode = 'desktop' | 'tablet' | 'mobile'surface. - Cross-window drag & drop (the North Star) — extend the current drag bridge to Media → Gutenberg block insertion, with pluggable mime-type negotiation.
- Polish — color-scheme-aware variables across all shell surfaces, View Transitions API animations, full a11y audit (ARIA, focus traps, keyboard nav).
- …and a whole lot more hooks, filters, and actions — every new surface lands with its own extension points, so this list keeps growing.
See docs/architecture.md for how the pieces fit together and docs/hooks-reference.md for the hook surface (current and planned).
See docs/architecture.md for how the pieces fit together and docs/hooks-reference.md for the hook surface (current and planned).
Repository layout
.
├── desktop-mode.php # bootstrap: header, constants, require_once of includes/
├── includes/ # PHP subsystems
│ ├── helpers.php admin-bar.php ajax.php
│ ├── assets.php render.php portal.php
│ ├── session.php default-window.php components.php
│ ├── os-settings.php extended-options.php
│ ├── accents.php wallpapers.php toast-types.php
│ ├── media-query.php
│ └── ai-copilot/ # AI assistant (OpenAI client, analysis, search, jobs)
├── assets/ # compiled CSS + JS (Vite output; tracked in git)
│ ├── css/ desktop.css, windows.css, dock.css, chromeless.css, variables.css
│ └── js/ desktop.js, desktop.min.js, chromeless bridge, media-library enhancements
├── src/ # TypeScript source — compiled by Vite
│ ├── desktop.ts / dock.ts / hooks.ts / commands.ts / palette-registry.ts
│ ├── ai-assistant.ts / drag-bridge.ts / toast.ts / desktop-icons.ts
│ ├── native-windows.ts / built-in-commands.ts / public-api.ts / types.ts
│ ├── window/ # Window class — DOM, pointer, tabs, iframe bridge
│ ├── window-manager/ # stack, desktops, arrange, snap, overview
│ ├── wallpapers/ # registry, layer, surfaces, server sync, vendor loader
│ ├── widgets/ # registry, layer, frame, picker, storage
│ ├── settings/ # OS Settings panel sections
│ ├── ui/ # <wpd-*> web components
│ ├── modules/ # vendor-script lazy-loader
│ └── plugins/ # built-in demos (animated-logo-wallpaper)
├── docs/ # developer-facing docs (source of truth for plugin authors)
├── tests/ # PHPUnit + Vitest
├── languages/ # .po / .mo (es shipped)
├── bin/ # package-zip helpers
├── package.json # devDeps (vite, typescript, vitest)
├── vite.config.js # Vite lib-mode: src/desktop.ts → assets/js/desktop[.min].js (IIFE)
├── vitest.config.ts
└── tsconfig.json
How to run it
Quick install
Just want to try it? Grab the pre-built zip and upload it to any WordPress — Studio by WordPress.com, wp-env, or a hosted site. No Node, no build step.
- Download
desktop-mode.zipfrom the latest release (or pick a specific version from the releases page). - In WP Admin: Plugins → Add New → Upload Plugin, choose the zip, and activate.
- Click the desktop icon in the admin bar's top-right corner. The admin reloads inside the desktop shell. Click the same icon again to return to classic admin.
Development setup
For hacking on the plugin: clone the repo, run the build in watch mode, and load it into a local WordPress via symlink so every save is one browser refresh away.
1. Install dependencies
npm install
2. Build the TypeScript bundle
The plugin uses Vite in library mode. esbuild handles transpile and minify, so builds finish in ~70 ms per bundle.
Full build — produces every bundle (npm run build:desktop, :iframe-bridge, :recycle-bin, :posts-window):
npm run build
Writes:
assets/js/desktop.js/.min.js— main shell bundle (loaded based onSCRIPT_DEBUG).assets/js/iframe-bridge.js/.min.js— opt-in bridge that gives any same-origin iframe access towp.desktop.iframe.*.assets/js/recycle-bin.js/.min.js— Recycle Bin native window.assets/js/posts-window.js/.min.js— Native Posts window (the<wpd-table>replacement for theedit.phpiframe; opt-in per user via OS Settings → Features).
Development watch — auto-recompiles the unminified bundle on save:
npm run dev
Leave it running in a separate terminal; refresh the browser after each save. Set define( 'SCRIPT_DEBUG', true ) in wp-config.php so WordPress picks up the unminified bundle during development.
3. Load into a local WordPress
You need a running WordPress to load the plugin into. Pick whichever is easier.
Studio, wp-env, or a hosted WP
Run npm run package to build a zip from HEAD (with correct 0644 / 0755 permissions), then follow the Quick install steps 2–3 to upload and activate it. Re-package and re-upload after each change.
If you changed source, run
npm run buildbeforenpm run package— the Vite output is gitignored, andbin/package.shsplices the built files into the zip from your working tree.
Clone wordpress-develop and symlink
Gives you the full dev loop: npm run dev rebuilds on save, a browser refresh picks it up.
# clone Core's Docker-based dev host alongside this repo
git clone https://github.com/WordPress/wordpress-develop.git
cd wordpress-develop
npm install
# symlink this plugin into the WP plugins directory
ln -s "$(pwd)/../alcazaba-plugin" src/wp-content/plugins/desktop-mode
# boot + install WordPress
npm run env:start # nginx + PHP + MySQL in Docker
npm run env:install # installs WordPress
Site: http://localhost:8889
Admin: http://localhost:8889/wp-admin/
Credentials: admin / password
Stop the environment with npm run env:stop (from the wordpress-develop directory). Activate the plugin per Quick install steps 2–3.
Requirements
- WordPress 6.0+
- PHP 7.4+
For plugin authors
This plugin is built to be extended. Every significant behavior is hookable — drop an icon on the desktop, add a dock item, gate desktop mode by role, react to window events, or register a native window, all from your own plugin with zero patches here.
See docs/ — the developer documentation index.
Quick links:
- Getting Started — the five-minute tour for plugin authors.
- Architecture — how the pieces fit together.
- Hooks Reference — every action and filter we fire, with signatures and examples.
- JavaScript Reference — CustomEvents,
window.wp.desktopAPI, and the iframepostMessagebridge. - Examples — copy-paste recipes.
License
GPLv2 or later. See LICENSE.