PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.0
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.0
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 / desktop-files / registry.php

registry.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.0, at includes/desktop-files/registry.php

260 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — file-type registry.
4 *
5 * Maps a file-type slug (`'post'`, `'user'`, `'folder'`, …) to the
6 * `Desktop_Mode_File` subclass that adapts the underlying entity.
7 * Plugins extend the file system by registering their own subclass
8 * via {@see desktop_mode_register_file_type()}; the desktop UI then
9 * knows how to render and resolve their entities just like the
10 * built-in types.
11 *
12 * @package WPDesktopMode
13 * @since 0.9.0
14 */
15
16 defined( 'ABSPATH' ) || exit;
17
18 /**
19 * Internal static-store registry. Mirrors the wallpaper / native-
20 * window pattern (see `desktop_mode_desktop_wallpaper_registry()`).
21 *
22 * @since 0.9.0
23 * @internal
24 *
25 * @param string $type File-type slug ('' to fetch the full store).
26 * @param array|null $entry Entry to write, or null to read.
27 * @return array|null Full store when `$type` is empty; entry when
28 * looking one up; `null` when not found.
29 */
30 function desktop_mode_file_type_registry( $type = '', $entry = null ) {
31 static $store = array();
32
33 if ( '' === (string) $type ) {
34 return $store;
35 }
36 if ( null !== $entry ) {
37 $store[ (string) $type ] = $entry;
38 }
39 return isset( $store[ (string) $type ] ) ? $store[ (string) $type ] : null;
40 }
41
42 /**
43 * Registers a desktop file type.
44 *
45 * @since 0.9.0
46 *
47 * @param string $type File-type slug, e.g. `'post'`, `'user'`,
48 * `'jorvy-quote'`. Must be non-empty and unique.
49 * @param array $args {
50 * @type string $label Required. Human label for picker UIs.
51 * @type string $class Required. Fully-qualified
52 * `Desktop_Mode_File` subclass name.
53 * @type string $script Optional. Enqueued script handle for the
54 * plugin's JS-side definition. The shell
55 * dynamically loads the URL on activation
56 * so a plugin's file types appear without
57 * a shell reload.
58 * @type int $sort Sort order in picker UIs. Default 100.
59 * @type string[] $capabilities Gate: ALL caps must match.
60 * }
61 * @return true|WP_Error `true` on success, `WP_Error` otherwise.
62 */
63 function desktop_mode_register_file_type( $type, $args = array() ) {
64 $type = (string) $type;
65 if ( '' === $type ) {
66 return desktop_mode_registration_error(
67 'desktop_mode_missing_id',
68 __( 'File-type slug is required.', 'desktop-mode' )
69 );
70 }
71
72 $defaults = array(
73 'label' => '',
74 'class' => '',
75 'script' => '',
76 'sort' => 100,
77 'capabilities' => array(),
78 );
79 $args = wp_parse_args( $args, $defaults );
80
81 foreach ( (array) $args['capabilities'] as $cap ) {
82 if ( ! current_user_can( (string) $cap ) ) {
83 return desktop_mode_registration_error(
84 'desktop_mode_capability_denied',
85 sprintf(
86 /* translators: %s: capability slug. */
87 __( 'Current user lacks the %s capability required to register this file type.', 'desktop-mode' ),
88 (string) $cap
89 ),
90 array( 'capability' => (string) $cap, 'type' => $type )
91 );
92 }
93 }
94
95 if ( '' === (string) $args['label'] ) {
96 return desktop_mode_registration_error(
97 'desktop_mode_missing_label',
98 __( 'File-type registration requires a non-empty `label`.', 'desktop-mode' ),
99 array( 'type' => $type )
100 );
101 }
102
103 $class = (string) $args['class'];
104 if ( '' === $class || ! class_exists( $class ) ) {
105 return desktop_mode_registration_error(
106 'desktop_mode_invalid_class',
107 __( 'File-type registration requires an existing `class`.', 'desktop-mode' ),
108 array( 'type' => $type, 'class' => $class )
109 );
110 }
111 if ( ! is_subclass_of( $class, 'Desktop_Mode_File' ) ) {
112 return desktop_mode_registration_error(
113 'desktop_mode_invalid_class',
114 __( '`class` must extend `Desktop_Mode_File`.', 'desktop-mode' ),
115 array( 'type' => $type, 'class' => $class )
116 );
117 }
118
119 $entry = array(
120 'type' => $type,
121 'label' => (string) $args['label'],
122 'class' => $class,
123 'script' => (string) $args['script'],
124 'sort' => (int) $args['sort'],
125 );
126 desktop_mode_file_type_registry( $type, $entry );
127
128 /**
129 * Fires after a desktop file type is successfully registered.
130 * Does NOT fire on `WP_Error` returns.
131 *
132 * @since 0.9.0
133 *
134 * @param string $type Type slug.
135 * @param array $entry Stored registry entry.
136 */
137 do_action( 'desktop_mode_file_type_registered', $type, $entry );
138
139 return true;
140 }
141
142 /**
143 * Looks up a registered file-type entry.
144 *
145 * @since 0.9.0
146 *
147 * @param string $type Type slug.
148 * @return array|null Registry entry, or `null` if unknown.
149 */
150 function desktop_mode_get_file_type( $type ) {
151 $entry = desktop_mode_file_type_registry( (string) $type );
152 return is_array( $entry ) ? $entry : null;
153 }
154
155 /**
156 * Returns every registered file type, sorted by `sort` then label.
157 *
158 * @since 0.9.0
159 *
160 * @return array[]
161 */
162 function desktop_mode_get_file_types() {
163 $registry = desktop_mode_file_type_registry();
164 if ( ! is_array( $registry ) || empty( $registry ) ) {
165 return array();
166 }
167
168 /**
169 * Filters the full file-type registry before consumers see it.
170 * Plugins can hide built-in types or swap a class out at runtime.
171 *
172 * @since 0.9.0
173 *
174 * @param array[] $registry Registered entries keyed by slug.
175 */
176 $registry = apply_filters( 'desktop_mode_file_types', $registry );
177 if ( ! is_array( $registry ) ) {
178 return array();
179 }
180
181 $entries = array_values( $registry );
182 usort(
183 $entries,
184 static function ( $a, $b ) {
185 $sa = isset( $a['sort'] ) ? (int) $a['sort'] : 100;
186 $sb = isset( $b['sort'] ) ? (int) $b['sort'] : 100;
187 if ( $sa !== $sb ) {
188 return $sa - $sb;
189 }
190 $la = isset( $a['label'] ) ? (string) $a['label'] : '';
191 $lb = isset( $b['label'] ) ? (string) $b['label'] : '';
192 return strcmp( $la, $lb );
193 }
194 );
195 return $entries;
196 }
197
198 /**
199 * Resolves a `(type, ref)` tuple into a `Desktop_Mode_File` instance,
200 * or `null` if the type is unknown.
201 *
202 * @since 0.9.0
203 *
204 * @param string $type File-type slug.
205 * @param string|int $ref Entity reference.
206 * @return Desktop_Mode_File|null
207 */
208 function desktop_mode_resolve_file( $type, $ref ) {
209 $entry = desktop_mode_get_file_type( $type );
210 if ( null === $entry ) {
211 return null;
212 }
213 $class = $entry['class'];
214 if ( ! class_exists( $class ) ) {
215 return null;
216 }
217 return new $class( $ref );
218 }
219
220 /**
221 * Builds the file-types payload sent to the shell. Only metadata
222 * (id, label, sort) and the resolved script URL cross the wire —
223 * the PHP class never serializes; the JS side has its own mirror.
224 *
225 * @since 0.9.0
226 *
227 * @return array[]
228 */
229 function desktop_mode_build_file_types_payload() {
230 $entries = desktop_mode_get_file_types();
231 if ( empty( $entries ) ) {
232 return array();
233 }
234 $out = array();
235 foreach ( $entries as $entry ) {
236 $handle = isset( $entry['script'] ) ? (string) $entry['script'] : '';
237 $payload = '' !== $handle
238 ? desktop_mode_resolve_script_payload( $handle )
239 : array(
240 'url' => '',
241 'before' => array(),
242 'after' => array(),
243 'l10n' => array(),
244 'translations' => '',
245 );
246 $out[] = array(
247 'id' => (string) $entry['type'],
248 'label' => (string) $entry['label'],
249 'sort' => (int) $entry['sort'],
250 'scriptUrl' => $payload['url'],
251 'scriptHandle' => $handle,
252 'scriptBefore' => $payload['before'],
253 'scriptAfter' => $payload['after'],
254 'scriptL10n' => $payload['l10n'],
255 'scriptTranslations' => $payload['translations'],
256 );
257 }
258 return $out;
259 }
260