PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.9
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.9
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 0.8.6 All 33 releases
desktop-mode / includes / commands.php

commands.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.9, at includes/commands.php

312 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop command registration APIs.
4 *
5 * Two entry points, mirroring the rest of the plugin surface but tuned
6 * for the command-palette use case:
7 *
8 * - `openstation_register_command_script( $handle )` — primary, minimum-
9 * ceremony opt-in. Tells the shell: "this enqueued script registers
10 * slash-commands; include it in the plugins-changed payload so it
11 * gets injected into the shell page mid-session when my plugin is
12 * installed or activated without a full reload."
13 *
14 * - `openstation_register_command( $args )` — optional. Plugins that
15 * want to declare command metadata server-side (for discoverability
16 * tooling, REST enumeration, future pre-registration shims) use this.
17 * The `run` function still lives JS-side; metadata is advisory today.
18 *
19 * Both APIs feed `openstation_build_desktop_command_scripts_payload()` and
20 * `openstation_build_desktop_commands_payload()`, which contribute
21 * `serverCommandScripts` and `serverCommands` to the shell payload in
22 * `openstation_build_menu_payload()`.
23 *
24 * @package OpenStation
25 */
26
27 defined( 'ABSPATH' ) || exit;
28
29 /**
30 * Declare a WP-registered script handle as a command-palette provider.
31 *
32 * Example:
33 *
34 * ```php
35 * add_action( 'admin_enqueue_scripts', function () {
36 * wp_register_script(
37 * 'home-assistant-commands',
38 * plugins_url( 'js/commands.js', __FILE__ ),
39 * array( 'openstation' ),
40 * '1.0.0',
41 * true
42 * );
43 * wp_enqueue_script( 'home-assistant-commands' );
44 * }, 5 ); // Before the shell harvests the payload at priority 10.
45 * openstation_register_command_script( 'home-assistant-commands' );
46 * ```
47 *
48 * The script's JS side calls `wp.os.registerCommand( { … } )` as
49 * usual. When a user installs or activates the plugin, the chromeless
50 * bridge's `os-plugins-changed` payload includes the resolved
51 * script URL; the shell's command-sync module injects the script into
52 * the shell page and the new commands appear in the palette without a
53 * full reload.
54 *
55 * @param string $handle WP-registered script handle.
56 * @return true|WP_Error `true` on success; `WP_Error` on validation failure.
57 */
58 function openstation_register_command_script( $handle ) {
59 $handle = (string) $handle;
60 if ( '' === $handle ) {
61 return openstation_registration_error(
62 'openstation_missing_handle',
63 __( 'Command script registration requires a non-empty script handle.', 'desktop-mode' )
64 );
65 }
66
67 openstation_desktop_command_script_registry( $handle, true );
68
69 /**
70 * Fires after a desktop command script handle is registered.
71 *
72 * @param string $handle The registered script handle.
73 */
74 do_action( 'openstation_command_script_registered', $handle );
75
76 return true;
77 }
78
79 /**
80 * Declare a desktop command server-side. Optional companion to
81 * `openstation_register_command_script()` for plugins that want metadata
82 * enumerable without JS execution (REST, future pre-registration, etc.).
83 * The command's `run` function still lives JS-side; this function only
84 * stores metadata.
85 *
86 * Example:
87 *
88 * ```php
89 * openstation_register_command( array(
90 * 'slug' => 'ha-lights',
91 * 'label' => __( 'Home Assistant: Lights', 'home-assistant' ),
92 * 'description' => __( 'Toggle smart lights from the palette.', 'home-assistant' ),
93 * 'icon' => 'dashicons-lightbulb',
94 * 'hint' => '[room]',
95 * 'script' => 'home-assistant-commands',
96 * ) );
97 * ```
98 *
99 * Implicitly registers the `script` handle via
100 * `openstation_register_command_script()` when provided, so plugins using
101 * this API don't need to call both functions.
102 *
103 * @param array $args {
104 * @type string $slug Slash-command slug (without leading `/`). Required.
105 * @type string $label Human-readable label. Required.
106 * @type string $description Subtitle shown in the palette. Default empty.
107 * @type string $icon Dashicons class. Default `dashicons-arrow-right-alt`.
108 * @type string $hint Argument hint rendered next to the slug. Default empty.
109 * @type string $script WP script handle providing the `run` function.
110 * Registered via `openstation_register_command_script()`
111 * when present. Default empty (advisory registration only).
112 * }
113 * @return true|WP_Error `true` on success; `WP_Error` on validation failure.
114 */
115 function openstation_register_command( $args = array() ) {
116 $defaults = array(
117 'slug' => '',
118 'label' => '',
119 'description' => '',
120 'icon' => 'dashicons-arrow-right-alt',
121 'hint' => '',
122 'script' => '',
123 );
124 $args = wp_parse_args( $args, $defaults );
125
126 $slug = (string) $args['slug'];
127 if ( '' === $slug ) {
128 return openstation_registration_error(
129 'openstation_missing_slug',
130 __( 'Command registration requires a non-empty `slug`.', 'desktop-mode' )
131 );
132 }
133 if ( '' === (string) $args['label'] ) {
134 return openstation_registration_error(
135 'openstation_missing_label',
136 __( 'Command registration requires a non-empty `label`.', 'desktop-mode' ),
137 array( 'slug' => $slug )
138 );
139 }
140
141 $entry = array(
142 'slug' => $slug,
143 'label' => (string) $args['label'],
144 'description' => (string) $args['description'],
145 'icon' => (string) $args['icon'],
146 'hint' => (string) $args['hint'],
147 'script' => (string) $args['script'],
148 );
149 openstation_desktop_command_registry( $slug, $entry );
150
151 if ( '' !== $entry['script'] ) {
152 openstation_register_command_script( $entry['script'] );
153 }
154
155 /**
156 * Fires after a desktop command is successfully registered.
157 *
158 * @param string $slug The command slug.
159 * @param array $entry The stored registry entry.
160 */
161 do_action( 'openstation_command_registered', $slug, $entry );
162
163 return true;
164 }
165
166 /**
167 * Internal module-level registry for command script handles declared
168 * via {@see openstation_register_command_script()}. Accessed by both the
169 * registration API (write) and the payload builder (read).
170 *
171 * @internal
172 *
173 * @param string $handle Script handle to read or write.
174 * @param bool|null $value Pass `true` to register; `null` to read only.
175 * @return array|bool When called with no args returns the full store.
176 */
177 function openstation_desktop_command_script_registry( $handle = '', $value = null ) {
178 static $store = array();
179
180 if ( '__flush__' === (string) $handle ) {
181 $store = array();
182 return array();
183 }
184 if ( '' === (string) $handle ) {
185 return $store;
186 }
187 if ( null !== $value ) {
188 $store[ (string) $handle ] = (bool) $value;
189 }
190 return isset( $store[ (string) $handle ] ) ? $store[ (string) $handle ] : false;
191 }
192
193 /**
194 * Flush the command-script registry. Tests call this in `set_up` so
195 * a previous test's stale handle doesn't leak into the next test's
196 * payload-build assertions. No production caller.
197 */
198 function openstation_flush_desktop_command_script_registry() {
199 openstation_desktop_command_script_registry( '__flush__' );
200 }
201
202 /**
203 * Internal module-level registry for commands declared via
204 * {@see openstation_register_command()}.
205 *
206 * @internal
207 *
208 * @param string $slug Slug to read or write.
209 * @param array|null $entry Entry to store, or `null` to read.
210 * @return array|null
211 */
212 function openstation_desktop_command_registry( $slug = '', $entry = null ) {
213 static $store = array();
214
215 if ( '' === (string) $slug ) {
216 return $store;
217 }
218 if ( null !== $entry ) {
219 $store[ (string) $slug ] = $entry;
220 }
221 return isset( $store[ (string) $slug ] ) ? $store[ (string) $slug ] : null;
222 }
223
224 /**
225 * Build the script-handle payload fed to the shell. Resolves each
226 * registered handle to a full payload via {@see openstation_resolve_script_payload()};
227 * handles that aren't currently enqueued (plugin not active this request)
228 * resolve to an empty URL and are dropped. The harvested `extra` data
229 * (localize / inline / translations) ships alongside the URL so the
230 * shell's lazy `<script>` injection doesn't drop it the way a bare
231 * `<script src="…">` append would.
232 *
233 * @return array[] List of `{ handle, scriptUrl, scriptBefore, scriptAfter, scriptL10n, scriptTranslations }` entries.
234 */
235 function openstation_build_desktop_command_scripts_payload() {
236 $registry = openstation_desktop_command_script_registry();
237 if ( ! is_array( $registry ) || empty( $registry ) ) {
238 return array();
239 }
240
241 $out = array();
242 $seen = array();
243 foreach ( $registry as $handle => $active ) {
244 if ( ! $active || isset( $seen[ $handle ] ) ) {
245 continue;
246 }
247 $payload = openstation_resolve_script_payload( $handle );
248 if ( '' === $payload['url'] ) {
249 openstation_warn_unresolvable_script_handle(
250 'openstation_register_command_script',
251 'Command',
252 (string) $handle
253 );
254 continue;
255 }
256 $out[] = array(
257 'handle' => (string) $handle,
258 'scriptUrl' => $payload['url'],
259 'scriptBefore' => $payload['before'],
260 'scriptAfter' => $payload['after'],
261 'scriptL10n' => $payload['l10n'],
262 'scriptTranslations' => $payload['translations'],
263 );
264 $seen[ $handle ] = true;
265 }
266 return $out;
267 }
268
269 /**
270 * Build the metadata payload for commands declared via
271 * {@see openstation_register_command()}. Each entry carries the resolved
272 * `scriptUrl` alongside metadata so the shell's sync knows which script
273 * contributed it — enables future pre-registration shims without a round
274 * trip.
275 *
276 * @return array[]
277 */
278 function openstation_build_desktop_commands_payload() {
279 $registry = openstation_desktop_command_registry();
280 if ( ! is_array( $registry ) || empty( $registry ) ) {
281 return array();
282 }
283
284 $out = array();
285 foreach ( $registry as $entry ) {
286 $handle = (string) $entry['script'];
287 $payload = '' !== $handle
288 ? openstation_resolve_script_payload( $handle )
289 : array(
290 'url' => '',
291 'before' => array(),
292 'after' => array(),
293 'l10n' => array(),
294 'translations' => '',
295 );
296 $out[] = array(
297 'slug' => (string) $entry['slug'],
298 'label' => (string) $entry['label'],
299 'description' => (string) $entry['description'],
300 'icon' => (string) $entry['icon'],
301 'hint' => (string) $entry['hint'],
302 'scriptUrl' => $payload['url'],
303 'scriptHandle' => $handle,
304 'scriptBefore' => $payload['before'],
305 'scriptAfter' => $payload['after'],
306 'scriptL10n' => $payload['l10n'],
307 'scriptTranslations' => $payload['translations'],
308 );
309 }
310 return $out;
311 }
312