PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.11
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.11
1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 All 35 releases
← All changes | includes/render/assets.php +94 -53 1.1.5 → 1.1.11 View file →
@@ -89,12 +89,16 @@
89 89 wp_enqueue_style( 'os-window-overview' );
90 90 wp_enqueue_style( 'os-dock' );
91 91 wp_enqueue_style( 'os-dock-peek' );
92 92 wp_enqueue_style( 'os-notch' );
93 + wp_enqueue_style( 'os-workspaces' );
93 94 wp_enqueue_style( 'os-shortcuts' );
94 95 wp_enqueue_style( 'os-openstation-layout' );
95 96 wp_enqueue_style( 'os-files' );
96 97 wp_enqueue_style( 'os-notes' );
98 + // Unconditional like the layout sheet: a live crossing into the
99 + // phone band must not find the phone layer unstyled.
100 + wp_enqueue_style( 'os-mobile' );
97 101
98 102 // Solo mode — a single window freed into a native OS window by the
99 103 // desktop host. Same shell, everything but that one window hidden.
100 104 $solo_window = openstation_solo_window_id();
@@ -217,11 +221,11 @@
217 221 // plugin-contributed top-level routes. `openstation_dock_placement`
218 222 // is the per-item filter escape hatch for hiding. Shared with the
219 223 // REST menu endpoint so live refreshes (post plugin-activation)
220 224 // produce the same ordering as the boot payload.
221 - $menu_payload = openstation_build_menu_payload();
222 - $dock_items = $menu_payload['dockItems'];
223 - $native_windows = isset( $menu_payload['nativeWindows'] )
225 + $menu_payload = openstation_build_menu_payload();
226 + $dock_items = $menu_payload['dockItems'];
227 + $native_windows = isset( $menu_payload['nativeWindows'] )
224 228 ? $menu_payload['nativeWindows']
225 229 : array();
226 230
227 231 // The BOOT page prints every registry window's template as a real
@@ -329,9 +333,9 @@
329 333 $desktop_theme_row['cssDeferred'] = true;
330 334 }
331 335 }
332 336 unset( $desktop_theme_row );
333 - $desktop_icons = isset( $menu_payload['desktopIcons'] )
337 + $desktop_icons = isset( $menu_payload['desktopIcons'] )
334 338 ? $menu_payload['desktopIcons']
335 339 : array();
336 340
337 341 // Files-on-the-Desktop payload (Phase 0+1). Plugin-registered
@@ -342,8 +346,16 @@
342 346 : array();
343 347 $server_file_openers = function_exists( 'openstation_build_file_openers_payload' )
344 348 ? openstation_build_file_openers_payload()
345 349 : array();
350 + // Entries in the menu payload carry dependency handles; their
351 + // payloads ride once in `scriptDepPayloads` (GH#892). The file
352 + // lists stay whole: no sync module reads them on the client, and
353 + // compacting them here was the only write to the map after the
354 + // menu payload froze its own, so a refresh could not match it.
355 + $script_dep_payloads = isset( $menu_payload['scriptDepPayloads'] )
356 + ? (array) $menu_payload['scriptDepPayloads']
357 + : array();
346 358 $user_file_associations = function_exists( 'openstation_get_user_file_associations' )
347 359 ? openstation_get_user_file_associations( get_current_user_id() )
348 360 : array();
349 361 $server_wallpaper_menu_items = function_exists( 'openstation_build_wallpaper_menu_items' )
@@ -507,9 +519,13 @@
507 519 array(
508 520 'currentPage' => esc_url( $current_page ),
509 521 'currentTitle' => $current_title,
510 522 'currentIcon' => sanitize_html_class( $menu_icon ),
511 - 'adminUrl' => esc_url( admin_url() ),
523 + // `self_admin_url()`: the base a window id is derived from,
524 + // and the URL the shell leaves for on exit. Both want the
525 + // admin the screen is in, which is the network one when the
526 + // network shell screen is what rendered.
527 + 'adminUrl' => esc_url( self_admin_url() ),
512 528 'homeUrl' => esc_url( home_url( '/' ) ),
513 529 // Decoded: the shell assigns this to `window.location`,
514 530 // where `&` would make `_wpnonce` arrive as
515 531 // `amp;_wpnonce` and fail the nonce check.
@@ -553,8 +569,11 @@
553 569 'serverDesktopThemes' => $server_desktop_themes,
554 570 'desktopIcons' => $desktop_icons,
555 571 'serverFileTypes' => $server_file_types,
556 572 'serverFileOpeners' => $server_file_openers,
573 + // Handle => dependency payload for every `scriptDeps` list in
574 + // this config; see `openstation_compact_script_deps()`.
575 + 'scriptDepPayloads' => (object) $script_dep_payloads,
557 576 'userFileAssociations' => $user_file_associations,
558 577 'filesUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/files' ) ),
559 578 // Pinned-notes REST base (`includes/notes/rest.php`). The
560 579 // notes layer boots only when this is present.
@@ -570,9 +589,17 @@
570 589 'coreNotices' => openstation_get_core_notices(),
571 590 'pluginNotices' => openstation_get_plugin_notices(),
572 591 'defaultWallpaper' => openstation_get_default_wallpaper(),
573 592 'session' => openstation_get_session( get_current_user_id() ),
574 - 'sessionUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/session' ) ),
593 + // The session route runs in the main site's blog context
594 + // whichever desktop posts to it, so the network screen's
595 + // URL says which session it is addressing — see
596 + // `openstation_rest_session_network()`.
597 + 'sessionUrl' => esc_url_raw(
598 + is_network_admin()
599 + ? add_query_arg( 'network', '1', rest_url( 'desktop-mode/v1/session' ) )
600 + : rest_url( 'desktop-mode/v1/session' )
601 + ),
575 602 'restUrl' => esc_url_raw( rest_url() ),
576 603 'mediaUrl' => esc_url_raw( rest_url( 'wp/v2/media' ) ),
577 604 'dropConfig' => $drop_config,
578 605 'defaultWindowUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/default-window' ) ),
@@ -595,15 +622,8 @@
595 622 // stub `<script>`-injects this URL the first time the user
596 623 // opens the assistant. Picking `.js` vs `.min.js` here keeps
597 624 // the SCRIPT_DEBUG gate server-side, matching iframeBridgeUrl.
598 625 'aiAssistantBundleUrl' => $lazy_bundle_url( 'ai-assistant' ),
599 - // URL of the OS Settings panel lazy bundle. Injected by
600 - // the main bundle's `OsSettings.renderPanel()` stub on
601 - // the user's first Settings open. Holds every section
602 - // renderer + the `<os-*>` components only the panel
603 - // uses, so nothing about Settings ships in
604 - // `desktop.min.js` for users who never open it.
605 - 'osSettingsPanelBundleUrl' => $lazy_bundle_url( 'os-settings-panel' ),
606 626 // URL of the shell-overlays lazy bundle. Pre-loaded by
607 627 // the main bundle after first paint so action-triggered
608 628 // overlays (toast, confirm dialog, context menus) feel
609 629 // instant the first time they fire.
@@ -658,12 +678,29 @@
658 678 // / `openNew()` call (both async); pre-loaded
659 679 // by the shell after first paint when no session is being
660 680 // restored and no `openCurrentPage` will fire.
661 681 'windowSystemBundleUrl' => $lazy_bundle_url( 'window-system' ),
682 + // URL of the lazy phone-layer bundle. Injected by the main
683 + // bundle only when the mode resolves to `mobile`, so a
684 + // desktop never fetches it. `mode` carries the preference
685 + // and breakpoints the first-paint head stamp already used,
686 + // plus the server's default tab-bar pins — see
687 + // `includes/mobile.php`.
688 + 'mobileBundleUrl' => $lazy_bundle_url( 'mobile' ),
689 + 'mode' => openstation_mode_config( get_current_user_id() ),
662 690 // URL of the item-visibility-menu lazy bundle — the
663 691 // right-click "hide from dock / desktop" menu. Injected by
664 692 // the main bundle's loader shim on the first right-click.
665 693 'itemVisibilityMenuBundleUrl' => $lazy_bundle_url( 'item-visibility-menu' ),
694 + // URL of the workspace-wizard lazy bundle — the modal
695 + // behind "Edit this workspace…". Injected by the main
696 + // bundle's loader shim on first open.
697 + 'workspaceWizardBundleUrl' => $lazy_bundle_url( 'workspace-wizard' ),
698 + // Server-side view of the workspace templates, so a plugin
699 + // can add or drop one from PHP. The client merges these
700 + // with its own built-ins by id — see
701 + // `src/workspaces/server-sync.ts`.
702 + 'workspacePresets' => openstation_workspace_presets(),
666 703 // URL of the release-card lazy bundle — the vinyl core-
667 704 // update announcement. Injected by `maybeShowUpdate()` only
668 705 // when a core update is actually pending.
669 706 'releaseCardBundleUrl' => $lazy_bundle_url( 'release-card' ),
@@ -695,38 +732,21 @@
695 732 // Site-wide games kill switch (Extended options). Exposed to
696 733 // every user — the shell skips the challenges Heartbeat
697 734 // channel when the framework is off.
698 735 'gamesEnabled' => openstation_games_enabled(),
699 - // Comments-window AI moderation toggle — surfaced at the
700 - // shell level so the OS Settings → Features tab can render
701 - // the toggle without depending on the Comments window
702 - // being registered for this user. URL is the same
703 - // endpoint the comments-window config exposes; state is
704 - // `null` for non-admins (the UI hides the row entirely).
705 - 'commentsAiUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/comments/ai-settings' ) ),
706 - // Non-null only for admins on a site where the Core AI stack is
707 - // present. Comment scoring routes through the AI Client (WP 7.0+),
708 - // so on older WordPress the whole row is hidden — same as the
709 - // assistant toggle — rather than shown disabled pointing at a
710 - // Settings → Connectors screen that doesn't exist there.
711 - 'commentsAi' => (
712 - current_user_can( 'manage_options' )
713 - && function_exists( 'openstation_ai_is_available' )
714 - && openstation_ai_is_available()
715 - )
716 - ? array(
717 - 'enabled' => function_exists( 'openstation_comments_ai_is_enabled' )
718 - ? openstation_comments_ai_is_enabled()
719 - : false,
720 - 'providerConfigured' => function_exists( 'openstation_comments_ai_provider_configured' )
721 - ? openstation_comments_ai_provider_configured()
722 - : false,
723 - )
724 - : null,
725 736 'currentUserIsAdmin' => current_user_can( 'manage_options' ),
737 + // Null on single-site installs; its `networkAdmin` null
738 + // without `manage_network`, which is what keeps the dock
739 + // tile from registering.
740 + 'multisite' => openstation_multisite_payload(),
726 741 'portalUrl' => esc_url( openstation_portal_url() ),
727 742 'fromPortal' => $from_portal,
728 743 'fromPortalIntent' => $from_portal_intent,
744 + // One-shot like the boot target: a switch from another
745 + // site's overview lands in this one's.
746 + 'landInOverview' => openstation_shell_lands_in_overview(),
747 + 'arrivalDirection' => openstation_shell_arrival_direction(),
748 + 'hopLinkOffer' => function_exists( 'openstation_network_link_offer' ) ? openstation_network_link_offer() : null,
729 749 'pwa' => array(
730 750 'manifestUrl' => esc_url_raw( openstation_pwa_manifest_url() ),
731 751 'swUrl' => esc_url_raw( openstation_pwa_sw_url() ),
732 752 // Extensionless retry target for hosts whose nginx 404s
@@ -731,8 +751,12 @@
731 751 'swUrl' => esc_url_raw( openstation_pwa_sw_url() ),
732 752 // Extensionless retry target for hosts whose nginx 404s
733 753 // virtual .js paths before WordPress runs (WordPress.com).
734 754 'swFallbackUrl' => esc_url_raw( openstation_pwa_sw_fallback_url() ),
755 + // The site's home path — the scope the registration
756 + // asks for, so a subdirectory network's sites each get
757 + // their own worker instead of fighting over the root.
758 + 'swScope' => openstation_pwa_sw_scope(),
735 759 // The worker's per-user flags, computed HERE rather than
736 760 // baked into the served `sw.js`.
737 761 //
738 762 // A service worker is origin-wide but these are per-user
@@ -738,12 +762,11 @@
738 762 // A service worker is origin-wide but these are per-user
739 763 // preferences, so putting them in the script bytes made
740 764 // the body differ between an anonymous and a logged-in
741 765 // request — and any in-scope logged-out navigation then
742 - // installed a "new" worker and tripped the shell's
743 - // `controllerchange` reload. The bytes are identical for
744 - // everyone now; the shell posts these to the worker at
745 - // boot.
766 + // installed a "new" worker, which at the time reloaded
767 + // the shell. The bytes are identical for everyone now;
768 + // the shell posts these to the worker at boot.
746 769 //
747 770 // Computed server-side, not read from the settings
748 771 // snapshot client-side, because
749 772 // `openstation_pwa_admin_asset_cache_enabled()` applies
@@ -752,8 +775,14 @@
752 775 'swConfig' => array(
753 776 'adminAssetCache' => (bool) openstation_pwa_admin_asset_cache_enabled(),
754 777 'windowPrewarm' => ! empty( openstation_get_os_settings( get_current_user_id() )['windowPrewarmEnabled'] ),
755 778 ),
779 + // The build this shell document belongs to. When a new
780 + // worker takes over mid-session the shell asks it for
781 + // the stamp it was served with and compares; only a
782 + // difference — the shell's own files changed on the
783 + // server — offers the user a reload. Never automatic.
784 + 'shellBuild' => openstation_shell_build_stamp(),
756 785 'stateUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/pwa-state' ) ),
757 786 'state' => openstation_pwa_get_user_state( get_current_user_id() ),
758 787 // Mirrors the manifest's `name` field — used by the
759 788 // install pill so the button reads "Install <site>"
@@ -790,19 +819,19 @@
790 819 : array(),
791 820 'deferredStyles' => openstation_build_deferred_styles(
792 821 array_merge(
793 822 array(
794 - 'os-settings',
795 823 'desktop-mode-ai-assistant',
796 824 'desktop-mode-bug-report',
797 - // WP Explorer's sheet. It rides that window as a
798 - // companion style, but the desktop FOLDER window
799 - // paints its preview pane with the same
800 - // `os-my-wordpress__*` classes and — being a
801 - // native window opened straight from JS — carries
802 - // no companion styles of its own. Without this,
803 - // the pane rendered unstyled until WP Explorer
804 - // had been opened once in the session.
825 + // The explorer's shared sheet. It rides the WP
826 + // Explorer APP as a companion style, but the
827 + // desktop FOLDER window paints its preview pane
828 + // with the same `os-my-wordpress__*` classes and
829 + // — being a native window opened straight from
830 + // JS — carries no companion styles of its own.
831 + // Without this, the pane rendered unstyled until
832 + // the explorer had been opened once in the
833 + // session.
805 834 'desktop-mode-my-wordpress',
806 835 ),
807 836 // The Games sheets. They also ride the hub window as
808 837 // companion styles, but a game is reachable without
@@ -955,8 +984,21 @@
955 984 'rel' => 'prefetch',
956 985 ),
957 986 );
958 987
988 + // The phone layer is needed at boot on a phone and never on a
989 + // desktop; the server cannot see the viewport, so the user agent
990 + // decides whether the hint is worth its bytes. A wrong guess costs
991 + // one low-priority fetch, never a wrong layout — the stamp and the
992 + // bundle loader read the real viewport.
993 + if ( openstation_mode_hint_is_mobile( get_current_user_id() ) ) {
994 + $hints[] = array(
995 + 'href' => $build_url( 'assets/js/mobile' . $suffix . '.js' ),
996 + 'as' => 'script',
997 + 'rel' => 'prefetch',
998 + );
999 + }
1000 +
959 1001 /**
960 1002 * Filters the list of resource preload hints emitted in `<head>`.
961 1003 *
962 1004 * Each entry is a `{ 'href' => string, 'as' => string,
@@ -1073,9 +1115,8 @@
1073 1115 'os-openstation-layout',
1074 1116 'desktop-mode-ai-assistant',
1075 1117 'desktop-mode-bug-report',
1076 1118 'os-window-overview',
1077 - 'os-settings',
1078 1119 )
1079 1120 );
1080 1121
1081 1122 if ( ! in_array( $handle, (array) $deferred, true ) ) {