PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.13
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.13
1.1.13 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 All 37 releases
← All changes | includes/os-settings.php +154 -7 1.1.3 → 1.1.13 View file →
@@ -30,8 +30,11 @@
30 30
31 31 /** Valid window-radius IDs — mirrors the TS `WINDOW_RADII` constant. */
32 32 const OPENSTATION_OS_SETTINGS_WINDOW_RADII = array( 'sharp', 'default', 'round' );
33 33
34 +/** How a newly opened window lands — mirrors the TS `OPEN_WINDOWS_AS` constant. */
35 +const OPENSTATION_OS_SETTINGS_OPEN_WINDOWS_AS = array( 'default', 'maximized', 'focused' );
36 +
34 37 /**
35 38 * Valid admin-bar mode IDs — mirrors the TS `ADMIN_BAR_MODES` constant.
36 39 *
37 40 * `static` keeps the WordPress admin bar pinned above the shell (the
@@ -52,8 +55,28 @@
52 55 */
53 56 const OPENSTATION_OS_SETTINGS_DOCK_PLACEMENTS = array( 'bottom', 'left', 'right' );
54 57
55 58 /**
59 + * Valid dock-behavior IDs — mirrors the TS `DOCK_BEHAVIORS` constant.
60 + *
61 + * `static` keeps the dock always on screen (the default); `dynamic`
62 + * parks it off its edge behind a peek strip that reveals when the
63 + * pointer reaches that edge or something on it takes keyboard focus,
64 + * and releases the band it floats over from the work area.
65 + */
66 +const OPENSTATION_OS_SETTINGS_DOCK_BEHAVIORS = array( 'static', 'dynamic' );
67 +
68 +/**
69 + * `mobileLayout` — which experience the shell renders. `auto`
70 + * follows the viewport; the other two force it either way.
71 + * Mirrors `OsModePreference` in `src/mode/index.ts`.
72 + */
73 +const OPENSTATION_OS_SETTINGS_MOBILE_LAYOUTS = array( 'auto', 'desktop', 'mobile' );
74 +
75 +/** `mobileTabs` — at most this many ids pinned to the phone tab bar. */
76 +const OPENSTATION_OS_SETTINGS_MOBILE_TABS_MAX = 3;
77 +
78 +/**
56 79 * Playable range for the window-reveal duration override, in ms.
57 80 * Mirrors `MIN_REVEAL_DURATION_MS` / `MAX_REVEAL_DURATION_MS` in
58 81 * `src/reveals/registry.ts`.
59 82 *
@@ -73,8 +96,10 @@
73 96 */
74 97 function openstation_default_os_settings() {
75 98 return array(
76 99 'wallpaper' => 'galaxy',
100 + // Pulse, the brand's signature. Mirrors `DEFAULTS` in
101 + // `src/settings/constants.ts`.
77 102 'accent' => 'pulse',
78 103 // Only read when `accent` is `custom`. Seeded with Pulse so
79 104 // picking Custom before touching the wheel is a no-op rather
80 105 // than a jump to black. Mirrors `DEFAULTS` in
@@ -88,8 +113,9 @@
88 113 // `src/settings/constants.ts` — PHP seeds the first load and JS
89 114 // owns every paint after it, so a mismatch shows up as the
90 115 // corners changing shape a moment after the shell boots.
91 116 'windowRadius' => 'round',
117 + 'openWindowsAs' => 'default',
92 118 // How the WordPress admin bar presents above the shell.
93 119 // `hidden` ships as the default so a fresh desktop has ONE
94 120 // navigation surface: everything the user can open lives on the
95 121 // dock, and the dock's "Exit OpenStation" tile is the way back
@@ -95,8 +121,14 @@
95 121 // dock, and the dock's "Exit OpenStation" tile is the way back
96 122 // to classic admin. `static` (vanilla behavior) and `dynamic`
97 123 // are one pick away in OpenStation Preferences → Appearance.
98 124 'adminBarMode' => 'hidden',
125 + // Always on screen. `dynamic` (auto-hide behind a peek strip)
126 + // is one pick away in OpenStation Preferences → Appearance.
127 + 'dockBehavior' => 'static',
128 + // The Split layout's sidebar answers for itself: a folded
129 + // sidebar over a static bottom dock is a valid desk.
130 + 'sideDockBehavior' => 'static',
99 131 // One dock holding every menu, with the system tiles grouped
100 132 // behind a hairline. `classic` (side bar for core menus + bottom
101 133 // dock for plugins) is the other option; it is no longer what a
102 134 // first-run desktop looks like.
@@ -184,8 +216,13 @@
184 216 // window (e.g. array( 'author', 'tags' )). Empty array means
185 217 // every column is visible. The sticky 'title' column is always
186 218 // shown — the UI prevents toggling it.
187 219 'nativePostsHiddenColumns' => array(),
220 + // Per-user list of column keys hidden in the native Pages
221 + // window (e.g. array( 'author', 'parent' )). Empty array means
222 + // every column is visible. The sticky 'title' column is always
223 + // shown — the UI prevents toggling it.
224 + 'nativePagesHiddenColumns' => array(),
188 225 // Per-user opt-IN for the native Pages window. Same posture as
189 226 // nativePostsEnabled — defaults OFF (Beta), users opt in to swap
190 227 // the classic `edit.php?post_type=page` iframe for the native UI.
191 228 'nativePagesEnabled' => false,
@@ -208,8 +245,11 @@
208 245 // (including any custom dashboard a plugin builds there) opens
209 246 // as a chromeless iframe until the user opts in via OS
210 247 // Settings → Features → Beta features.
211 248 'stationHomeEnabled' => false,
249 + // Performance enhancements are enabled unless explicitly disabled.
250 + 'adminAssetCacheEnabled' => true,
251 + 'windowPrewarmEnabled' => true,
212 252 // When true, left-clicking the empty wallpaper triggers the
213 253 // "Show desktop" toggle (macOS-style) and the matching entry is
214 254 // hidden from the wallpaper context menu. When false (default),
215 255 // the entry stays in the menu and left clicks on the wallpaper
@@ -214,13 +254,20 @@
214 254 // hidden from the wallpaper context menu. When false (default),
215 255 // the entry stays in the menu and left clicks on the wallpaper
216 256 // do nothing. Per-user.
217 257 'showDesktopOnWallpaperClick' => false,
258 + // Whether the close-all-windows shortcut (Alt+Cmd/Ctrl+W) asks
259 + // before it closes. The dialog's "Don't ask again" checkbox is
260 + // what writes false; OpenStation Preferences -> Windows is what
261 + // turns it back on. Per-user.
262 + 'confirmCloseAllWindows' => true,
218 263 // Mio — a soft-body companion that floats over
219 264 // the wallpaper, settles onto nearby windows, and watches the
220 265 // pointer. Off by default; toggled from the wallpaper context
221 266 // menu. Per-user. See `docs/mio.md`.
222 267 'mioEnabled' => false,
268 + 'mioApiEnabled' => false,
269 + 'mioShowOnWallpaper' => true,
223 270 // The user's own Mio, as built in "Make it yours": partial
224 271 // appearance + silhouette overrides, both empty until they
225 272 // touch a control. Stored per user rather than per browser
226 273 // because it is a preference about the person — ten minutes
@@ -271,8 +318,14 @@
271 318 // Per-user ordering, flat across every dock/sidebar zone. Ids
272 319 // not in the list keep their registration order and render
273 320 // after the listed ones. Unknown ids are tolerated.
274 321 'navOrder' => array(),
322 + // Which experience the shell renders: 'auto' follows the
323 + // viewport, 'desktop' / 'mobile' force it. See `includes/mobile.php`.
324 + 'mobileLayout' => 'auto',
325 + // Ids pinned to the phone tab bar, at most three. Empty means
326 + // the server default (`openstation_mobile_tab_bar`).
327 + 'mobileTabs' => array(),
275 328 // Persisted desktop position for every item the user has
276 329 // promoted to the wallpaper via `navPlacement[id]=desktop|both`.
277 330 // Keyed by item id, value is `{ x: int, y: int }`. The JS
278 331 // synthesizer reads this when building a synthetic placement so
@@ -293,14 +346,14 @@
293 346 */
294 347 function openstation_get_os_settings( $user_id ) {
295 348 $user_id = (int) $user_id;
296 349 if ( $user_id <= 0 ) {
297 - return openstation_default_os_settings();
350 + return openstation_sanitize_os_settings( array() );
298 351 }
299 352
300 353 $raw = get_user_meta( $user_id, OPENSTATION_OS_SETTINGS_META_KEY, true );
301 354 if ( ! is_array( $raw ) ) {
302 - return openstation_default_os_settings();
355 + return openstation_sanitize_os_settings( array() );
303 356 }
304 357
305 358 return openstation_sanitize_os_settings( $raw );
306 359 }
@@ -403,16 +456,22 @@
403 456 function openstation_sanitize_os_settings( $raw ) {
404 457 $defaults = openstation_default_os_settings();
405 458
406 459 if ( ! is_array( $raw ) ) {
407 - return $defaults;
460 + $raw = array();
408 461 }
409 462
410 463 // Wallpaper — any non-empty string; registry membership is validated
411 464 // client-side at apply time.
412 - $wallpaper = isset( $raw['wallpaper'] ) && is_string( $raw['wallpaper'] ) && '' !== $raw['wallpaper']
413 - ? sanitize_key( $raw['wallpaper'] )
414 - : $defaults['wallpaper'];
465 + // Key-clean per `/` segment: a desktop theme's wallpapers are
466 + // registered as `desktop-theme/<theme>/<id>`, and a flat
467 + // `sanitize_key()` would fold that into an id nothing answers to.
468 + $wallpaper = isset( $raw['wallpaper'] ) && is_string( $raw['wallpaper'] )
469 + ? implode( '/', array_filter( array_map( 'sanitize_key', explode( '/', $raw['wallpaper'] ) ) ) )
470 + : '';
471 + if ( '' === $wallpaper ) {
472 + $wallpaper = $defaults['wallpaper'];
473 + }
415 474
416 475 // Accent — non-empty string; swatch validity is enforced in the picker.
417 476 $accent = isset( $raw['accent'] ) && is_string( $raw['accent'] ) && '' !== $raw['accent']
418 477 ? sanitize_key( $raw['accent'] )
@@ -437,8 +496,13 @@
437 496 $window_radius = isset( $raw['windowRadius'] ) && in_array( $raw['windowRadius'], OPENSTATION_OS_SETTINGS_WINDOW_RADII, true )
438 497 ? (string) $raw['windowRadius']
439 498 : $defaults['windowRadius'];
440 499
500 + // How a newly opened window lands — one of the three known values.
501 + $open_windows_as = isset( $raw['openWindowsAs'] ) && in_array( $raw['openWindowsAs'], OPENSTATION_OS_SETTINGS_OPEN_WINDOWS_AS, true )
502 + ? (string) $raw['openWindowsAs']
503 + : $defaults['openWindowsAs'];
504 +
441 505 // Admin-bar mode — must be one of the three known values.
442 506 $admin_bar_mode = isset( $raw['adminBarMode'] )
443 507 && in_array( $raw['adminBarMode'], OPENSTATION_OS_SETTINGS_ADMIN_BAR_MODES, true )
444 508 ? (string) $raw['adminBarMode']
@@ -443,8 +507,19 @@
443 507 && in_array( $raw['adminBarMode'], OPENSTATION_OS_SETTINGS_ADMIN_BAR_MODES, true )
444 508 ? (string) $raw['adminBarMode']
445 509 : $defaults['adminBarMode'];
446 510
511 + // Dock behavior — must be one of the two known values. One answer
512 + // per rail: the dock, and the Split layout's sidebar.
513 + $dock_behavior = isset( $raw['dockBehavior'] )
514 + && in_array( $raw['dockBehavior'], OPENSTATION_OS_SETTINGS_DOCK_BEHAVIORS, true )
515 + ? (string) $raw['dockBehavior']
516 + : $defaults['dockBehavior'];
517 + $side_dock_behavior = isset( $raw['sideDockBehavior'] )
518 + && in_array( $raw['sideDockBehavior'], OPENSTATION_OS_SETTINGS_DOCK_BEHAVIORS, true )
519 + ? (string) $raw['sideDockBehavior']
520 + : $defaults['sideDockBehavior'];
521 +
447 522 // Desktop layout — must be one of the known values (`classic`,
448 523 // `unified`). Default `unified`.
449 524 $desktop_layout = isset( $raw['desktopLayout'] )
450 525 && in_array( $raw['desktopLayout'], OPENSTATION_OS_SETTINGS_DESKTOP_LAYOUTS, true )
@@ -725,8 +800,27 @@
725 800 // user meta indefinitely.
726 801 $native_posts_hidden_columns = array_slice( array_values( array_unique( $native_posts_hidden_columns ) ), 0, 32 );
727 802 }
728 803
804 + $native_pages_hidden_columns = $defaults['nativePagesHiddenColumns'];
805 + if ( isset( $raw['nativePagesHiddenColumns'] ) && is_array( $raw['nativePagesHiddenColumns'] ) ) {
806 + $native_pages_hidden_columns = array();
807 + foreach ( $raw['nativePagesHiddenColumns'] as $col ) {
808 + if ( ! is_string( $col ) || '' === $col ) {
809 + continue;
810 + }
811 + $slug = sanitize_key( $col );
812 + if ( '' === $slug ) {
813 + continue;
814 + }
815 + $native_pages_hidden_columns[] = $slug;
816 + }
817 + // Cap to a sane upper bound — far more than any plausible
818 + // column count, but blocks a malicious payload from bloating
819 + // user meta indefinitely.
820 + $native_pages_hidden_columns = array_slice( array_values( array_unique( $native_pages_hidden_columns ) ), 0, 32 );
821 + }
822 +
729 823 $native_pages_enabled = isset( $raw['nativePagesEnabled'] )
730 824 ? (bool) $raw['nativePagesEnabled']
731 825 : $defaults['nativePagesEnabled'];
732 826
@@ -745,15 +839,25 @@
745 839 $station_home_enabled = isset( $raw['stationHomeEnabled'] )
746 840 ? (bool) $raw['stationHomeEnabled']
747 841 : $defaults['stationHomeEnabled'];
748 842
843 + // Site-wide performance controls supersede the legacy per-user values.
844 + // Keep the snapshot keys so existing window consumers can read them.
845 + $extended_options = openstation_get_extended_options();
846 + $admin_asset_cache_enabled = $extended_options['admin_asset_cache'];
847 + $window_prewarm_enabled = $extended_options['window_prewarm'];
848 +
749 849 $show_desktop_on_wallpaper_click = isset( $raw['showDesktopOnWallpaperClick'] )
750 850 ? (bool) $raw['showDesktopOnWallpaperClick']
751 851 : $defaults['showDesktopOnWallpaperClick'];
752 852
853 + $confirm_close_all_windows = isset( $raw['confirmCloseAllWindows'] )
854 + ? (bool) $raw['confirmCloseAllWindows']
855 + : $defaults['confirmCloseAllWindows'];
856 +
753 857 $mio_enabled = isset( $raw['mioEnabled'] )
754 858 ? (bool) $raw['mioEnabled']
755 - : $defaults['mioEnabled'];
859 + : ( isset( $raw['mioApiEnabled'] ) ? (bool) $raw['mioApiEnabled'] : $defaults['mioEnabled'] );
756 860
757 861 // A missing key means "no look saved yet", which sanitizes to the
758 862 // same pair of empty arrays the defaults carry — so this needs no
759 863 // isset() branch of its own.
@@ -768,8 +872,35 @@
768 872 $developer_mode_enabled = isset( $raw['developerModeEnabled'] )
769 873 ? (bool) $raw['developerModeEnabled']
770 874 : $defaults['developerModeEnabled'];
771 875
876 + // mobileLayout — the phone/desktop override.
877 + $mobile_layout = isset( $raw['mobileLayout'] )
878 + && in_array( $raw['mobileLayout'], OPENSTATION_OS_SETTINGS_MOBILE_LAYOUTS, true )
879 + ? (string) $raw['mobileLayout']
880 + : $defaults['mobileLayout'];
881 +
882 + // mobileTabs — ordered nav ids pinned to the phone tab bar. Same
883 + // id grammar as navOrder, capped at the tab bar's slot count.
884 + $mobile_tabs = array();
885 + if ( isset( $raw['mobileTabs'] ) && is_array( $raw['mobileTabs'] ) ) {
886 + $seen_tabs = array();
887 + foreach ( $raw['mobileTabs'] as $id ) {
888 + if ( ! is_string( $id ) || '' === $id ) {
889 + continue;
890 + }
891 + $slug = sanitize_key( openstation_canonical_nav_id( $id ) );
892 + if ( '' === $slug || isset( $seen_tabs[ $slug ] ) ) {
893 + continue;
894 + }
895 + $seen_tabs[ $slug ] = true;
896 + $mobile_tabs[] = $slug;
897 + if ( count( $mobile_tabs ) >= OPENSTATION_OS_SETTINGS_MOBILE_TABS_MAX ) {
898 + break;
899 + }
900 + }
901 + }
902 +
772 903 $folders_sharing_enabled = isset( $raw['foldersSharingEnabled'] )
773 904 ? (bool) $raw['foldersSharingEnabled']
774 905 : $defaults['foldersSharingEnabled'];
775 906
@@ -887,11 +1018,14 @@
887 1018 'accent' => $accent,
888 1019 'customAccent' => $custom_accent,
889 1020 'dockSize' => $dock_size,
890 1021 'windowRadius' => $window_radius,
1022 + 'openWindowsAs' => $open_windows_as,
891 1023 'adminBarMode' => $admin_bar_mode,
892 1024 'desktopLayout' => $desktop_layout,
893 1025 'dockPlacement' => $dock_placement,
1026 + 'dockBehavior' => $dock_behavior,
1027 + 'sideDockBehavior' => $side_dock_behavior,
894 1028 'dockRailRenderer' => $dock_rail_renderer,
895 1029 'desktopTheme' => $desktop_theme,
896 1030 'appliedThemeRecommendations' => $applied_theme_recommendations,
897 1031 'unfocusEffect' => $unfocus_effect,
@@ -910,14 +1044,20 @@
910 1044 'heartbeatRate' => $heartbeat_rate,
911 1045 'nativePostsEnabled' => $native_posts_enabled,
912 1046 'nativePostsHiddenColumns' => $native_posts_hidden_columns,
913 1047 'nativePagesEnabled' => $native_pages_enabled,
1048 + 'nativePagesHiddenColumns' => $native_pages_hidden_columns,
914 1049 'nativeUsersEnabled' => $native_users_enabled,
915 1050 'nativePluginsEnabled' => $native_plugins_enabled,
916 1051 'nativeCommentsEnabled' => $native_comments_enabled,
917 1052 'stationHomeEnabled' => $station_home_enabled,
1053 + 'adminAssetCacheEnabled' => $admin_asset_cache_enabled,
1054 + 'windowPrewarmEnabled' => $window_prewarm_enabled,
918 1055 'showDesktopOnWallpaperClick' => $show_desktop_on_wallpaper_click,
1056 + 'confirmCloseAllWindows' => $confirm_close_all_windows,
919 1057 'mioEnabled' => $mio_enabled,
1058 + 'mioApiEnabled' => $mio_enabled,
1059 + 'mioShowOnWallpaper' => isset( $raw['mioShowOnWallpaper'] ) ? (bool) $raw['mioShowOnWallpaper'] : $defaults['mioShowOnWallpaper'],
920 1060 'mioStyle' => $mio_style,
921 1061 'showPostStatusRibbons' => $show_post_status_ribbons,
922 1062 'developerModeEnabled' => $developer_mode_enabled,
923 1063 'foldersSharingEnabled' => $folders_sharing_enabled,
@@ -922,8 +1062,10 @@
922 1062 'developerModeEnabled' => $developer_mode_enabled,
923 1063 'foldersSharingEnabled' => $folders_sharing_enabled,
924 1064 'navPlacement' => $nav_placement,
925 1065 'navOrder' => $nav_order,
1066 + 'mobileLayout' => $mobile_layout,
1067 + 'mobileTabs' => $mobile_tabs,
926 1068 'dockPromotedPositions' => $dock_promoted_positions,
927 1069 );
928 1070 }
929 1071
@@ -1023,8 +1165,13 @@
1023 1165 // true of every path into this handler, not just the ones the
1024 1166 // schema happens to guard.
1025 1167 if ( ! is_array( $payload ) ) {
1026 1168 return rest_ensure_response( openstation_get_os_settings( $user_id ) );
1169 + }
1170 +
1171 + // Normalize an alias-only patch before merging it with the saved master value.
1172 + if ( ! array_key_exists( 'mioEnabled', $payload ) && array_key_exists( 'mioApiEnabled', $payload ) ) {
1173 + $payload['mioEnabled'] = $payload['mioApiEnabled'];
1027 1174 }
1028 1175
1029 1176 openstation_save_os_settings(
1030 1177 $user_id,