PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
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 0.8.7 All 34 releases
← All changes | includes/shell-screen.php +86 -11 1.1.51.1.10 View file →
@@ -75,8 +75,44 @@
75 75 */
76 76 const OPENSTATION_SHELL_INTENT_ARG = 'intent';
77 77
78 78 /**
79 + * Query arg asking the shell screen to boot straight into overview: how
80 + * a switch from another site's overview lands in this one's, tiles and
81 + * all (on a network every site is its own OpenStation, see
82 + * docs/multisite.md). One-shot like the two above — read here, handed
83 + * to the shell as `landInOverview`, stripped from the address bar.
84 + */
85 +const OPENSTATION_SHELL_OVERVIEW_ARG = 'openstation_overview';
86 +
87 +/**
88 + * Whether this shell-screen request asked to boot into overview.
89 + *
90 + * @return bool
91 + */
92 +function openstation_shell_lands_in_overview() {
93 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing flag.
94 + return openstation_is_shell_screen_request() && ! empty( $_GET[ OPENSTATION_SHELL_OVERVIEW_ARG ] );
95 +}
96 +
97 +/**
98 + * The side this shell slides its desk in from, when it was reached by a
99 + * switch from another origin: `next`, `prev`, or ''. A one-shot boot
100 + * arg like the two above (`openstation_hop_from`), because the hint a
101 + * same-origin switch leaves in sessionStorage never crosses origins.
102 + *
103 + * @return string
104 + */
105 +function openstation_shell_arrival_direction() {
106 + if ( ! openstation_is_shell_screen_request() ) {
107 + return '';
108 + }
109 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only routing flag.
110 + $from = isset( $_GET[ OPENSTATION_NETWORK_HOP_FROM_ARG ] ) && is_scalar( $_GET[ OPENSTATION_NETWORK_HOP_FROM_ARG ] ) ? sanitize_key( wp_unslash( $_GET[ OPENSTATION_NETWORK_HOP_FROM_ARG ] ) ) : '';
111 + return in_array( $from, array( 'next', 'prev' ), true ) ? $from : '';
112 +}
113 +
114 +/**
79 115 * Builds the shell screen URL, optionally carrying a target.
80 116 *
81 117 * `$target` is an absolute same-origin admin URL or a request-URI-shaped
82 118 * path (`/wp-admin/edit.php?post_type=page`). Either way only its path
@@ -84,18 +120,37 @@
84 120 * {@see openstation_sanitize_portal_target()}, so the parameter is
85 121 * never trusted from the URL alone. An empty target yields the bare
86 122 * screen URL and the screen resolves the entry itself.
87 123 *
88 - * @param string $target Admin URL to open first, or '' for none.
89 - * @param bool $intent Whether the target is the user's navigation intent.
124 + * The screen exists in both admins, so the URL follows the one the
125 + * caller is in. `$network` overrides that for callers with no context
126 + * of their own: `admin-ajax.php` is never the network admin, whatever
127 + * the click that reached it.
128 + *
129 + * @param string $target Admin URL to open first, or '' for none.
130 + * @param bool $intent Whether the target is the user's navigation intent.
131 + * @param bool|null $network Force the network screen (true) or the site
132 + * one (false). Null follows the request.
90 133 * @return string Absolute shell screen URL.
91 134 */
92 -function openstation_shell_url( $target = '', $intent = false ) {
93 - $url = admin_url( 'admin.php?page=' . OPENSTATION_SHELL_PAGE_SLUG );
135 +function openstation_shell_url( $target = '', $intent = false, $network = null ) {
136 + $target = is_string( $target ) ? openstation_shell_normalize_admin_url( $target ) : '';
137 + $path = '' !== $target ? wp_parse_url( $target, PHP_URL_PATH ) : '';
94 138
95 - $target = is_string( $target ) ? openstation_shell_normalize_admin_url( $target ) : '';
139 + if ( null === $network ) {
140 + // Follow the admin the TARGET lives in, falling back to the
141 + // request's own. The network dashboard opened on the site
142 + // screen would be one admin inside another's shell, which is
143 + // what the bridge refuses on a link click for the same reason.
144 + $network = is_string( $path ) && '' !== $path
145 + ? false !== strpos( $path, '/wp-admin/network/' )
146 + : is_network_admin();
147 + }
148 +
149 + $screen = 'admin.php?page=' . OPENSTATION_SHELL_PAGE_SLUG;
150 + $url = $network ? network_admin_url( $screen ) : admin_url( $screen );
151 +
96 152 if ( '' !== $target ) {
97 - $path = wp_parse_url( $target, PHP_URL_PATH );
98 153 $query = wp_parse_url( $target, PHP_URL_QUERY );
99 154 if ( is_string( $path ) && '' !== $path ) {
100 155 $relative = $path . ( is_string( $query ) && '' !== $query ? '?' . $query : '' );
101 156 $url = add_query_arg( OPENSTATION_SHELL_TARGET_ARG, rawurlencode( $relative ), $url );
@@ -187,9 +242,15 @@
187 242 }
188 243 if ( function_exists( 'get_current_screen' ) ) {
189 244 $screen = get_current_screen();
190 245 if ( $screen instanceof WP_Screen ) {
191 - return OPENSTATION_SHELL_SCREEN_ID === $screen->id;
246 + // WordPress suffixes screen ids in the network admin, so
247 + // the network shell is `admin_page_openstation-network`.
248 + return in_array(
249 + $screen->id,
250 + array( OPENSTATION_SHELL_SCREEN_ID, OPENSTATION_SHELL_SCREEN_ID . '-network' ),
251 + true
252 + );
192 253 }
193 254 }
194 255 global $pagenow, $plugin_page;
195 256 return 'admin.php' === $pagenow
@@ -251,8 +312,13 @@
251 312 add_action( "load-{$hook}", 'openstation_shell_screen_set_title' );
252 313 }
253 314 }
254 315 add_action( 'admin_menu', 'openstation_register_shell_screen' );
316 +// The network admin builds its menu from its own hook, and the desktop
317 +// is reachable there for the same reason it is on a site: it is where
318 +// the network's own admin pages are. `network/admin.php` routes
319 +// `?page=` exactly as `admin.php` does.
320 +add_action( 'network_admin_menu', 'openstation_register_shell_screen' );
255 321
256 322 /**
257 323 * Names the shell document, before `admin-header.php` asks for a name.
258 324 *
@@ -351,19 +417,28 @@
351 417 $intent = ! empty( $_GET[ OPENSTATION_SHELL_INTENT_ARG ] );
352 418 }
353 419 }
354 420 if ( '' === $target ) {
355 - $target = openstation_portal_entry_url( get_current_user_id() );
421 + // The network screen has its own dashboard to fall back to;
422 + // the saved session belongs to a site, so it would open one
423 + // admin's window on the other's desktop.
424 + $target = is_network_admin()
425 + ? network_admin_url( 'index.php' )
426 + : openstation_portal_entry_url( get_current_user_id() );
356 427 }
357 428 $target = openstation_shell_normalize_admin_url( $target );
358 429
359 - // `admin_url()` alone names the directory; `$pagenow` on that
430 + // An admin URL alone names the directory; `$pagenow` on that
360 431 // request is `index.php`, and the dock derives the Dashboard's
361 - // window id from the file. Keep both sides deriving the same id.
432 + // window id from the file. Keep both sides deriving the same id,
433 + // naming the file inside the target's OWN admin so a network
434 + // URL does not resolve to the site's dashboard.
362 435 $path = wp_parse_url( $target, PHP_URL_PATH );
363 436 if ( is_string( $path ) && '/' === substr( $path, -1 ) ) {
364 437 $query = wp_parse_url( $target, PHP_URL_QUERY );
365 - $target = admin_url( 'index.php' ) . ( is_string( $query ) && '' !== $query ? '?' . $query : '' );
438 + $parts = explode( '?', $target, 2 );
439 + $target = rtrim( $parts[0], '/' ) . '/index.php'
440 + . ( is_string( $query ) && '' !== $query ? '?' . $query : '' );
366 441 }
367 442
368 443 return array(
369 444 'url' => $target,