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/registries/widgets.php +81 -79 0.9.01.1.10 View file →
@@ -1,11 +1,11 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Widgets registry.
3 + * OpenStation — Widgets registry.
4 4 *
5 5 * Server-side registration API + payload builder + asset enqueue
6 6 * for the right-column widget layer. Plugin-side JS publishes
7 - * the full widget def on `window.desktopModeWidgets[ id ]`; this
7 + * the full widget def on `window.openStationWidgets[ id ]`; this
8 8 * module is the PHP side that announces them and ships their
9 9 * script handles into the boot payload.
10 10 *
11 11 * Extracted from `components.php` during the architecture-0.8.1
@@ -10,10 +10,9 @@
10 10 *
11 11 * Extracted from `components.php` during the architecture-0.8.1
12 12 * PHP slicing (phase 6).
13 13 *
14 - * @package Desktop_Mode
15 - * @since 0.8.1
14 + * @package OpenStation
16 15 */
17 16
18 17 defined( 'ABSPATH' ) || exit;
19 18
@@ -18,9 +17,9 @@
18 17 defined( 'ABSPATH' ) || exit;
19 18
20 19 /**
21 20 * Register a server-side desktop widget. Symmetric to
22 - * {@see desktop_mode_register_window()} for the right-column widget
21 + * {@see openstation_register_window()} for the right-column widget
23 22 * layer: plugin declares the widget's metadata + script handle in
24 23 * PHP; shell syncs its registry from the live payload so
25 24 * activation / deactivation map to picker add / remove without a
26 25 * browser reload.
@@ -26,9 +25,9 @@
26 25 * browser reload.
27 26 *
28 27 * The mount callback still lives in JS — not serializable across
29 28 * the wire. Plugins register it on
30 - * `window.desktopModeWidgets[ <id> ]` as a `(container, ctx) =>
29 + * `window.openStationWidgets[ <id> ]` as a `(container, ctx) =>
31 30 * teardown` function. The shell reads that global once the
32 31 * declared script loads and wraps it into a WidgetDef.
33 32 *
34 33 * Example:
@@ -33,9 +32,9 @@
33 32 *
34 33 * Example:
35 34 *
36 35 * ```php
37 - * desktop_mode_register_widget( 'myplugin/stats', array(
36 + * openstation_register_widget( 'myplugin/stats', array(
38 37 * 'label' => __( 'Stats', 'my-plugin' ),
39 38 * 'description' => __( 'Live analytics rollup', 'my-plugin' ),
40 39 * 'icon' => 'dashicons-chart-bar',
41 40 * 'script' => 'my-plugin-desktop-widgets',
@@ -47,28 +46,27 @@
47 46 * ```
48 47 *
49 48 * ```js
50 49 * // Inside my-plugin-desktop-widgets.js:
51 - * window.desktopModeWidgets = window.desktopModeWidgets || {};
52 - * window.desktopModeWidgets[ 'myplugin/stats' ] = function ( container, ctx ) {
50 + * window.openStationWidgets = window.openStationWidgets || {};
51 + * window.openStationWidgets[ 'myplugin/stats' ] = function ( container, ctx ) {
53 52 * container.append( buildDOM() );
54 53 * return function teardown() { };
55 54 * };
56 55 * ```
57 56 *
58 - * @since 0.10.0
59 - * @since 0.11.0 Returns `WP_Error` on validation failure instead of
60 - * silent `false`. Legacy `if ( $result )` callers remain
61 - * correct because `WP_Error` is truthy.
62 - *
63 57 * @param string $id Widget id. Must match the key the JS side
64 - * uses on `window.desktopModeWidgets[ … ]`.
58 + * uses on `window.openStationWidgets[ … ]`.
65 59 * @param array $args {
66 60 * @type string $label Human-readable picker label. Required.
67 61 * @type string $description Picker subtitle. Default empty.
68 - * @type string $icon Dashicons class for the picker. Required.
62 + * @type string $icon Dashicons class for the picker.
63 + * Default 'dashicons-admin-generic'.
69 64 * @type string $script Enqueued script handle that owns
70 - * the mount callback. Required.
65 + * the mount callback. Optional — omit
66 + * when the mount callback is declared
67 + * by a script already on the shell
68 + * page. Default empty.
71 69 * @type bool $movable Allow drag out of the right column.
72 70 * @type bool $resizable Allow user resize.
73 71 * @type int $min_width
74 72 * @type int $min_height
@@ -77,17 +75,17 @@
77 75 * @type int $default_width First-mount floating width.
78 76 * @type int $default_height First-mount floating height.
79 77 * @type string[] $capabilities Gate: ALL caps must match. Any
80 78 * missed cap returns
81 - * `WP_Error desktop_mode_capability_denied`.
79 + * `WP_Error openstation_capability_denied`.
82 80 * }
83 81 * @return true|WP_Error `true` on success; `WP_Error` otherwise.
84 82 */
85 -function desktop_mode_register_widget( $id, $args = array() ) {
83 +function openstation_register_widget( $id, $args = array() ) {
86 84 $id = (string) $id;
87 85 if ( '' === $id ) {
88 - return desktop_mode_registration_error(
89 - 'desktop_mode_missing_id',
86 + return openstation_registration_error(
87 + 'openstation_missing_id',
90 88 __( 'Widget id is required.', 'desktop-mode' )
91 89 );
92 90 }
93 91
@@ -105,20 +103,23 @@
105 103 'default_width' => 0,
106 104 'default_height' => 0,
107 105 'capabilities' => array(),
108 106 );
109 - $args = wp_parse_args( $args, $defaults );
107 + $args = wp_parse_args( $args, $defaults );
110 108
111 109 foreach ( (array) $args['capabilities'] as $cap ) {
112 110 if ( ! current_user_can( (string) $cap ) ) {
113 - return desktop_mode_registration_error(
114 - 'desktop_mode_capability_denied',
111 + return openstation_registration_error(
112 + 'openstation_capability_denied',
115 113 sprintf(
116 114 /* translators: %s: capability slug. */
117 115 __( 'Current user lacks the %s capability required to register this widget.', 'desktop-mode' ),
118 116 (string) $cap
119 117 ),
120 - array( 'capability' => (string) $cap, 'id' => $id )
118 + array(
119 + 'capability' => (string) $cap,
120 + 'id' => $id,
121 + )
121 122 );
122 123 }
123 124 }
124 125
@@ -125,10 +126,10 @@
125 126 // Required fields. The script handle isn't strictly required —
126 127 // a plugin could register a widget whose mount callback is
127 128 // declared on the shell page's own JS (edge case; still valid).
128 129 if ( '' === (string) $args['label'] ) {
129 - return desktop_mode_registration_error(
130 - 'desktop_mode_missing_label',
130 + return openstation_registration_error(
131 + 'openstation_missing_label',
131 132 __( 'Widget registration requires a non-empty `label`.', 'desktop-mode' ),
132 133 array( 'id' => $id )
133 134 );
134 135 }
@@ -147,22 +148,20 @@
147 148 'max_height' => (int) $args['max_height'],
148 149 'default_width' => (int) $args['default_width'],
149 150 'default_height' => (int) $args['default_height'],
150 151 );
151 - desktop_mode_desktop_widget_registry( $id, $entry );
152 + openstation_desktop_widget_registry( $id, $entry );
152 153
153 154 /**
154 155 * Fires after a desktop widget is successfully registered.
155 156 *
156 - * Does NOT fire when `desktop_mode_register_widget()` returns a
157 + * Does NOT fire when `openstation_register_widget()` returns a
157 158 * `WP_Error`.
158 159 *
159 - * @since 0.11.0
160 - *
161 160 * @param string $id The widget id.
162 161 * @param array $entry The stored registry entry.
163 162 */
164 - do_action( 'desktop_mode_widget_registered', $id, $entry );
163 + do_action( 'openstation_widget_registered', $id, $entry );
165 164
166 165 return true;
167 166 }
168 167
@@ -167,15 +166,14 @@
167 166 }
168 167
169 168 /**
170 169 * Internal module-level registry for widgets registered via
171 - * {@see desktop_mode_register_widget()}. Same pattern as
172 - * {@see desktop_mode_native_window_registry()}.
170 + * {@see openstation_register_widget()}. Same pattern as
171 + * {@see openstation_native_window_registry()}.
173 172 *
174 - * @since 0.10.0
175 173 * @internal
176 174 */
177 -function desktop_mode_desktop_widget_registry( $id = '', $entry = null ) {
175 +function openstation_desktop_widget_registry( $id = '', $entry = null ) {
178 176 static $store = array();
179 177
180 178 if ( '' === (string) $id ) {
181 179 return $store;
@@ -187,19 +185,17 @@
187 185 }
188 186
189 187 /**
190 188 * Build the widget list for the shell payload. Runs through
191 - * every entry registered via `desktop_mode_register_widget()` and
189 + * every entry registered via `openstation_register_widget()` and
192 190 * attaches the resolved script URL (`wp_scripts()` lookup) so
193 191 * the shell can dynamically inject the script on mid-session
194 192 * plugin activation.
195 193 *
196 - * @since 0.10.0
197 - *
198 194 * @return array[]
199 195 */
200 -function desktop_mode_build_desktop_widgets_payload() {
201 - $registry = desktop_mode_desktop_widget_registry();
196 +function openstation_build_desktop_widgets_payload() {
197 + $registry = openstation_desktop_widget_registry();
202 198 if ( ! is_array( $registry ) || empty( $registry ) ) {
203 199 return array();
204 200 }
205 201
@@ -204,28 +200,35 @@
204 200 }
205 201
206 202 $out = array();
207 203 foreach ( $registry as $entry ) {
208 - $script_payload = desktop_mode_resolve_script_payload( $entry['script'] );
204 + $script_payload = openstation_resolve_script_payload( $entry['script'] );
209 205
210 206 $out[] = array(
211 - 'id' => $entry['id'],
212 - 'label' => $entry['label'],
213 - 'description' => $entry['description'],
214 - 'icon' => $entry['icon'],
215 - 'movable' => $entry['movable'],
216 - 'resizable' => $entry['resizable'],
217 - 'minWidth' => $entry['min_width'],
218 - 'minHeight' => $entry['min_height'],
219 - 'maxWidth' => $entry['max_width'],
220 - 'maxHeight' => $entry['max_height'],
221 - 'defaultWidth' => $entry['default_width'],
222 - 'defaultHeight' => $entry['default_height'],
223 - 'scriptUrl' => $script_payload['url'],
224 - 'scriptHandle' => $entry['script'],
225 - 'scriptBefore' => $script_payload['before'],
226 - 'scriptAfter' => $script_payload['after'],
227 - 'scriptL10n' => $script_payload['l10n'],
207 + 'id' => $entry['id'],
208 + 'label' => $entry['label'],
209 + 'description' => $entry['description'],
210 + 'icon' => $entry['icon'],
211 + 'movable' => $entry['movable'],
212 + 'resizable' => $entry['resizable'],
213 + 'minWidth' => $entry['min_width'],
214 + 'minHeight' => $entry['min_height'],
215 + 'maxWidth' => $entry['max_width'],
216 + 'maxHeight' => $entry['max_height'],
217 + 'defaultWidth' => $entry['default_width'],
218 + 'defaultHeight' => $entry['default_height'],
219 + 'scriptUrl' => $script_payload['url'],
220 + // The packages this widget declares, in load order.
221 + // WordPress resolves a script's dependencies when it
222 + // enqueues it; a widget bundle is delivered lazily and
223 + // never goes through that, so a widget declaring
224 + // `wp-api-fetch` found `wp.apiFetch` undefined at mount.
225 + // See docs/migration-wp-package-globals.md.
226 + 'scriptDeps' => openstation_resolve_script_dependencies( $entry['script'] ),
227 + 'scriptHandle' => $entry['script'],
228 + 'scriptBefore' => $script_payload['before'],
229 + 'scriptAfter' => $script_payload['after'],
230 + 'scriptL10n' => $script_payload['l10n'],
228 231 'scriptTranslations' => $script_payload['translations'],
229 232 );
230 233 }
231 234 return $out;
@@ -230,26 +233,25 @@
230 233 }
231 234 return $out;
232 235 }
233 236
234 -/**
235 - * Enqueue plugin-registered widget scripts on the shell page so
236 - * widgets active at boot time have their mount callbacks
237 - * available without any dynamic-load roundtrip.
237 +/*
238 + * Widget scripts are NOT enqueued here, and that is deliberate.
238 239 *
239 - * @since 0.10.0
240 + * Everything the widget picker shows — label, description, icon,
241 + * size constraints — is metadata declared right here in PHP and
242 + * shipped in the boot payload. The only thing a plugin's bundle
243 + * contributes is the `mount` callback, so the shell assembles the
244 + * whole def from the payload and loads the script the first time
245 + * the widget is actually mounted.
246 + *
247 + * A widget the user has never enabled therefore costs a row in the
248 + * picker and nothing else. This file used to `wp_enqueue_script()`
249 + * every registered one on every admin page, which meant the nine
250 + * built-in widget bundles — Drafts at 46 KB, Focus Timer at 41 KB,
251 + * Notes at 31 KB, and the rest — were downloaded and parsed by
252 + * every user whether or not a single widget was on their desktop.
253 + *
254 + * See `src/widgets/server-sync.ts`. `scriptUrl` in the payload
255 + * (built above) is what makes that possible; nothing else on the
256 + * PHP side is involved.
240 257 */
241 -function desktop_mode_enqueue_desktop_widget_scripts() {
242 - if ( ! desktop_mode_is_enabled() || desktop_mode_is_chromeless_request() || desktop_mode_is_classic_request() ) {
243 - return;
244 - }
245 - $registry = desktop_mode_desktop_widget_registry();
246 - if ( ! is_array( $registry ) ) {
247 - return;
248 - }
249 - foreach ( $registry as $entry ) {
250 - if ( ! empty( $entry['script'] ) ) {
251 - wp_enqueue_script( $entry['script'] );
252 - }
253 - }
254 -}
255 -add_action( 'admin_enqueue_scripts', 'desktop_mode_enqueue_desktop_widget_scripts', 20 );