` URL matches the
// `` hint emitted by
// `desktop_mode_print_preload_hints()` (which stamps with filemtime).
// Registering this with the plain `$version` instead produced two
// different `?ver=` query strings for the same file, so the browser
// never matched the preload to the stylesheet and logged "preloaded
// but not used within a few seconds from the window's load event".
wp_register_style(
'desktop-mode',
DESKTOP_MODE_URL . 'assets/css/desktop.css',
array( 'desktop-mode-variables' ),
$built_version( 'assets/css/desktop.css' )
);
// `filemtime`-stamped — window-chrome iteration (drop overlays,
// new drag affordances, third-party-plugin compat) lands faster
// than plugin version bumps. Without an mtime stamp the browser
// keeps `?ver=` valid for the whole release cycle
// and the user keeps seeing yesterday's CSS even after a hard
// reload. Stamps the parent `windows.css` only; the @imports inside
// (`window-chrome.css`, `window-states.css`, …) inherit the cache
// directive from the parent fetch, so a busted `windows.css` busts
// the whole subtree.
wp_register_style(
'desktop-mode-windows',
DESKTOP_MODE_URL . 'assets/css/windows.css',
array( 'desktop-mode-variables', 'dashicons' ),
$built_version( 'assets/css/windows.css' )
);
wp_register_style(
'desktop-mode-dock',
DESKTOP_MODE_URL . 'assets/css/dock.css',
array( 'desktop-mode-variables', 'dashicons' ),
$version
);
wp_register_style(
'desktop-mode-dock-peek',
DESKTOP_MODE_URL . 'assets/css/dock-peek.css',
array( 'desktop-mode-dock' ),
$version
);
// `filemtime`-stamped — the chromeless overrides iterate faster
// than the plugin-wide version bumps (per-page compat shims and
// page-title-action exceptions land in patches), and a stale
// cached copy means the user sees yesterday's rules. Without the
// stamp, the browser keeps `?ver=0.8.1` valid for the whole
// release cycle.
wp_register_style(
'desktop-mode-chromeless',
DESKTOP_MODE_URL . 'assets/css/chromeless.css',
array( 'desktop-mode' ),
$built_version( 'assets/css/chromeless.css' )
);
// `filemtime`-stamped — the AI assistant surface (error states,
// inline affordances) iterates faster than plugin version bumps.
// Without an mtime stamp the browser keeps `?ver=`
// valid for the whole release cycle and the user keeps seeing
// yesterday's CSS even after a hard reload.
wp_register_style(
'desktop-mode-ai-assistant',
DESKTOP_MODE_URL . 'assets/css/ai-assistant.css',
array( 'desktop-mode-variables' ),
$built_version( 'assets/css/ai-assistant.css' )
);
wp_register_style(
'desktop-mode-bug-report',
DESKTOP_MODE_URL . 'assets/css/bug-report.css',
array( 'desktop-mode-variables' ),
$version
);
// `filemtime` instead of the plugin-wide `$version` for the
// recycle-bin CSS — this file iterates faster than the bundle
// and we never want a stale CSS cache to mask a real fix.
$recycle_bin_css = DESKTOP_MODE_DIR . 'assets/css/recycle-bin.css';
wp_register_style(
'desktop-mode-recycle-bin',
DESKTOP_MODE_URL . 'assets/css/recycle-bin.css',
array( 'desktop-mode-variables', 'dashicons' ),
file_exists( $recycle_bin_css ) ? (string) filemtime( $recycle_bin_css ) : $version
);
// `filemtime` for the native Posts window CSS — same rationale as
// the recycle-bin CSS: bundle iterates faster than the plugin
// version and stale caches are worse than the cost of a 304.
$posts_window_css = DESKTOP_MODE_DIR . 'assets/css/posts-window.css';
wp_register_style(
'desktop-mode-posts-window',
DESKTOP_MODE_URL . 'assets/css/posts-window.css',
array( 'desktop-mode-variables', 'dashicons' ),
file_exists( $posts_window_css ) ? (string) filemtime( $posts_window_css ) : $version
);
// Native Plugins window CSS — same `filemtime`-cache-bust posture
// as the Posts/Recycle Bin styles.
$plugins_window_css = DESKTOP_MODE_DIR . 'assets/css/plugins-window.css';
wp_register_style(
'desktop-mode-plugins-window',
DESKTOP_MODE_URL . 'assets/css/plugins-window.css',
array( 'desktop-mode-variables', 'dashicons' ),
file_exists( $plugins_window_css ) ? (string) filemtime( $plugins_window_css ) : $version
);
// Native Comments window CSS — same `filemtime` posture.
$comments_window_css = DESKTOP_MODE_DIR . 'assets/css/comments-window.css';
wp_register_style(
'desktop-mode-comments-window',
DESKTOP_MODE_URL . 'assets/css/comments-window.css',
array( 'desktop-mode-variables', 'dashicons' ),
file_exists( $comments_window_css ) ? (string) filemtime( $comments_window_css ) : $version
);
// Files-on-the-Desktop tile + layer styles. `filemtime` for the
// same reason as the recycle-bin / posts-window CSS: this file
// iterates faster than the plugin version, and a stale cache
// would mask a real fix.
$desktop_files_css = DESKTOP_MODE_DIR . 'assets/css/desktop-files.css';
wp_register_style(
'desktop-mode-files',
DESKTOP_MODE_URL . 'assets/css/desktop-files.css',
array( 'desktop-mode-variables', 'dashicons' ),
file_exists( $desktop_files_css ) ? (string) filemtime( $desktop_files_css ) : $version
);
// Scripts.
//
// `wp-hooks` — the shell exposes a WordPress-style filter/action
// API (`window.wp.hooks`) to third-party plugins.
// `wp-i18n` — the TS `__()` / `_x()` / `sprintf()` wrappers in
// `src/i18n.ts` delegate to `window.wp.i18n` for translation
// lookups. Both handles are core-shipped but only pre-enqueued
// when Gutenberg-adjacent deps pull them in, so we list them
// explicitly to guarantee load order.
wp_register_script(
'desktop-mode',
DESKTOP_MODE_URL . 'assets/js/desktop' . $suffix . '.js',
// `heartbeat` + `jquery` — the recycle-bin badge module
// (loaded as part of this bundle) opts into the WordPress
// Heartbeat API so the count tile / desktop-icon badge
// stays in sync even when the bin window is closed.
array( 'wp-hooks', 'wp-i18n', 'heartbeat', 'jquery' ),
$built_version( 'assets/js/desktop' . $suffix . '.js' ),
true
);
// `desktop-mode-iframe-bridge` — opt-in iframe-side bridge that
// provides `wp.desktop.iframe.publish/subscribe/onConnection/
// requestConnection` to any same-origin iframe that enqueues it.
// Same code is also injected inline by the chromeless bridge
// (so chromeless wp-admin pages don't need a separate enqueue)
// and auto-injected when a native window opts in via
// `iframeContent: { bridge: true }`. Plugins targeting their
// own iframe pages just enqueue this handle.
wp_register_script(
'desktop-mode-iframe-bridge',
DESKTOP_MODE_URL . 'assets/js/iframe-bridge' . $suffix . '.js',
array(),
$built_version( 'assets/js/iframe-bridge' . $suffix . '.js' ),
true
);
// `desktop-mode-gutenberg-drop-receiver` — iframe-side bundle
// enqueued only on the Block Editor screens (`post.php` /
// `post-new.php`) for desktop-mode users. Listens for
// `desktop-mode-drop` postMessages from the parent shell (see
// `src/drag/iframe-drop-targets.ts`) and inserts the matching
// Gutenberg block via `wp.data.dispatch('core/block-editor')`.
// Depends on `wp-blocks` + `wp-data` so the editor stores are
// guaranteed enqueued before the receiver runs its first message
// handler.
wp_register_script(
'desktop-mode-gutenberg-drop-receiver',
DESKTOP_MODE_URL . 'assets/js/gutenberg-drop-receiver' . $suffix . '.js',
array( 'wp-blocks', 'wp-data' ),
$built_version( 'assets/js/gutenberg-drop-receiver' . $suffix . '.js' ),
true
);
// `desktop-mode-recycle-bin` — small bundle for the Recycle Bin
// native window. Lazy-loaded by the native-window sync the first
// time the bin opens; registers a render callback on
// `window.desktopModeNativeWindows['desktop-mode-recycle-bin']`.
$recycle_bin_js = DESKTOP_MODE_DIR . 'assets/js/recycle-bin' . $suffix . '.js';
wp_register_script(
'desktop-mode-recycle-bin',
DESKTOP_MODE_URL . 'assets/js/recycle-bin' . $suffix . '.js',
// `heartbeat` + `jquery` — the bin opts in to the WordPress
// Heartbeat API while its window is open as the catch-all
// real-time channel for deletes that don't render an admin
// footer (REST/AJAX/other tabs/WP-CLI). See
// `src/recycle-bin/realtime.ts` for the subscriber.
array( 'wp-i18n', 'heartbeat', 'jquery' ),
file_exists( $recycle_bin_js ) ? (string) filemtime( $recycle_bin_js ) : $version,
true
);
wp_set_script_translations(
'desktop-mode-recycle-bin',
'desktop-mode',
DESKTOP_MODE_DIR . 'languages'
);
// `desktop-mode-posts-window` — small bundle for the native Posts
// window. Lazy-loaded by the native-window sync the first time the
// window opens (via the dock-click swap when the user opts in);
// registers a render callback on
// `window.desktopModeNativeWindows['desktop-mode-posts']`.
$posts_window_js = DESKTOP_MODE_DIR . 'assets/js/posts-window' . $suffix . '.js';
wp_register_script(
'desktop-mode-posts-window',
DESKTOP_MODE_URL . 'assets/js/posts-window' . $suffix . '.js',
array( 'wp-i18n' ),
file_exists( $posts_window_js ) ? (string) filemtime( $posts_window_js ) : $version,
true
);
wp_set_script_translations(
'desktop-mode-posts-window',
'desktop-mode',
DESKTOP_MODE_DIR . 'languages'
);
// `desktop-mode-plugins-window` — small bundle for the native
// Plugins window. Lazy-loaded by the native-window sync the first
// time the window opens (via the dock-click swap when the user
// opts in); registers a render callback on
// `window.desktopModeNativeWindows['desktop-mode-plugins']`.
$plugins_window_js = DESKTOP_MODE_DIR . 'assets/js/plugins-window' . $suffix . '.js';
wp_register_script(
'desktop-mode-plugins-window',
DESKTOP_MODE_URL . 'assets/js/plugins-window' . $suffix . '.js',
array( 'wp-i18n' ),
file_exists( $plugins_window_js ) ? (string) filemtime( $plugins_window_js ) : $version,
true
);
wp_set_script_translations(
'desktop-mode-plugins-window',
'desktop-mode',
DESKTOP_MODE_DIR . 'languages'
);
// `desktop-mode-comments-window` — small bundle for the native
// Comments window. Lazy-loaded by the native-window sync the first
// time the window opens (via the dock-click swap when the user
// opts in); registers a render callback on
// `window.desktopModeNativeWindows['desktop-mode-comments']`.
$comments_window_js = DESKTOP_MODE_DIR . 'assets/js/comments-window' . $suffix . '.js';
wp_register_script(
'desktop-mode-comments-window',
DESKTOP_MODE_URL . 'assets/js/comments-window' . $suffix . '.js',
array( 'wp-i18n' ),
file_exists( $comments_window_js ) ? (string) filemtime( $comments_window_js ) : $version,
true
);
wp_set_script_translations(
'desktop-mode-comments-window',
'desktop-mode',
DESKTOP_MODE_DIR . 'languages'
);
// `desktop-mode-animated-logo-wallpaper` — built-in PixiJS canvas
// wallpaper, moved out of `desktop.min.js` in 0.8.4. The wallpaper
// `server-sync` loads this handle when the user selects the
// `wp-animated-logo` wallpaper (or opens OS Settings → Wallpaper
// and the picker pulls every registered canvas def in). The
// bundle's only side effect is publishing the `WallpaperDef` on
// `window.desktopModeWallpapers['wp-animated-logo']`.
$animated_logo_js = DESKTOP_MODE_DIR . 'assets/js/animated-logo-wallpaper' . $suffix . '.js';
wp_register_script(
'desktop-mode-animated-logo-wallpaper',
DESKTOP_MODE_URL . 'assets/js/animated-logo-wallpaper' . $suffix . '.js',
array( 'wp-hooks' ),
file_exists( $animated_logo_js ) ? (string) filemtime( $animated_logo_js ) : $version,
true
);
// `desktop-mode-ai-assistant` — AI Copilot spotlight overlay,
// moved out of `desktop.min.js` in 0.8.4. The main bundle ships a
// stub matching the public `wp.desktop.ai` contract; the stub
// `