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 / wallpapers.php

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

278 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Wallpapers registry.
4 *
5 * Server-side registration API + payload builder + asset enqueue
6 * for the desktop wallpaper picker. Wallpaper definitions live
7 * on `window.desktopModeWallpapers[ id ]` (set by the plugin's
8 * own JS); this module is the PHP side that announces them to
9 * the shell and ships their script handles into the boot
10 * payload.
11 *
12 * Extracted from `components.php` during the architecture-0.8.1
13 * PHP slicing (phase 6). Behaviour, function names, filter
14 * contracts, and error codes all unchanged.
15 *
16 * @package Desktop_Mode
17 */
18
19 defined( 'ABSPATH' ) || exit;
20
21 /**
22 * Register a server-side desktop wallpaper. Symmetrical to
23 * {@see desktop_mode_register_widget()}. The plugin's JS side
24 * publishes the full `WallpaperDef` (with mount / resolveValue /
25 * renderEditor callbacks as appropriate) on
26 * `window.desktopModeWallpapers[ <id> ]`; the shell loads the
27 * declared script, reads that global, and registers the def via
28 * the normal wallpaper registry. Deactivation unregisters the
29 * def and re-applies the current selection (which falls back to
30 * a built-in if the user's active wallpaper was the one leaving).
31 *
32 * Example:
33 *
34 * ```php
35 * desktop_mode_register_wallpaper( 'myplugin/snow', array(
36 * 'label' => __( 'Snow', 'my-plugin' ),
37 * 'preview' => 'linear-gradient(#fff, #ddd)',
38 * 'type' => 'canvas',
39 * 'script' => 'my-plugin-snow-wallpaper',
40 * ) );
41 * ```
42 *
43 * ```js
44 * // Inside my-plugin-snow-wallpaper.js
45 * window.desktopModeWallpapers = window.desktopModeWallpapers || {};
46 * window.desktopModeWallpapers[ 'myplugin/snow' ] = {
47 * id: 'myplugin/snow',
48 * label: 'Snow',
49 * type: 'canvas',
50 * preview: 'linear-gradient(#fff, #ddd)',
51 * needs: [ 'pixijs' ],
52 * mount: function ( container, ctx ) { return function () {}; },
53 * };
54 * ```
55 *
56 * @param string $id Wallpaper id. For canvas wallpapers this must
57 * match the `window.desktopModeWallpapers[<id>]`
58 * key the plugin's JS publishes.
59 * @param array $args {
60 * @type string $label Picker label. Required.
61 * @type string $preview CSS value rendered in the picker
62 * swatch (gradient, color,
63 * `url(...)`, etc.). Required.
64 * @type string $type 'css' | 'canvas'. Default 'canvas'.
65 * @type string $value CSS value applied to the wallpaper
66 * surface (only relevant for `css`
67 * type — canvas wallpapers paint in
68 * JS). Defaults to `preview` so a
69 * single string covers the common
70 * case where swatch and surface are
71 * identical.
72 * @type string $script Enqueued script handle that
73 * publishes the def on the global.
74 * Required for `canvas` type;
75 * optional for `css`.
76 * @type string $description Plain-text description shown in OS
77 * Settings when the wallpaper is the
78 * active selection — what it is, where
79 * its data comes from, the story behind
80 * it. Optional.
81 * @type string[] $capabilities Gate: ALL caps must match. Any
82 * missed cap returns
83 * `WP_Error desktop_mode_capability_denied`.
84 * }
85 * @return true|WP_Error `true` on success; `WP_Error` otherwise.
86 */
87 function desktop_mode_register_wallpaper( $id, $args = array() ) {
88 $id = (string) $id;
89 if ( '' === $id ) {
90 return desktop_mode_registration_error(
91 'desktop_mode_missing_id',
92 __( 'Wallpaper id is required.', 'desktop-mode' )
93 );
94 }
95
96 $defaults = array(
97 'label' => '',
98 'preview' => '',
99 'type' => 'canvas',
100 'value' => '',
101 'script' => '',
102 'description' => '',
103 'capabilities' => array(),
104 );
105 $args = wp_parse_args( $args, $defaults );
106
107 foreach ( (array) $args['capabilities'] as $cap ) {
108 if ( ! current_user_can( (string) $cap ) ) {
109 return desktop_mode_registration_error(
110 'desktop_mode_capability_denied',
111 sprintf(
112 /* translators: %s: capability slug. */
113 __( 'Current user lacks the %s capability required to register this wallpaper.', 'desktop-mode' ),
114 (string) $cap
115 ),
116 array( 'capability' => (string) $cap, 'id' => $id )
117 );
118 }
119 }
120 if ( '' === (string) $args['label'] ) {
121 return desktop_mode_registration_error(
122 'desktop_mode_missing_label',
123 __( 'Wallpaper registration requires a non-empty `label`.', 'desktop-mode' ),
124 array( 'id' => $id )
125 );
126 }
127 $type = in_array( $args['type'], array( 'css', 'canvas' ), true )
128 ? $args['type']
129 : 'canvas';
130 // Canvas wallpapers always need a script (the def with its
131 // `mount` callback is published on the JS global by that
132 // script). CSS wallpapers can skip the script — the shell can
133 // render from the `value` / `preview` string alone.
134 if ( 'canvas' === $type && '' === (string) $args['script'] ) {
135 return desktop_mode_registration_error(
136 'desktop_mode_missing_script',
137 __( 'Canvas wallpaper registration requires a `script` handle that publishes the def.', 'desktop-mode' ),
138 array( 'id' => $id )
139 );
140 }
141
142 // `value` defaults to `preview` when omitted — the common case
143 // for a plain gradient/solid where the swatch and the surface
144 // render the same CSS. Authors can split them (e.g. static
145 // swatch preview + animated value) by passing both.
146 $value = (string) $args['value'];
147 if ( '' === $value ) {
148 $value = (string) $args['preview'];
149 }
150
151 $entry = array(
152 'id' => $id,
153 // Plain text by contract, same as `description` below. The
154 // shell paints labels through the `html` tagged template, whose
155 // text slots build DOM with `createTextNode()` — never
156 // `innerHTML` — so a label cannot become markup downstream.
157 //
158 // Note this STRIPS rather than ESCAPES, and that distinction is
159 // load-bearing: `esc_html()` here would encode `&` in a
160 // perfectly ordinary label ("Black & White") and the text node
161 // would then render the entity literally as `&amp;`. Escaping
162 // belongs at an HTML boundary; there isn't one on this path.
163 'label' => sanitize_text_field( (string) $args['label'] ),
164 'preview' => (string) $args['preview'],
165 'type' => $type,
166 'value' => $value,
167 'script' => (string) $args['script'],
168 // Plain text by contract — the shell renders it as text, never
169 // as HTML, so strip tags here rather than trusting every caller.
170 'description' => sanitize_textarea_field( (string) $args['description'] ),
171 );
172 desktop_mode_desktop_wallpaper_registry( $id, $entry );
173
174 /**
175 * Fires after a desktop wallpaper is successfully registered.
176 *
177 * Does NOT fire when `desktop_mode_register_wallpaper()` returns a
178 * `WP_Error`.
179 *
180 * @param string $id The wallpaper id.
181 * @param array $entry The stored registry entry.
182 */
183 do_action( 'desktop_mode_wallpaper_registered', $id, $entry );
184
185 return true;
186 }
187
188 /**
189 * Internal module-level registry for wallpapers registered via
190 * {@see desktop_mode_register_wallpaper()}. Same static-store
191 * pattern as the widget + native-window registries.
192 *
193 * @internal
194 */
195 function desktop_mode_desktop_wallpaper_registry( $id = '', $entry = null ) {
196 static $store = array();
197
198 if ( '' === (string) $id ) {
199 return $store;
200 }
201 if ( null !== $entry ) {
202 $store[ $id ] = $entry;
203 }
204 return isset( $store[ $id ] ) ? $store[ $id ] : null;
205 }
206
207 /**
208 * Build the wallpaper list for the shell payload. Only metadata +
209 * the resolved script URL cross the wire; the plugin's mount
210 * callback is announced via the JS global the script sets up.
211 *
212 * @return array[]
213 */
214 function desktop_mode_build_desktop_wallpapers_payload() {
215 $registry = desktop_mode_desktop_wallpaper_registry();
216 if ( ! is_array( $registry ) || empty( $registry ) ) {
217 return array();
218 }
219 /**
220 * Filters the server-declared wallpaper list before it ships to
221 * the shell. Mirrors the JS-side `desktop-mode.wallpapers` filter
222 * so plugins can rearrange, hide, or override entries at boot
223 * without round-tripping through the JS registry.
224 *
225 * @param array[] $registry The registered wallpaper entries.
226 */
227 $registry = apply_filters( 'desktop_mode_wallpapers', $registry );
228 if ( ! is_array( $registry ) ) {
229 return array();
230 }
231 $out = array();
232 foreach ( $registry as $entry ) {
233 if ( ! is_array( $entry ) || empty( $entry['id'] ) ) {
234 continue;
235 }
236 $handle = isset( $entry['script'] ) ? (string) $entry['script'] : '';
237 $payload = desktop_mode_resolve_script_payload( $handle );
238 $out[] = array(
239 'id' => (string) $entry['id'],
240 'label' => isset( $entry['label'] ) ? (string) $entry['label'] : '',
241 'preview' => isset( $entry['preview'] ) ? (string) $entry['preview'] : '',
242 'type' => isset( $entry['type'] ) ? (string) $entry['type'] : 'canvas',
243 'value' => isset( $entry['value'] ) ? (string) $entry['value'] : '',
244 'description' => isset( $entry['description'] ) ? (string) $entry['description'] : '',
245 'scriptUrl' => $payload['url'],
246 'scriptHandle' => $handle,
247 'scriptBefore' => $payload['before'],
248 'scriptAfter' => $payload['after'],
249 'scriptL10n' => $payload['l10n'],
250 'scriptTranslations' => $payload['translations'],
251 );
252 }
253 return $out;
254 }
255
256
257 /**
258 * Enqueue plugin-registered wallpaper scripts on the shell page
259 * so wallpapers active at boot time have their defs available
260 * without any dynamic-load roundtrip.
261 */
262 function desktop_mode_enqueue_desktop_wallpaper_scripts() {
263 if ( ! desktop_mode_is_enabled() || desktop_mode_is_chromeless_request() || desktop_mode_is_classic_request() ) {
264 return;
265 }
266 $registry = desktop_mode_desktop_wallpaper_registry();
267 if ( ! is_array( $registry ) ) {
268 return;
269 }
270 foreach ( $registry as $entry ) {
271 if ( ! empty( $entry['script'] ) ) {
272 wp_enqueue_script( $entry['script'] );
273 }
274 }
275 }
276 add_action( 'admin_enqueue_scripts', 'desktop_mode_enqueue_desktop_wallpaper_scripts', 20 );
277
278