PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.6
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.6
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 / recycle-bin / rest.php

rest.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.6, at includes/recycle-bin/rest.php

308 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Recycle Bin: REST routes.
4 *
5 * Five routes, all under `/desktop-mode/v1/recycle-bin`:
6 *
7 * GET / — list trashed items
8 * POST /restore — body { ids: int[] }
9 * POST /purge — body { ids: int[] }
10 * POST /empty — empties the visible bin
11 * GET /count — total items in the bin (badge polling)
12 *
13 * Permission gating delegates to `desktop_mode_recycle_bin_user_can_*` per item;
14 * the route-level callback only checks "are you logged in and in
15 * desktop mode at all?" via `desktop_mode_is_enabled()`.
16 *
17 * @package WPDesktopMode
18 * @since 0.6.0
19 */
20
21 defined( 'ABSPATH' ) || exit;
22
23 /**
24 * Register REST routes.
25 *
26 * @since 0.6.0
27 */
28 function desktop_mode_recycle_bin_register_rest_routes() {
29 $namespace = 'desktop-mode/v1';
30
31 register_rest_route(
32 $namespace,
33 '/recycle-bin',
34 array(
35 'methods' => WP_REST_Server::READABLE,
36 'permission_callback' => 'desktop_mode_recycle_bin_rest_permission',
37 'callback' => 'desktop_mode_recycle_bin_rest_list',
38 'args' => array(
39 'page' => array(
40 'type' => 'integer',
41 'default' => 1,
42 'sanitize_callback' => 'absint',
43 ),
44 'per_page' => array(
45 'type' => 'integer',
46 'default' => 100,
47 'sanitize_callback' => 'absint',
48 ),
49 'type' => array(
50 'type' => 'string',
51 'default' => '',
52 'sanitize_callback' => 'sanitize_key',
53 ),
54 'search' => array(
55 'type' => 'string',
56 'default' => '',
57 'sanitize_callback' => 'sanitize_text_field',
58 ),
59 ),
60 )
61 );
62
63 register_rest_route(
64 $namespace,
65 '/recycle-bin/restore',
66 array(
67 'methods' => WP_REST_Server::CREATABLE,
68 'permission_callback' => 'desktop_mode_recycle_bin_rest_permission',
69 'callback' => 'desktop_mode_recycle_bin_rest_restore',
70 // Accepts either `items: [{id, type}]` (preferred) or
71 // `ids: int[]` (legacy — assumes post-ish entities).
72 // Both registered as optional; the handler validates.
73 'args' => array(
74 'items' => array(
75 'type' => 'array',
76 'required' => false,
77 ),
78 'ids' => array(
79 'type' => 'array',
80 'required' => false,
81 'items' => array( 'type' => 'integer' ),
82 ),
83 ),
84 )
85 );
86
87 register_rest_route(
88 $namespace,
89 '/recycle-bin/purge',
90 array(
91 'methods' => WP_REST_Server::CREATABLE,
92 'permission_callback' => 'desktop_mode_recycle_bin_rest_permission',
93 'callback' => 'desktop_mode_recycle_bin_rest_purge',
94 'args' => array(
95 'items' => array(
96 'type' => 'array',
97 'required' => false,
98 ),
99 'ids' => array(
100 'type' => 'array',
101 'required' => false,
102 'items' => array( 'type' => 'integer' ),
103 ),
104 ),
105 )
106 );
107
108 register_rest_route(
109 $namespace,
110 '/recycle-bin/empty',
111 array(
112 'methods' => WP_REST_Server::CREATABLE,
113 'permission_callback' => 'desktop_mode_recycle_bin_rest_permission',
114 'callback' => 'desktop_mode_recycle_bin_rest_empty',
115 )
116 );
117
118 register_rest_route(
119 $namespace,
120 '/recycle-bin/count',
121 array(
122 'methods' => WP_REST_Server::READABLE,
123 'permission_callback' => 'desktop_mode_recycle_bin_rest_permission',
124 'callback' => static function () {
125 return rest_ensure_response(
126 array( 'count' => desktop_mode_recycle_bin_count() )
127 );
128 },
129 )
130 );
131 }
132 add_action( 'rest_api_init', 'desktop_mode_recycle_bin_register_rest_routes' );
133
134 /**
135 * Route-level permission gate.
136 *
137 * Per-item capability checks happen inside the store layer; here we
138 * only enforce "logged-in user with desktop mode opted in" — same
139 * baseline as every other desktop REST surface.
140 *
141 * @since 0.6.0
142 *
143 * @return bool|WP_Error
144 */
145 function desktop_mode_recycle_bin_rest_permission() {
146 if ( ! is_user_logged_in() ) {
147 return new WP_Error(
148 'rest_forbidden',
149 __( 'Sorry, you must be logged in.', 'desktop-mode' ),
150 array( 'status' => 401 )
151 );
152 }
153 if ( function_exists( 'desktop_mode_is_enabled' ) && ! desktop_mode_is_enabled() ) {
154 return new WP_Error(
155 'rest_forbidden',
156 __( 'Desktop mode is not enabled for this user.', 'desktop-mode' ),
157 array( 'status' => 403 )
158 );
159 }
160 return true;
161 }
162
163 /**
164 * GET /recycle-bin
165 *
166 * @since 0.6.0
167 *
168 * @param WP_REST_Request $request REST request.
169 * @return WP_REST_Response
170 */
171 function desktop_mode_recycle_bin_rest_list( $request ) {
172 $payload = desktop_mode_recycle_bin_get_items(
173 array(
174 'page' => (int) $request->get_param( 'page' ),
175 'per_page' => (int) $request->get_param( 'per_page' ),
176 'type' => (string) $request->get_param( 'type' ),
177 'search' => (string) $request->get_param( 'search' ),
178 )
179 );
180
181 return rest_ensure_response( $payload );
182 }
183
184 /**
185 * POST /recycle-bin/restore
186 *
187 * @since 0.6.0
188 *
189 * @param WP_REST_Request $request REST request.
190 * @return WP_REST_Response
191 */
192 function desktop_mode_recycle_bin_rest_restore( $request ) {
193 $items = desktop_mode_recycle_bin_normalize_items( $request );
194 return rest_ensure_response( desktop_mode_recycle_bin_apply_bulk( $items, 'desktop_mode_recycle_bin_restore' ) );
195 }
196
197 /**
198 * POST /recycle-bin/purge
199 *
200 * @since 0.6.0
201 *
202 * @param WP_REST_Request $request REST request.
203 * @return WP_REST_Response
204 */
205 function desktop_mode_recycle_bin_rest_purge( $request ) {
206 $items = desktop_mode_recycle_bin_normalize_items( $request );
207 return rest_ensure_response( desktop_mode_recycle_bin_apply_bulk( $items, 'desktop_mode_recycle_bin_purge' ) );
208 }
209
210 /**
211 * Read either `items: [{id, type}]` (preferred) or `ids: int[]`
212 * (legacy) and normalise into a list of `[id, type]` pairs the
213 * bulk runner can hand straight to a typed callback.
214 *
215 * @since 0.6.0
216 *
217 * @param WP_REST_Request $request REST request.
218 * @return array<int, array{id:int, type:string}>
219 */
220 function desktop_mode_recycle_bin_normalize_items( $request ) {
221 $out = array();
222
223 $items = $request->get_param( 'items' );
224 if ( is_array( $items ) ) {
225 foreach ( $items as $entry ) {
226 if ( ! is_array( $entry ) ) {
227 continue;
228 }
229 $id = isset( $entry['id'] ) ? (int) $entry['id'] : 0;
230 $type = isset( $entry['type'] ) ? sanitize_key( (string) $entry['type'] ) : '';
231 if ( $id <= 0 ) {
232 continue;
233 }
234 $out[] = array(
235 'id' => $id,
236 'type' => $type,
237 );
238 }
239 return $out;
240 }
241
242 $ids = $request->get_param( 'ids' );
243 if ( is_array( $ids ) ) {
244 foreach ( $ids as $id ) {
245 $id = (int) $id;
246 if ( $id > 0 ) {
247 $out[] = array(
248 'id' => $id,
249 'type' => '',
250 );
251 }
252 }
253 }
254 return $out;
255 }
256
257 /**
258 * POST /recycle-bin/empty
259 *
260 * @since 0.6.0
261 *
262 * @return WP_REST_Response
263 */
264 function desktop_mode_recycle_bin_rest_empty() {
265 return rest_ensure_response( desktop_mode_recycle_bin_empty() );
266 }
267
268 /**
269 * Run a per-item callback over a list, capturing per-item results.
270 *
271 * @since 0.6.0
272 * @since 0.6.0 `$items` now carries `{id, type}` pairs; the
273 * callback receives both arguments. Legacy id-only
274 * callers go through `desktop_mode_recycle_bin_normalize_items`,
275 * which fills `type` with `''` (post default).
276 *
277 * @param array<int, array{id:int, type:string}> $items Items to operate on.
278 * @param callable $callback `($id, $type) → true|WP_Error`.
279 * @return array{ok:int[], errors:array<int, array{id:int, code:string, message:string}>}
280 */
281 function desktop_mode_recycle_bin_apply_bulk( $items, $callback ) {
282 $ok = array();
283 $errors = array();
284
285 foreach ( $items as $item ) {
286 $id = isset( $item['id'] ) ? (int) $item['id'] : 0;
287 $type = isset( $item['type'] ) ? (string) $item['type'] : '';
288 if ( $id <= 0 ) {
289 continue;
290 }
291 $result = call_user_func( $callback, $id, $type );
292 if ( is_wp_error( $result ) ) {
293 $errors[] = array(
294 'id' => $id,
295 'code' => $result->get_error_code(),
296 'message' => $result->get_error_message(),
297 );
298 } else {
299 $ok[] = $id;
300 }
301 }
302
303 return array(
304 'ok' => $ok,
305 'errors' => $errors,
306 );
307 }
308