PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.8
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.8, at includes/registries/widgets.php

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