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 / desktop-files / registry.php

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

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