PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.7
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.7
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
desktop-mode / includes / registries / widgets.php

widgets.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.7, at includes/registries/widgets.php

260 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Widgets registry.
4 *
5 * Server-side registration API + payload builder + asset enqueue
6 * for the right-column widget layer. Plugin-side JS publishes
7 * the full widget def on `window.desktopModeWidgets[ id ]`; this
8 * module is the PHP side that announces them and ships their
9 * script handles into the boot payload.
10 *
11 * Extracted from `components.php` during the architecture-0.8.1
12 * PHP slicing (phase 6).
13 *
14 * @package Desktop_Mode
15 * @since 0.8.1
16 */
17
18 defined( 'ABSPATH' ) || exit;
19
20 /**
21 * Register a server-side desktop widget. Symmetric to
22 * {@see desktop_mode_register_window()} for the right-column widget
23 * layer: plugin declares the widget's metadata + script handle in
24 * PHP; shell syncs its registry from the live payload so
25 * activation / deactivation map to picker add / remove without a
26 * browser reload.
27 *
28 * The mount callback still lives in JS — not serializable across
29 * the wire. Plugins register it on
30 * `window.desktopModeWidgets[ <id> ]` as a `(container, ctx) =>
31 * teardown` function. The shell reads that global once the
32 * declared script loads and wraps it into a WidgetDef.
33 *
34 * Example:
35 *
36 * ```php
37 * desktop_mode_register_widget( 'myplugin/stats', array(
38 * 'label' => __( 'Stats', 'my-plugin' ),
39 * 'description' => __( 'Live analytics rollup', 'my-plugin' ),
40 * 'icon' => 'dashicons-chart-bar',
41 * 'script' => 'my-plugin-desktop-widgets',
42 * 'movable' => true,
43 * 'resizable' => true,
44 * 'default_width' => 280,
45 * 'default_height' => 180,
46 * ) );
47 * ```
48 *
49 * ```js
50 * // Inside my-plugin-desktop-widgets.js:
51 * window.desktopModeWidgets = window.desktopModeWidgets || {};
52 * window.desktopModeWidgets[ 'myplugin/stats' ] = function ( container, ctx ) {
53 * container.append( buildDOM() );
54 * return function teardown() { };
55 * };
56 * ```
57 *
58 * @since 0.8.1
59 * @since 0.8.1 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 * @param string $id Widget id. Must match the key the JS side
64 * uses on `window.desktopModeWidgets[ … ]`.
65 * @param array $args {
66 * @type string $label Human-readable picker label. Required.
67 * @type string $description Picker subtitle. Default empty.
68 * @type string $icon Dashicons class for the picker.
69 * Default 'dashicons-admin-generic'.
70 * @type string $script Enqueued script handle that owns
71 * the mount callback. Optional — omit
72 * when the mount callback is declared
73 * by a script already on the shell
74 * page. Default empty.
75 * @type bool $movable Allow drag out of the right column.
76 * @type bool $resizable Allow user resize.
77 * @type int $min_width
78 * @type int $min_height
79 * @type int $max_width
80 * @type int $max_height
81 * @type int $default_width First-mount floating width.
82 * @type int $default_height First-mount floating height.
83 * @type string[] $capabilities Gate: ALL caps must match. Any
84 * missed cap returns
85 * `WP_Error desktop_mode_capability_denied`.
86 * }
87 * @return true|WP_Error `true` on success; `WP_Error` otherwise.
88 */
89 function desktop_mode_register_widget( $id, $args = array() ) {
90 $id = (string) $id;
91 if ( '' === $id ) {
92 return desktop_mode_registration_error(
93 'desktop_mode_missing_id',
94 __( 'Widget id is required.', 'desktop-mode' )
95 );
96 }
97
98 $defaults = array(
99 'label' => '',
100 'description' => '',
101 'icon' => 'dashicons-admin-generic',
102 'script' => '',
103 'movable' => false,
104 'resizable' => false,
105 'min_width' => 0,
106 'min_height' => 0,
107 'max_width' => 0,
108 'max_height' => 0,
109 'default_width' => 0,
110 'default_height' => 0,
111 'capabilities' => array(),
112 );
113 $args = wp_parse_args( $args, $defaults );
114
115 foreach ( (array) $args['capabilities'] as $cap ) {
116 if ( ! current_user_can( (string) $cap ) ) {
117 return desktop_mode_registration_error(
118 'desktop_mode_capability_denied',
119 sprintf(
120 /* translators: %s: capability slug. */
121 __( 'Current user lacks the %s capability required to register this widget.', 'desktop-mode' ),
122 (string) $cap
123 ),
124 array( 'capability' => (string) $cap, 'id' => $id )
125 );
126 }
127 }
128
129 // Required fields. The script handle isn't strictly required —
130 // a plugin could register a widget whose mount callback is
131 // declared on the shell page's own JS (edge case; still valid).
132 if ( '' === (string) $args['label'] ) {
133 return desktop_mode_registration_error(
134 'desktop_mode_missing_label',
135 __( 'Widget registration requires a non-empty `label`.', 'desktop-mode' ),
136 array( 'id' => $id )
137 );
138 }
139
140 $entry = array(
141 'id' => $id,
142 'label' => (string) $args['label'],
143 'description' => (string) $args['description'],
144 'icon' => (string) $args['icon'],
145 'script' => (string) $args['script'],
146 'movable' => (bool) $args['movable'],
147 'resizable' => (bool) $args['resizable'],
148 'min_width' => (int) $args['min_width'],
149 'min_height' => (int) $args['min_height'],
150 'max_width' => (int) $args['max_width'],
151 'max_height' => (int) $args['max_height'],
152 'default_width' => (int) $args['default_width'],
153 'default_height' => (int) $args['default_height'],
154 );
155 desktop_mode_desktop_widget_registry( $id, $entry );
156
157 /**
158 * Fires after a desktop widget is successfully registered.
159 *
160 * Does NOT fire when `desktop_mode_register_widget()` returns a
161 * `WP_Error`.
162 *
163 * @since 0.8.1
164 *
165 * @param string $id The widget id.
166 * @param array $entry The stored registry entry.
167 */
168 do_action( 'desktop_mode_widget_registered', $id, $entry );
169
170 return true;
171 }
172
173 /**
174 * Internal module-level registry for widgets registered via
175 * {@see desktop_mode_register_widget()}. Same pattern as
176 * {@see desktop_mode_native_window_registry()}.
177 *
178 * @since 0.8.1
179 * @internal
180 */
181 function desktop_mode_desktop_widget_registry( $id = '', $entry = null ) {
182 static $store = array();
183
184 if ( '' === (string) $id ) {
185 return $store;
186 }
187 if ( null !== $entry ) {
188 $store[ $id ] = $entry;
189 }
190 return isset( $store[ $id ] ) ? $store[ $id ] : null;
191 }
192
193 /**
194 * Build the widget list for the shell payload. Runs through
195 * every entry registered via `desktop_mode_register_widget()` and
196 * attaches the resolved script URL (`wp_scripts()` lookup) so
197 * the shell can dynamically inject the script on mid-session
198 * plugin activation.
199 *
200 * @since 0.8.1
201 *
202 * @return array[]
203 */
204 function desktop_mode_build_desktop_widgets_payload() {
205 $registry = desktop_mode_desktop_widget_registry();
206 if ( ! is_array( $registry ) || empty( $registry ) ) {
207 return array();
208 }
209
210 $out = array();
211 foreach ( $registry as $entry ) {
212 $script_payload = desktop_mode_resolve_script_payload( $entry['script'] );
213
214 $out[] = array(
215 'id' => $entry['id'],
216 'label' => $entry['label'],
217 'description' => $entry['description'],
218 'icon' => $entry['icon'],
219 'movable' => $entry['movable'],
220 'resizable' => $entry['resizable'],
221 'minWidth' => $entry['min_width'],
222 'minHeight' => $entry['min_height'],
223 'maxWidth' => $entry['max_width'],
224 'maxHeight' => $entry['max_height'],
225 'defaultWidth' => $entry['default_width'],
226 'defaultHeight' => $entry['default_height'],
227 'scriptUrl' => $script_payload['url'],
228 'scriptHandle' => $entry['script'],
229 'scriptBefore' => $script_payload['before'],
230 'scriptAfter' => $script_payload['after'],
231 'scriptL10n' => $script_payload['l10n'],
232 'scriptTranslations' => $script_payload['translations'],
233 );
234 }
235 return $out;
236 }
237
238 /**
239 * Enqueue plugin-registered widget scripts on the shell page so
240 * widgets active at boot time have their mount callbacks
241 * available without any dynamic-load roundtrip.
242 *
243 * @since 0.8.1
244 */
245 function desktop_mode_enqueue_desktop_widget_scripts() {
246 if ( ! desktop_mode_is_enabled() || desktop_mode_is_chromeless_request() || desktop_mode_is_classic_request() ) {
247 return;
248 }
249 $registry = desktop_mode_desktop_widget_registry();
250 if ( ! is_array( $registry ) ) {
251 return;
252 }
253 foreach ( $registry as $entry ) {
254 if ( ! empty( $entry['script'] ) ) {
255 wp_enqueue_script( $entry['script'] );
256 }
257 }
258 }
259 add_action( 'admin_enqueue_scripts', 'desktop_mode_enqueue_desktop_widget_scripts', 20 );
260