PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.12
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.12
1.1.12 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 All 36 releases
← All changes | includes/render/assets.php +146 -73 1.1.4 → 1.1.12 View file →
@@ -73,9 +73,9 @@
73 73 do_action( 'openstation_chromeless_styles' );
74 74 return;
75 75 }
76 76
77 - if ( ! openstation_is_enabled() || openstation_is_classic_request() ) {
77 + if ( ! openstation_is_shell_request() ) {
78 78 return;
79 79 }
80 80
81 81 // CSS. Only the sheets that paint surfaces present at boot — the
@@ -88,13 +88,16 @@
88 88 wp_enqueue_style( 'os-windows' );
89 89 wp_enqueue_style( 'os-window-overview' );
90 90 wp_enqueue_style( 'os-dock' );
91 91 wp_enqueue_style( 'os-dock-peek' );
92 - wp_enqueue_style( 'os-notch' );
92 + wp_enqueue_style( 'os-workspaces' );
93 93 wp_enqueue_style( 'os-shortcuts' );
94 94 wp_enqueue_style( 'os-openstation-layout' );
95 95 wp_enqueue_style( 'os-files' );
96 96 wp_enqueue_style( 'os-notes' );
97 + // Unconditional like the layout sheet: a live crossing into the
98 + // phone band must not find the phone layer unstyled.
99 + wp_enqueue_style( 'os-mobile' );
97 100
98 101 // Solo mode — a single window freed into a native OS window by the
99 102 // desktop host. Same shell, everything but that one window hidden.
100 103 $solo_window = openstation_solo_window_id();
@@ -199,9 +202,9 @@
199 202 );
200 203 }
201 204
202 205 // Pass configuration to JavaScript.
203 - global $title, $pagenow, $parent_file, $menu;
206 + global $title, $parent_file, $menu;
204 207
205 208 $menu_icon = 'dashicons-admin-generic';
206 209 if ( ! empty( $parent_file ) && ! empty( $menu ) ) {
207 210 foreach ( $menu as $item ) {
@@ -217,11 +220,11 @@
217 220 // plugin-contributed top-level routes. `openstation_dock_placement`
218 221 // is the per-item filter escape hatch for hiding. Shared with the
219 222 // REST menu endpoint so live refreshes (post plugin-activation)
220 223 // 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'] )
224 + $menu_payload = openstation_build_menu_payload();
225 + $dock_items = $menu_payload['dockItems'];
226 + $native_windows = isset( $menu_payload['nativeWindows'] )
224 227 ? $menu_payload['nativeWindows']
225 228 : array();
226 229
227 230 // The BOOT page prints every registry window's template as a real
@@ -329,9 +332,9 @@
329 332 $desktop_theme_row['cssDeferred'] = true;
330 333 }
331 334 }
332 335 unset( $desktop_theme_row );
333 - $desktop_icons = isset( $menu_payload['desktopIcons'] )
336 + $desktop_icons = isset( $menu_payload['desktopIcons'] )
334 337 ? $menu_payload['desktopIcons']
335 338 : array();
336 339
337 340 // Files-on-the-Desktop payload (Phase 0+1). Plugin-registered
@@ -342,8 +345,16 @@
342 345 : array();
343 346 $server_file_openers = function_exists( 'openstation_build_file_openers_payload' )
344 347 ? openstation_build_file_openers_payload()
345 348 : array();
349 + // Entries in the menu payload carry dependency handles; their
350 + // payloads ride once in `scriptDepPayloads` (GH#892). The file
351 + // lists stay whole: no sync module reads them on the client, and
352 + // compacting them here was the only write to the map after the
353 + // menu payload froze its own, so a refresh could not match it.
354 + $script_dep_payloads = isset( $menu_payload['scriptDepPayloads'] )
355 + ? (array) $menu_payload['scriptDepPayloads']
356 + : array();
346 357 $user_file_associations = function_exists( 'openstation_get_user_file_associations' )
347 358 ? openstation_get_user_file_associations( get_current_user_id() )
348 359 : array();
349 360 $server_wallpaper_menu_items = function_exists( 'openstation_build_wallpaper_menu_items' )
@@ -432,18 +443,33 @@
432 443 OPENSTATION_URL . 'assets/js/' . $base . $suffix . '.js?ver=' . $ver
433 444 );
434 445 };
435 446
436 - // Build the current page URL from $pagenow + $_GET. Strip the portal
437 - // markers so the derived window ID matches what the dock would produce
438 - // for the same page — otherwise auto-opening the entry window and
439 - // clicking the same dock icon would create a duplicate.
440 - $current_query = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
441 - unset( $current_query[ OPENSTATION_PORTAL_FLAG ], $current_query[ OPENSTATION_PORTAL_INTENT_FLAG ] );
442 - $current_page = admin_url( $pagenow ) . ( ! empty( $current_query ) ? '?' . http_build_query( $current_query ) : '' );
447 + // The page the shell opens first. On the shell screen it is the
448 + // validated `target` query arg (else the session's focused window,
449 + // the default window, the Dashboard); on a solo boot it is the
450 + // request's own URL. Either way the frozen portal flags are gone
451 + // from it, so the derived window id matches what the dock would
452 + // produce for the same page — otherwise auto-opening the entry
453 + // window and clicking the same dock icon would create a duplicate.
454 + $boot_target = openstation_shell_boot_target();
455 + $current_page = $boot_target['url'];
456 + $from_portal = $boot_target['fromPortal'];
457 + $from_portal_intent = $boot_target['fromPortalIntent'];
443 458
444 - $from_portal = ! empty( $_GET[ OPENSTATION_PORTAL_FLAG ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
445 - $from_portal_intent = ! empty( $_GET[ OPENSTATION_PORTAL_INTENT_FLAG ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
459 + // On the shell screen `$title` and `$parent_file` describe the
460 + // screen ("OpenStation", no menu), not the page about to open. The
461 + // dock entry for that page is the identity the entry window folds
462 + // into, so its title and icon are the right first paint; the iframe
463 + // reports its own title once it lands either way.
464 + $current_title = wp_strip_all_tags( (string) $title );
465 + if ( openstation_is_shell_screen_request() ) {
466 + $boot_meta = openstation_shell_boot_target_meta( $current_page, $dock_items );
467 + $current_title = wp_strip_all_tags( $boot_meta['title'] );
468 + if ( '' !== $boot_meta['icon'] ) {
469 + $menu_icon = $boot_meta['icon'];
470 + }
471 + }
446 472
447 473 /**
448 474 * Filters the desktop shell configuration passed to JavaScript.
449 475 *
@@ -483,9 +509,14 @@
483 509 * @type bool $fromPortal Whether the shell was reached via the portal.
484 510 * @type bool $fromPortalIntent Whether the portal redirect resolved from an explicit `?target=…` (user navigation intent) rather than the session's focused window or the default-window fallback. Distinguishes a bare `/openstation/` visit from a portal-redirected admin-bar click so the shell can honour the URL the user actually asked for.
485 511 * @type array $seenIntros Slugs of one-time announcements the user has dismissed (e.g. `['openstation-rebrand']`).
486 512 * @type string $seenIntrosUrl REST endpoint for the seen-intros surface — POST `/seen` to mark, DELETE the base to reset.
513 + * @type bool $shellTour Whether this site offers the first-boot shell tour (`openstation_show_shell_tour`). Whether this user already had it is `seenIntros` containing `shell-tour`.
514 + * @type string $shellTourBundleUrl URL of the lazy shell-tour bundle, injected on first use.
515 + * @type array $firstRun `{ installedAt, firstEnabledAt, enabledAt }`, epoch seconds, 0 when unknown — the first-run stamps, read-only.
487 516 * @type bool $rebrandNotice Whether to offer this user the one-off announcement explaining the rename from Desktop Mode to OpenStation. True only when migration 5 flagged this user as a Desktop Mode user from before the rename AND they haven't dismissed the `openstation-rebrand` intro. Only ever present in the shell config, so the announcement never reaches the classic admin.
517 + * @type array|null $usageFeedback What the one-time usage feedback prompt needs (`restUrl`), or `null` when this user is not owed it: the feature is off, they have had OpenStation on for fewer than seven days by the `openstation_enabled_at` stamp, or they already answered or dismissed the `usage-feedback` intro. Carries no user data.
518 + * @type string $usageFeedbackBundleUrl URL of the lazy `usage-feedback` bundle, the form the prompt opens.
488 519 * }
489 520 */
490 521 $config = apply_filters(
491 522 'openstation_shell_config',
@@ -490,11 +521,15 @@
490 521 $config = apply_filters(
491 522 'openstation_shell_config',
492 523 array(
493 524 'currentPage' => esc_url( $current_page ),
494 - 'currentTitle' => wp_strip_all_tags( $title ),
525 + 'currentTitle' => $current_title,
495 526 'currentIcon' => sanitize_html_class( $menu_icon ),
496 - 'adminUrl' => esc_url( admin_url() ),
527 + // `self_admin_url()`: the base a window id is derived from,
528 + // and the URL the shell leaves for on exit. Both want the
529 + // admin the screen is in, which is the network one when the
530 + // network shell screen is what rendered.
531 + 'adminUrl' => esc_url( self_admin_url() ),
497 532 'homeUrl' => esc_url( home_url( '/' ) ),
498 533 // Decoded: the shell assigns this to `window.location`,
499 534 // where `&` would make `_wpnonce` arrive as
500 535 // `amp;_wpnonce` and fail the nonce check.
@@ -538,8 +573,11 @@
538 573 'serverDesktopThemes' => $server_desktop_themes,
539 574 'desktopIcons' => $desktop_icons,
540 575 'serverFileTypes' => $server_file_types,
541 576 'serverFileOpeners' => $server_file_openers,
577 + // Handle => dependency payload for every `scriptDeps` list in
578 + // this config; see `openstation_compact_script_deps()`.
579 + 'scriptDepPayloads' => (object) $script_dep_payloads,
542 580 'userFileAssociations' => $user_file_associations,
543 581 'filesUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/files' ) ),
544 582 // Pinned-notes REST base (`includes/notes/rest.php`). The
545 583 // notes layer boots only when this is present.
@@ -555,9 +593,17 @@
555 593 'coreNotices' => openstation_get_core_notices(),
556 594 'pluginNotices' => openstation_get_plugin_notices(),
557 595 'defaultWallpaper' => openstation_get_default_wallpaper(),
558 596 'session' => openstation_get_session( get_current_user_id() ),
559 - 'sessionUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/session' ) ),
597 + // The session route runs in the main site's blog context
598 + // whichever desktop posts to it, so the network screen's
599 + // URL says which session it is addressing — see
600 + // `openstation_rest_session_network()`.
601 + 'sessionUrl' => esc_url_raw(
602 + is_network_admin()
603 + ? add_query_arg( 'network', '1', rest_url( 'desktop-mode/v1/session' ) )
604 + : rest_url( 'desktop-mode/v1/session' )
605 + ),
560 606 'restUrl' => esc_url_raw( rest_url() ),
561 607 'mediaUrl' => esc_url_raw( rest_url( 'wp/v2/media' ) ),
562 608 'dropConfig' => $drop_config,
563 609 'defaultWindowUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/default-window' ) ),
@@ -580,15 +626,8 @@
580 626 // stub `<script>`-injects this URL the first time the user
581 627 // opens the assistant. Picking `.js` vs `.min.js` here keeps
582 628 // the SCRIPT_DEBUG gate server-side, matching iframeBridgeUrl.
583 629 'aiAssistantBundleUrl' => $lazy_bundle_url( 'ai-assistant' ),
584 - // URL of the OS Settings panel lazy bundle. Injected by
585 - // the main bundle's `OsSettings.renderPanel()` stub on
586 - // the user's first Settings open. Holds every section
587 - // renderer + the `<os-*>` components only the panel
588 - // uses, so nothing about Settings ships in
589 - // `desktop.min.js` for users who never open it.
590 - 'osSettingsPanelBundleUrl' => $lazy_bundle_url( 'os-settings-panel' ),
591 630 // URL of the shell-overlays lazy bundle. Pre-loaded by
592 631 // the main bundle after first paint so action-triggered
593 632 // overlays (toast, confirm dialog, context menus) feel
594 633 // instant the first time they fire.
@@ -643,12 +682,29 @@
643 682 // / `openNew()` call (both async); pre-loaded
644 683 // by the shell after first paint when no session is being
645 684 // restored and no `openCurrentPage` will fire.
646 685 'windowSystemBundleUrl' => $lazy_bundle_url( 'window-system' ),
686 + // URL of the lazy phone-layer bundle. Injected by the main
687 + // bundle only when the mode resolves to `mobile`, so a
688 + // desktop never fetches it. `mode` carries the preference
689 + // and breakpoints the first-paint head stamp already used,
690 + // plus the server's default tab-bar pins — see
691 + // `includes/mobile.php`.
692 + 'mobileBundleUrl' => $lazy_bundle_url( 'mobile' ),
693 + 'mode' => openstation_mode_config( get_current_user_id() ),
647 694 // URL of the item-visibility-menu lazy bundle — the
648 695 // right-click "hide from dock / desktop" menu. Injected by
649 696 // the main bundle's loader shim on the first right-click.
650 697 'itemVisibilityMenuBundleUrl' => $lazy_bundle_url( 'item-visibility-menu' ),
698 + // URL of the workspace-wizard lazy bundle — the modal
699 + // behind "Edit this workspace…". Injected by the main
700 + // bundle's loader shim on first open.
701 + 'workspaceWizardBundleUrl' => $lazy_bundle_url( 'workspace-wizard' ),
702 + // Server-side view of the workspace templates, so a plugin
703 + // can add or drop one from PHP. The client merges these
704 + // with its own built-ins by id — see
705 + // `src/workspaces/server-sync.ts`.
706 + 'workspacePresets' => openstation_workspace_presets(),
651 707 // URL of the release-card lazy bundle — the vinyl core-
652 708 // update announcement. Injected by `maybeShowUpdate()` only
653 709 // when a core update is actually pending.
654 710 'releaseCardBundleUrl' => $lazy_bundle_url( 'release-card' ),
@@ -665,8 +721,26 @@
665 721 // announcement yet. Same value that gated `os-announce`
666 722 // above; the dialog cannot paint without that stylesheet, so
667 723 // the two must not diverge.
668 724 'rebrandNotice' => $show_rebrand_notice,
725 + // The first-boot shell tour: whether this site offers it
726 + // (the `openstation_show_shell_tour` filter), and the lazy
727 + // bundle that runs it. Whether THIS user already had it is
728 + // `seenIntros` containing `shell-tour`; the shell reads that
729 + // itself so a reset can replay the tour without a new boot.
730 + 'shellTour' => openstation_should_offer_shell_tour( get_current_user_id() ),
731 + 'shellTourBundleUrl' => $lazy_bundle_url( 'shell-tour' ),
732 + // The first-run stamps, read-only, epoch seconds (0 when
733 + // unknown): when the plugin was installed, when anyone first
734 + // enabled it, and when this user did. See
735 + // `includes/first-run/stamps.php`.
736 + 'firstRun' => openstation_first_run_config( get_current_user_id() ),
737 + // Null for everyone but a user who has had OpenStation on
738 + // long enough and has not answered yet; the gate lives in
739 + // `includes/feedback/usage.php`. The form is a lazy bundle
740 + // fetched only when the user says yes to the prompt.
741 + 'usageFeedback' => function_exists( 'openstation_usage_feedback_config' ) ? openstation_usage_feedback_config() : null,
742 + 'usageFeedbackBundleUrl' => $lazy_bundle_url( 'usage-feedback' ),
669 743 'aiSearchUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/ai/search' ) ),
670 744 // AI assistant availability + per-user toggle. Drives whether the
671 745 // Cmd+K palette and admin-bar icon appear, and the setup placeholder.
672 746 'aiAssistant' => function_exists( 'openstation_ai_assistant_config' )
@@ -680,38 +754,21 @@
680 754 // Site-wide games kill switch (Extended options). Exposed to
681 755 // every user — the shell skips the challenges Heartbeat
682 756 // channel when the framework is off.
683 757 'gamesEnabled' => openstation_games_enabled(),
684 - // Comments-window AI moderation toggle — surfaced at the
685 - // shell level so the OS Settings → Features tab can render
686 - // the toggle without depending on the Comments window
687 - // being registered for this user. URL is the same
688 - // endpoint the comments-window config exposes; state is
689 - // `null` for non-admins (the UI hides the row entirely).
690 - 'commentsAiUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/comments/ai-settings' ) ),
691 - // Non-null only for admins on a site where the Core AI stack is
692 - // present. Comment scoring routes through the AI Client (WP 7.0+),
693 - // so on older WordPress the whole row is hidden — same as the
694 - // assistant toggle — rather than shown disabled pointing at a
695 - // Settings → Connectors screen that doesn't exist there.
696 - 'commentsAi' => (
697 - current_user_can( 'manage_options' )
698 - && function_exists( 'openstation_ai_is_available' )
699 - && openstation_ai_is_available()
700 - )
701 - ? array(
702 - 'enabled' => function_exists( 'openstation_comments_ai_is_enabled' )
703 - ? openstation_comments_ai_is_enabled()
704 - : false,
705 - 'providerConfigured' => function_exists( 'openstation_comments_ai_provider_configured' )
706 - ? openstation_comments_ai_provider_configured()
707 - : false,
708 - )
709 - : null,
710 758 'currentUserIsAdmin' => current_user_can( 'manage_options' ),
759 + // Null on single-site installs; its `networkAdmin` null
760 + // without `manage_network`, which is what keeps the dock
761 + // tile from registering.
762 + 'multisite' => openstation_multisite_payload(),
711 763 'portalUrl' => esc_url( openstation_portal_url() ),
712 764 'fromPortal' => $from_portal,
713 765 'fromPortalIntent' => $from_portal_intent,
766 + // One-shot like the boot target: a switch from another
767 + // site's overview lands in this one's.
768 + 'landInOverview' => openstation_shell_lands_in_overview(),
769 + 'arrivalDirection' => openstation_shell_arrival_direction(),
770 + 'hopLinkOffer' => function_exists( 'openstation_network_link_offer' ) ? openstation_network_link_offer() : null,
714 771 'pwa' => array(
715 772 'manifestUrl' => esc_url_raw( openstation_pwa_manifest_url() ),
716 773 'swUrl' => esc_url_raw( openstation_pwa_sw_url() ),
717 774 // Extensionless retry target for hosts whose nginx 404s
@@ -716,8 +773,12 @@
716 773 'swUrl' => esc_url_raw( openstation_pwa_sw_url() ),
717 774 // Extensionless retry target for hosts whose nginx 404s
718 775 // virtual .js paths before WordPress runs (WordPress.com).
719 776 'swFallbackUrl' => esc_url_raw( openstation_pwa_sw_fallback_url() ),
777 + // The site's home path — the scope the registration
778 + // asks for, so a subdirectory network's sites each get
779 + // their own worker instead of fighting over the root.
780 + 'swScope' => openstation_pwa_sw_scope(),
720 781 // The worker's per-user flags, computed HERE rather than
721 782 // baked into the served `sw.js`.
722 783 //
723 784 // A service worker is origin-wide but these are per-user
@@ -723,12 +784,11 @@
723 784 // A service worker is origin-wide but these are per-user
724 785 // preferences, so putting them in the script bytes made
725 786 // the body differ between an anonymous and a logged-in
726 787 // request — and any in-scope logged-out navigation then
727 - // installed a "new" worker and tripped the shell's
728 - // `controllerchange` reload. The bytes are identical for
729 - // everyone now; the shell posts these to the worker at
730 - // boot.
788 + // installed a "new" worker, which at the time reloaded
789 + // the shell. The bytes are identical for everyone now;
790 + // the shell posts these to the worker at boot.
731 791 //
732 792 // Computed server-side, not read from the settings
733 793 // snapshot client-side, because
734 794 // `openstation_pwa_admin_asset_cache_enabled()` applies
@@ -737,8 +797,14 @@
737 797 'swConfig' => array(
738 798 'adminAssetCache' => (bool) openstation_pwa_admin_asset_cache_enabled(),
739 799 'windowPrewarm' => ! empty( openstation_get_os_settings( get_current_user_id() )['windowPrewarmEnabled'] ),
740 800 ),
801 + // The build this shell document belongs to. When a new
802 + // worker takes over mid-session the shell asks it for
803 + // the stamp it was served with and compares; only a
804 + // difference — the shell's own files changed on the
805 + // server — offers the user a reload. Never automatic.
806 + 'shellBuild' => openstation_shell_build_stamp(),
741 807 'stateUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/pwa-state' ) ),
742 808 'state' => openstation_pwa_get_user_state( get_current_user_id() ),
743 809 // Mirrors the manifest's `name` field — used by the
744 810 // install pill so the button reads "Install <site>"
@@ -775,19 +841,19 @@
775 841 : array(),
776 842 'deferredStyles' => openstation_build_deferred_styles(
777 843 array_merge(
778 844 array(
779 - 'os-settings',
780 845 'desktop-mode-ai-assistant',
781 846 'desktop-mode-bug-report',
782 - // WP Explorer's sheet. It rides that window as a
783 - // companion style, but the desktop FOLDER window
784 - // paints its preview pane with the same
785 - // `os-my-wordpress__*` classes and — being a
786 - // native window opened straight from JS — carries
787 - // no companion styles of its own. Without this,
788 - // the pane rendered unstyled until WP Explorer
789 - // had been opened once in the session.
847 + // The explorer's shared sheet. It rides the WP
848 + // Explorer APP as a companion style, but the
849 + // desktop FOLDER window paints its preview pane
850 + // with the same `os-my-wordpress__*` classes and
851 + // — being a native window opened straight from
852 + // JS — carries no companion styles of its own.
853 + // Without this, the pane rendered unstyled until
854 + // the explorer had been opened once in the
855 + // session.
790 856 'desktop-mode-my-wordpress',
791 857 ),
792 858 // The Games sheets. They also ride the hub window as
793 859 // companion styles, but a game is reachable without
@@ -843,9 +909,9 @@
843 909 * before the callback fires. On WP 6.9 (function exists, no default
844 910 * hook) the `remove_action()` is a harmless no-op.
845 911 */
846 912 function openstation_defer_core_command_palette() {
847 - if ( ! openstation_is_enabled() || openstation_is_chromeless_request() || openstation_is_classic_request() ) {
913 + if ( ! openstation_is_shell_request() ) {
848 914 return;
849 915 }
850 916 remove_action( 'admin_enqueue_scripts', 'wp_enqueue_command_palette_assets' );
851 917 }
@@ -895,14 +961,9 @@
895 961 * supply absolute URLs through the filter; in that case the consumer
896 962 * is responsible for the `crossorigin` semantics.
897 963 */
898 964 function openstation_print_preload_hints() {
899 - if (
900 - ! is_admin()
901 - || ! openstation_is_enabled()
902 - || openstation_is_chromeless_request()
903 - || openstation_is_classic_request()
904 - ) {
965 + if ( ! openstation_is_shell_request() ) {
905 966 return;
906 967 }
907 968
908 969 $suffix = openstation_asset_suffix();
@@ -945,8 +1006,21 @@
945 1006 'rel' => 'prefetch',
946 1007 ),
947 1008 );
948 1009
1010 + // The phone layer is needed at boot on a phone and never on a
1011 + // desktop; the server cannot see the viewport, so the user agent
1012 + // decides whether the hint is worth its bytes. A wrong guess costs
1013 + // one low-priority fetch, never a wrong layout — the stamp and the
1014 + // bundle loader read the real viewport.
1015 + if ( openstation_mode_hint_is_mobile( get_current_user_id() ) ) {
1016 + $hints[] = array(
1017 + 'href' => $build_url( 'assets/js/mobile' . $suffix . '.js' ),
1018 + 'as' => 'script',
1019 + 'rel' => 'prefetch',
1020 + );
1021 + }
1022 +
949 1023 /**
950 1024 * Filters the list of resource preload hints emitted in `<head>`.
951 1025 *
952 1026 * Each entry is a `{ 'href' => string, 'as' => string,
@@ -1063,9 +1137,8 @@
1063 1137 'os-openstation-layout',
1064 1138 'desktop-mode-ai-assistant',
1065 1139 'desktop-mode-bug-report',
1066 1140 'os-window-overview',
1067 - 'os-settings',
1068 1141 )
1069 1142 );
1070 1143
1071 1144 if ( ! in_array( $handle, (array) $deferred, true ) ) {