PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.12
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.12
1.1.12 1.1.11 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 All 36 releases
← All changes | includes/recycle-bin/store.php +231 -203 0.9.0 → 1.1.12 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Desktop Mode — Recycle Bin: store.
3 + * OpenStation — Recycle Bin: store.
4 4 *
5 5 * Read/restore/purge primitives that the REST layer wraps. Backed
6 6 * entirely by core post-table state — no custom tables, no options
7 7 * blob. "Trashed" items are exactly the rows with
@@ -6,14 +6,13 @@
6 6 * entirely by core post-table state — no custom tables, no options
7 7 * blob. "Trashed" items are exactly the rows with
8 8 * `post_status = 'trash'` for the post types the bin tracks.
9 9 *
10 - * Every read goes through `desktop_mode_recycle_bin_query_args` so
10 + * Every read goes through `openstation_recycle_bin_query_args` so
11 11 * plugins can scope the bin (e.g. show only the current user's
12 12 * trash, or filter by author/role for compliance use cases).
13 13 *
14 - * @package WPDesktopMode
15 - * @since 0.19.0
14 + * @package OpenStation
16 15 */
17 16
18 17 defined( 'ABSPATH' ) || exit;
19 18
@@ -20,10 +19,8 @@
20 19 /**
21 20 * Returns the list of trashed items the current user is allowed to
22 21 * see, shaped for the table component.
23 22 *
24 - * @since 0.19.0
25 - *
26 23 * @param array $args {
27 24 * Optional. Query overrides.
28 25 *
29 26 * @type int $per_page Default 100.
@@ -35,9 +32,9 @@
35 32 * @type array $items List of items shaped for the JS layer.
36 33 * @type int $total Total matching rows (across pages).
37 34 * }
38 35 */
39 -function desktop_mode_recycle_bin_get_items( $args = array() ) {
36 +function openstation_recycle_bin_get_items( $args = array() ) {
40 37 $args = wp_parse_args(
41 38 $args,
42 39 array(
43 40 'per_page' => 100,
@@ -59,9 +56,9 @@
59 56
60 57 // Source gates: each `$type` filter narrows down to the
61 58 // owning store. `''` (All) loads every source. The files-on-
62 59 // desktop sources (`shortcut` / `placement` / `folder`) live in
63 - // `desktop_mode_files_list_trashed_for_recycle_bin` — never run
60 + // `openstation_files_list_trashed_for_recycle_bin` — never run
64 61 // the WP-core post / comment queries when one of those is the
65 62 // active filter, otherwise trashed posts leak into the
66 63 // "Shortcuts" / "Folders" tabs.
67 64 $files_types = array( 'desktop', 'placement', 'shortcut', 'folder' );
@@ -68,12 +65,12 @@
68 65 $is_files_filter = in_array( $type, $files_types, true );
69 66 $wants_post_types = '' === $type
70 67 || ( 'comment' !== $type && ! $is_files_filter );
71 68 $wants_comments = ( '' === $type || 'comment' === $type )
72 - && desktop_mode_recycle_bin_comments_enabled();
69 + && openstation_recycle_bin_comments_enabled();
73 70
74 71 if ( $wants_post_types ) {
75 - $post_types = desktop_mode_recycle_bin_capture_post_types();
72 + $post_types = openstation_recycle_bin_capture_post_types();
76 73 if ( '' !== $type && in_array( $type, $post_types, true ) ) {
77 74 $post_types = array( $type );
78 75 }
79 76
@@ -90,21 +87,19 @@
90 87
91 88 /**
92 89 * Filter the WP_Query args used to populate the recycle bin.
93 90 *
94 - * @since 0.19.0
95 - *
96 91 * @param array $query_args Args passed to WP_Query.
97 92 * @param array $args Caller-provided args.
98 93 */
99 - $query_args = apply_filters( 'desktop_mode_recycle_bin_query_args', $query_args, $args );
94 + $query_args = apply_filters( 'openstation_recycle_bin_query_args', $query_args, $args );
100 95
101 96 $query = new WP_Query( $query_args );
102 97 foreach ( $query->posts as $post ) {
103 - if ( ! desktop_mode_recycle_bin_user_can_view( $post ) ) {
98 + if ( ! openstation_recycle_bin_user_can_view( $post ) ) {
104 99 continue;
105 100 }
106 - $items_posts[] = desktop_mode_recycle_bin_shape_item( $post );
101 + $items_posts[] = openstation_recycle_bin_shape_item( $post );
107 102 }
108 103 }
109 104
110 105 if ( $wants_comments ) {
@@ -120,17 +115,15 @@
120 115
121 116 /**
122 117 * Filter the `WP_Comment_Query` args used to populate the
123 118 * recycle bin's comments. Mirror of
124 - * `desktop_mode_recycle_bin_query_args` for comments.
119 + * `openstation_recycle_bin_query_args` for comments.
125 120 *
126 - * @since 0.21.0
127 - *
128 121 * @param array $comment_args Args passed to `get_comments()`.
129 122 * @param array $args Caller-provided args.
130 123 */
131 124 $comment_args = apply_filters(
132 - 'desktop_mode_recycle_bin_comment_query_args',
125 + 'openstation_recycle_bin_comment_query_args',
133 126 $comment_args,
134 127 $args
135 128 );
136 129
@@ -136,12 +129,12 @@
136 129
137 130 $comments = get_comments( $comment_args );
138 131 if ( is_array( $comments ) ) {
139 132 foreach ( $comments as $comment ) {
140 - if ( ! desktop_mode_recycle_bin_user_can_view_comment( $comment ) ) {
133 + if ( ! openstation_recycle_bin_user_can_view_comment( $comment ) ) {
141 134 continue;
142 135 }
143 - $items_comments[] = desktop_mode_recycle_bin_shape_comment_item( $comment );
136 + $items_comments[] = openstation_recycle_bin_shape_comment_item( $comment );
144 137 }
145 138 }
146 139 }
147 140
@@ -148,9 +141,9 @@
148 141 // Files-on-the-Desktop trash — soft-trashed placements
149 142 // (shortcuts) and folders. Returned in the same item shape so
150 143 // the JS layer treats them uniformly. The `placement` and
151 144 // `folder` types route to the desktop-files trash module on
152 - // restore / purge (see `desktop_mode_recycle_bin_handle_files_*`).
145 + // restore / purge (see `openstation_recycle_bin_handle_files_*`).
153 146 $items_files = array();
154 147 // Map UI filter → set of `type` values to keep from the
155 148 // files-on-desktop helper. The "Shortcuts" segment in the bin
156 149 // UI now covers both registered icons (`shortcut`) AND user
@@ -174,11 +167,11 @@
174 167 break;
175 168 }
176 169 if (
177 170 ! empty( $wanted_files_types )
178 - && function_exists( 'desktop_mode_files_list_trashed_for_recycle_bin' )
171 + && function_exists( 'openstation_files_list_trashed_for_recycle_bin' )
179 172 ) {
180 - $file_items = desktop_mode_files_list_trashed_for_recycle_bin(
173 + $file_items = openstation_files_list_trashed_for_recycle_bin(
181 174 get_current_user_id()
182 175 );
183 176 foreach ( (array) $file_items as $item ) {
184 177 if ( ! in_array( (string) $item['type'], $wanted_files_types, true ) ) {
@@ -193,11 +186,14 @@
193 186 // Sort the merged list chronologically by deleted_at desc. The
194 187 // shape always carries a sortable string in `deleted_at`, so a
195 188 // straight string compare is enough (`Y-m-d H:i:s` is sortable
196 189 // lexicographically).
197 - usort( $items, static function ( $a, $b ) {
198 - return strcmp( (string) $b['deleted_at'], (string) $a['deleted_at'] );
199 - } );
190 + usort(
191 + $items,
192 + static function ( $a, $b ) {
193 + return strcmp( (string) $b['deleted_at'], (string) $a['deleted_at'] );
194 + }
195 + );
200 196
201 197 // `total` reports the GLOBAL trash count (every type, every
202 198 // row, ignoring the current filter / search). The dock-tile
203 199 // + desktop-icon badge consume this directly — `setRecycleBinBadge`
@@ -203,9 +199,9 @@
203 199 // + desktop-icon badge consume this directly — `setRecycleBinBadge`
204 200 // only cares about "how many things are sitting in the bin
205 201 // right now". A future paginated UI that needs a filtered
206 202 // count can compute it from `count( $items )` itself.
207 - $total = desktop_mode_recycle_bin_count();
203 + $total = openstation_recycle_bin_count();
208 204
209 205 $offset = max( 0, ( max( 1, (int) $args['page'] ) - 1 ) * $per_page );
210 206 $sliced = array_slice( $items, $offset, $per_page );
211 207
@@ -211,15 +207,13 @@
211 207
212 208 /**
213 209 * Filter the final list of items returned to the JS layer.
214 210 *
215 - * @since 0.19.0
216 - *
217 211 * @param array $items Shaped list (id, title, type, deleted_at, …).
218 212 * @param array|null $query Underlying post query, or null for the
219 - * merged post+comment shape (since 0.21.0).
213 + * merged post+comment shape.
220 214 */
221 - $sliced = apply_filters( 'desktop_mode_recycle_bin_items', $sliced, null );
215 + $sliced = apply_filters( 'openstation_recycle_bin_items', $sliced, null );
222 216
223 217 return array(
224 218 'items' => $sliced,
225 219 'total' => $total,
@@ -229,34 +223,76 @@
229 223 /**
230 224 * Total number of items in the recycle bin, summed across every
231 225 * tracked source (post types + comments).
232 226 *
233 - * Cheaper than `desktop_mode_recycle_bin_get_items()` because it never
227 + * Cheaper than `openstation_recycle_bin_get_items()` because it never
234 228 * loads the row data — just the COUNT(*) under the hood. Used by
235 229 * the badge on the dock tile + desktop icon, and by the REST
236 230 * `/count` endpoint subscribers refresh on broadcasts.
237 231 *
238 - * @since 0.21.0
232 + * The post component mirrors the per-item `edit_post` gate the list
233 + * applies, at the aggregate level: tracked types the user cannot edit
234 + * at all contribute zero, and types where the user can only edit their
235 + * own posts are counted author-scoped — so the badge never discloses
236 + * the global trash total to low-capability users.
239 237 *
240 238 * @return int
241 239 */
242 -function desktop_mode_recycle_bin_count() {
243 - $post_types = desktop_mode_recycle_bin_capture_post_types();
240 +function openstation_recycle_bin_count() {
241 + $post_types = openstation_recycle_bin_capture_post_types();
244 242
245 - $post_query = new WP_Query(
246 - array(
247 - 'post_type' => $post_types,
248 - 'post_status' => 'trash',
249 - 'posts_per_page' => 1,
250 - 'fields' => 'ids',
251 - 'no_found_rows' => false,
252 - 'suppress_filters' => false,
253 - )
254 - );
255 - $post_count = (int) $post_query->found_posts;
243 + // Bucket the tracked types by what the current user may edit:
244 + // full count when they hold the type's `edit_others_posts`,
245 + // author-scoped count when they only hold `edit_posts`, nothing
246 + // otherwise. At most two cheap COUNT(*) queries.
247 + $all_types = array();
248 + $own_types = array();
249 + foreach ( $post_types as $post_type ) {
250 + $post_type_obj = get_post_type_object( $post_type );
251 + if ( ! $post_type_obj ) {
252 + continue;
253 + }
254 + if ( ! current_user_can( $post_type_obj->cap->edit_posts ) ) {
255 + continue;
256 + }
257 + if ( current_user_can( $post_type_obj->cap->edit_others_posts ) ) {
258 + $all_types[] = $post_type;
259 + } else {
260 + $own_types[] = $post_type;
261 + }
262 + }
256 263
264 + $post_count = 0;
265 + if ( ! empty( $all_types ) ) {
266 + $post_query = new WP_Query(
267 + array(
268 + 'post_type' => $all_types,
269 + 'post_status' => 'trash',
270 + 'posts_per_page' => 1,
271 + 'fields' => 'ids',
272 + 'no_found_rows' => false,
273 + 'suppress_filters' => false,
274 + )
275 + );
276 + $post_count += (int) $post_query->found_posts;
277 + }
278 + if ( ! empty( $own_types ) ) {
279 + $own_query = new WP_Query(
280 + array(
281 + 'post_type' => $own_types,
282 + 'post_status' => 'trash',
283 + 'posts_per_page' => 1,
284 + 'fields' => 'ids',
285 + 'no_found_rows' => false,
286 + 'suppress_filters' => false,
287 + 'author' => get_current_user_id(),
288 + )
289 + );
290 + $post_count += (int) $own_query->found_posts;
291 + }
292 +
257 293 $comment_count = 0;
258 - if ( desktop_mode_recycle_bin_comments_enabled() ) {
294 + if ( openstation_recycle_bin_comments_enabled() ) {
259 295 $comment_count = (int) get_comments(
260 296 array(
261 297 'status' => 'trash',
262 298 'count' => true,
@@ -264,10 +300,10 @@
264 300 );
265 301 }
266 302
267 303 $files_count = 0;
268 - if ( function_exists( 'desktop_mode_files_count_trashed_for_recycle_bin' ) ) {
269 - $files_count = (int) desktop_mode_files_count_trashed_for_recycle_bin( get_current_user_id() );
304 + if ( function_exists( 'openstation_files_count_trashed_for_recycle_bin' ) ) {
305 + $files_count = (int) openstation_files_count_trashed_for_recycle_bin( get_current_user_id() );
270 306 }
271 307
272 308 $total = $post_count + $comment_count + $files_count;
273 309
@@ -273,16 +309,15 @@
273 309
274 310 /**
275 311 * Filter the total count surfaced to the badge.
276 312 *
277 - * @since 0.21.0
278 - *
279 313 * @param int $total Default sum (posts + comments + files visible to the user).
280 - * @param int $post_count Items in trash from the post-type query.
314 + * @param int $post_count Items in trash from the post-type query, capability-scoped
315 + * to what the current user can edit.
281 316 * @param int $comment_count Items in trash from the comment query.
282 - * @param int $files_count Items in trash from the desktop-files trash (since 0.8.0).
317 + * @param int $files_count Items in trash from the desktop-files trash.
283 318 */
284 - return (int) apply_filters( 'desktop_mode_recycle_bin_count', $total, $post_count, $comment_count, $files_count );
319 + return (int) apply_filters( 'openstation_recycle_bin_count', $total, $post_count, $comment_count, $files_count );
285 320 }
286 321
287 322 /**
288 323 * Whether comments are part of the bin. Filterable so installs
@@ -288,23 +323,19 @@
288 323 * Whether comments are part of the bin. Filterable so installs
289 324 * that don't moderate comments at all (read-only blogs, headless
290 325 * setups) can hide the segment without touching the JS.
291 326 *
292 - * @since 0.21.0
293 - *
294 327 * @return bool
295 328 */
296 -function desktop_mode_recycle_bin_comments_enabled() {
329 +function openstation_recycle_bin_comments_enabled() {
297 330 $on = current_user_can( 'moderate_comments' );
298 331
299 332 /**
300 333 * Filter whether the recycle bin tracks comments.
301 334 *
302 - * @since 0.21.0
303 - *
304 335 * @param bool $on Default: current user has `moderate_comments`.
305 336 */
306 - return (bool) apply_filters( 'desktop_mode_recycle_bin_comments_enabled', $on );
337 + return (bool) apply_filters( 'openstation_recycle_bin_comments_enabled', $on );
307 338 }
308 339
309 340 /**
310 341 * Whether the current user can see a given trashed item.
@@ -312,70 +343,58 @@
312 343 * Mirrors `current_user_can( 'edit_post', $id )` for the consistent
313 344 * "if you can edit it, you can manage its trash" rule. Filterable for
314 345 * stricter / looser policies.
315 346 *
316 - * @since 0.19.0
317 - *
318 347 * @param WP_Post $post Trashed post.
319 348 * @return bool
320 349 */
321 -function desktop_mode_recycle_bin_user_can_view( $post ) {
350 +function openstation_recycle_bin_user_can_view( $post ) {
322 351 $can = current_user_can( 'edit_post', $post->ID );
323 352
324 353 /**
325 354 * Filter whether the current user can see a given trashed item.
326 355 *
327 - * @since 0.19.0
328 - *
329 356 * @param bool $can Default: edit_post capability check.
330 357 * @param WP_Post $post Trashed post.
331 358 */
332 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_view', $can, $post );
359 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_view', $can, $post );
333 360 }
334 361
335 362 /**
336 363 * Whether the current user can restore a given trashed item.
337 364 *
338 - * @since 0.19.0
339 - *
340 365 * @param WP_Post $post Trashed post.
341 366 * @return bool
342 367 */
343 -function desktop_mode_recycle_bin_user_can_restore( $post ) {
368 +function openstation_recycle_bin_user_can_restore( $post ) {
344 369 $can = current_user_can( 'delete_post', $post->ID );
345 370
346 371 /**
347 372 * Filter whether the current user can restore a given trashed item.
348 373 *
349 - * @since 0.19.0
350 - *
351 374 * @param bool $can Default: delete_post capability check (the same
352 375 * gate WP itself uses for trash/untrash).
353 376 * @param WP_Post $post Trashed post.
354 377 */
355 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_restore', $can, $post );
378 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_restore', $can, $post );
356 379 }
357 380
358 381 /**
359 382 * Whether the current user can permanently delete a trashed item.
360 383 *
361 - * @since 0.19.0
362 - *
363 384 * @param WP_Post $post Trashed post.
364 385 * @return bool
365 386 */
366 -function desktop_mode_recycle_bin_user_can_purge( $post ) {
387 +function openstation_recycle_bin_user_can_purge( $post ) {
367 388 $can = current_user_can( 'delete_post', $post->ID );
368 389
369 390 /**
370 391 * Filter whether the current user can permanently delete a trashed item.
371 392 *
372 - * @since 0.19.0
373 - *
374 393 * @param bool $can Default: delete_post capability check.
375 394 * @param WP_Post $post Trashed post.
376 395 */
377 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_purge', $can, $post );
396 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_purge', $can, $post );
378 397 }
379 398
380 399 /**
381 400 * Capability gates for trashed comments. Mirror of the post gates,
@@ -380,56 +399,47 @@
380 399 /**
381 400 * Capability gates for trashed comments. Mirror of the post gates,
382 401 * with `edit_comment`/`moderate_comments` as the WP-native checks.
383 402 *
384 - * @since 0.21.0
385 - *
386 403 * @param WP_Comment $comment Trashed comment.
387 404 * @return bool
388 405 */
389 -function desktop_mode_recycle_bin_user_can_view_comment( $comment ) {
406 +function openstation_recycle_bin_user_can_view_comment( $comment ) {
390 407 $can = current_user_can( 'edit_comment', $comment->comment_ID );
391 408
392 409 /**
393 - * @since 0.21.0
394 410 * @param bool $can Default: edit_comment capability check.
395 411 * @param WP_Comment $comment Trashed comment.
396 412 */
397 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_view_comment', $can, $comment );
413 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_view_comment', $can, $comment );
398 414 }
399 415
400 416 /**
401 - * @since 0.21.0
402 - *
403 417 * @param WP_Comment $comment Trashed comment.
404 418 * @return bool
405 419 */
406 -function desktop_mode_recycle_bin_user_can_restore_comment( $comment ) {
420 +function openstation_recycle_bin_user_can_restore_comment( $comment ) {
407 421 $can = current_user_can( 'edit_comment', $comment->comment_ID );
408 422
409 423 /**
410 - * @since 0.21.0
411 424 * @param bool $can Default: edit_comment capability check.
412 425 * @param WP_Comment $comment Trashed comment.
413 426 */
414 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_restore_comment', $can, $comment );
427 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_restore_comment', $can, $comment );
415 428 }
416 429
417 430 /**
418 - * @since 0.21.0
419 - *
420 431 * @param WP_Comment $comment Trashed comment.
421 432 * @return bool
422 433 */
423 -function desktop_mode_recycle_bin_user_can_purge_comment( $comment ) {
434 +function openstation_recycle_bin_user_can_purge_comment( $comment ) {
424 435 $can = current_user_can( 'edit_comment', $comment->comment_ID );
425 436
426 437 /**
427 - * @since 0.21.0
428 438 * @param bool $can Default: edit_comment capability check.
429 439 * @param WP_Comment $comment Trashed comment.
430 440 */
431 - return (bool) apply_filters( 'desktop_mode_recycle_bin_user_can_purge_comment', $can, $comment );
441 + return (bool) apply_filters( 'openstation_recycle_bin_user_can_purge_comment', $can, $comment );
432 442 }
433 443
434 444 /**
435 445 * Shape a `WP_Comment` into the JSON the JS table consumes.
@@ -438,14 +448,12 @@
438 448 * have to special-case the row by `type`. The `title` reads as
439 449 * "<author> on <post title>"; the `subtitle` carries a 100-char
440 450 * excerpt of `comment_content`.
441 451 *
442 - * @since 0.21.0
443 - *
444 452 * @param WP_Comment $comment Trashed comment.
445 453 * @return array
446 454 */
447 -function desktop_mode_recycle_bin_shape_comment_item( $comment ) {
455 +function openstation_recycle_bin_shape_comment_item( $comment ) {
448 456 $user_id = (int) get_comment_meta( $comment->comment_ID, '_desktop_mode_trash_user_id', true );
449 457 $deleted_at = (string) get_comment_meta( $comment->comment_ID, '_desktop_mode_trash_time_gmt', true );
450 458
451 459 if ( '' === $deleted_at ) {
@@ -452,9 +460,9 @@
452 460 $deleted_at = (string) $comment->comment_date_gmt;
453 461 }
454 462
455 463 $parent = $comment->comment_post_ID ? get_post( (int) $comment->comment_post_ID ) : null;
456 - $parent_text = $parent ? get_the_title( $parent ) : '';
464 + $parent_text = $parent ? openstation_recycle_bin_plain_text( get_the_title( $parent ) ) : '';
457 465 $author = $comment->comment_author
458 466 ? (string) $comment->comment_author
459 467 : __( 'Anonymous', 'desktop-mode' );
460 468
@@ -466,9 +474,9 @@
466 474 $parent_text
467 475 )
468 476 : $author;
469 477
470 - $subtitle = wp_trim_words( wp_strip_all_tags( (string) $comment->comment_content ), 18, '…' );
478 + $subtitle = openstation_recycle_bin_excerpt( (string) $comment->comment_content );
471 479
472 480 $user = $user_id ? get_userdata( $user_id ) : false;
473 481 $user_name = $user ? $user->display_name : '';
474 482
@@ -483,10 +491,10 @@
483 491 'icon' => 'dashicons-admin-comments',
484 492 'deleted_at' => $deleted_at,
485 493 'deleted_by' => $user_name,
486 494 'deleted_by_id' => $user_id,
487 - 'can_restore' => desktop_mode_recycle_bin_user_can_restore_comment( $comment ),
488 - 'can_purge' => desktop_mode_recycle_bin_user_can_purge_comment( $comment ),
495 + 'can_restore' => openstation_recycle_bin_user_can_restore_comment( $comment ),
496 + 'can_purge' => openstation_recycle_bin_user_can_purge_comment( $comment ),
489 497 'edit_link' => (string) get_edit_comment_link( $comment->comment_ID ),
490 498 );
491 499
492 500 /**
@@ -491,25 +499,59 @@
491 499
492 500 /**
493 501 * Filter the comment item shape.
494 502 *
495 - * @since 0.21.0
496 - *
497 503 * @param array $item Item shape.
498 504 * @param WP_Comment $comment Source comment.
499 505 */
500 - return (array) apply_filters( 'desktop_mode_recycle_bin_comment_item', $item, $comment );
506 + return (array) apply_filters( 'openstation_recycle_bin_comment_item', $item, $comment );
501 507 }
502 508
503 509 /**
510 + * Collapse a title/subtitle to plain text for the wire.
511 + *
512 + * `get_the_title()` runs the `the_title` filter chain, and
513 + * `wptexturize` in it encodes punctuation as numeric entities
514 + * (apostrophe → `&#8217;`, quotes, dashes) — correct for HTML
515 + * output, wrong for the bin table, which renders every cell via
516 + * `textContent` and would show the literal entity. Strip tags first,
517 + * then decode entities back to characters.
518 + *
519 + * @param string $text Raw filtered text.
520 + * @return string
521 + */
522 +function openstation_recycle_bin_plain_text( $text ) {
523 + return html_entity_decode(
524 + openstation_strip_all_tags( $text ),
525 + ENT_QUOTES,
526 + get_bloginfo( 'charset' )
527 + );
528 +}
529 +
530 +/**
531 + * The first words of a body, as the plain text of a row's subtitle.
532 + *
533 + * @param string $text Raw excerpt or content.
534 + * @return string
535 + */
536 +function openstation_recycle_bin_excerpt( $text ) {
537 + // `wp_trim_words()` strips tags itself, and in plain text that cuts
538 + // at a `<`. Trimming before the decode would avoid it, but where
539 + // WordPress counts characters instead of words an `&amp;` would
540 + // count as five and could be cut in half. So each `<` sits out the
541 + // trim as a control character, one for one.
542 + $text = str_replace( '<', "\x1A", openstation_recycle_bin_plain_text( $text ) );
543 +
544 + return str_replace( "\x1A", '<', wp_trim_words( $text, 18, '…' ) );
545 +}
546 +
547 +/**
504 548 * Shape one WP_Post into the JSON the JS table consumes.
505 549 *
506 - * @since 0.19.0
507 - *
508 550 * @param WP_Post $post Trashed post.
509 551 * @return array
510 552 */
511 -function desktop_mode_recycle_bin_shape_item( $post ) {
553 +function openstation_recycle_bin_shape_item( $post ) {
512 554 $user_id = (int) get_post_meta( $post->ID, '_desktop_mode_trash_user_id', true );
513 555 $deleted_at = (string) get_post_meta( $post->ID, '_desktop_mode_trash_time_gmt', true );
514 556
515 557 // Fall back to post_modified_gmt — set when wp_trash_post runs and
@@ -518,9 +560,9 @@
518 560 $deleted_at = (string) $post->post_modified_gmt;
519 561 }
520 562
521 563 $type = (string) $post->post_type;
522 - $title = (string) get_the_title( $post );
564 + $title = openstation_recycle_bin_plain_text( (string) get_the_title( $post ) );
523 565 $mime = (string) $post->post_mime_type;
524 566 $preview = '';
525 567 $icon = '';
526 568 $subtitle = '';
@@ -532,18 +574,33 @@
532 574 $thumb = wp_get_attachment_image_src( $post->ID, array( 64, 64 ), true );
533 575 if ( is_array( $thumb ) ) {
534 576 $preview = (string) $thumb[0];
535 577 }
536 - $icon = desktop_mode_recycle_bin_icon_for_mime( $mime );
578 + $icon = openstation_recycle_bin_icon_for_mime( $mime );
537 579 $subtitle = $mime;
538 580 } elseif ( 'post' === $type ) {
539 581 $icon = 'dashicons-admin-post';
540 - $subtitle = wp_trim_words( wp_strip_all_tags( (string) $post->post_excerpt ?: (string) $post->post_content ), 18, '…' );
582 + $excerpt = (string) $post->post_excerpt;
583 + $subtitle = openstation_recycle_bin_excerpt( $excerpt ? $excerpt : (string) $post->post_content );
541 584 } elseif ( 'page' === $type ) {
542 585 $icon = 'dashicons-admin-page';
543 - $subtitle = wp_trim_words( wp_strip_all_tags( (string) $post->post_content ), 18, '…' );
586 + $subtitle = openstation_recycle_bin_excerpt( (string) $post->post_content );
544 587 } else {
545 - $icon = 'dashicons-media-default';
588 + // Custom post types: reuse the type's own menu Dashicon when it
589 + // registered one, so a trashed product row reads as a product
590 + // instead of a generic file. Content excerpt as the subtitle,
591 + // same as posts.
592 + $icon = 'dashicons-media-default';
593 + $post_type_obj = get_post_type_object( $type );
594 + if (
595 + $post_type_obj
596 + && is_string( $post_type_obj->menu_icon )
597 + && str_starts_with( $post_type_obj->menu_icon, 'dashicons-' )
598 + ) {
599 + $icon = $post_type_obj->menu_icon;
600 + }
601 + $excerpt = (string) $post->post_excerpt;
602 + $subtitle = openstation_recycle_bin_excerpt( $excerpt ? $excerpt : (string) $post->post_content );
546 603 }
547 604
548 605 $user = $user_id ? get_userdata( $user_id ) : false;
549 606 $user_name = $user ? $user->display_name : '';
@@ -575,10 +632,10 @@
575 632 'icon' => $icon,
576 633 'deleted_at' => $deleted_at,
577 634 'deleted_by' => $user_name,
578 635 'deleted_by_id' => $user_id,
579 - 'can_restore' => desktop_mode_recycle_bin_user_can_restore( $post ),
580 - 'can_purge' => desktop_mode_recycle_bin_user_can_purge( $post ),
636 + 'can_restore' => openstation_recycle_bin_user_can_restore( $post ),
637 + 'can_purge' => openstation_recycle_bin_user_can_purge( $post ),
581 638 'edit_link' => (string) get_edit_post_link( $post->ID, 'raw' ),
582 639 );
583 640
584 641 /**
@@ -587,25 +644,21 @@
587 644 * Add custom columns or override the icon/preview for a custom
588 645 * post type. The id/type/deleted_at trio is load-bearing — keep
589 646 * them in the returned array.
590 647 *
591 - * @since 0.19.0
592 - *
593 648 * @param array $item Item shape.
594 649 * @param WP_Post $post Source post.
595 650 */
596 - return (array) apply_filters( 'desktop_mode_recycle_bin_item', $item, $post );
651 + return (array) apply_filters( 'openstation_recycle_bin_item', $item, $post );
597 652 }
598 653
599 654 /**
600 655 * Map a mime type to a Dashicon for the type cell.
601 656 *
602 - * @since 0.19.0
603 - *
604 657 * @param string $mime Mime type.
605 658 * @return string Dashicon class.
606 659 */
607 -function desktop_mode_recycle_bin_icon_for_mime( $mime ) {
660 +function openstation_recycle_bin_icon_for_mime( $mime ) {
608 661 if ( '' === $mime ) {
609 662 return 'dashicons-media-default';
610 663 }
611 664 if ( str_starts_with( $mime, 'image/' ) ) {
@@ -648,51 +701,46 @@
648 701 * everything else through `wp_untrash_post`. The legacy single-arg
649 702 * call (id only) defaults to `'post'` so older clients that haven't
650 703 * migrated to the typed API keep working.
651 704 *
652 - * @since 0.19.0
653 - * @since 0.21.0 Added `$type` parameter.
654 - *
655 705 * @param int $id Post id (or comment id when `$type === 'comment'`).
656 706 * @param string $type Entity type — '', 'post', 'page', 'attachment', or 'comment'.
657 707 * @return true|WP_Error
658 708 */
659 -function desktop_mode_recycle_bin_restore( $id, $type = '' ) {
709 +function openstation_recycle_bin_restore( $id, $type = '' ) {
660 710 $id = (int) $id;
661 711 if ( 'comment' === $type ) {
662 - return desktop_mode_recycle_bin_restore_comment( $id );
712 + return openstation_recycle_bin_restore_comment( $id );
663 713 }
664 - if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'desktop_mode_files_restore_placement' ) ) {
665 - return desktop_mode_files_restore_placement( get_current_user_id(), $id );
714 + if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'openstation_files_restore_placement' ) ) {
715 + return openstation_files_restore_placement( get_current_user_id(), $id );
666 716 }
667 - if ( 'folder' === $type && function_exists( 'desktop_mode_files_restore_folder' ) ) {
668 - return desktop_mode_files_restore_folder( get_current_user_id(), $id );
717 + if ( 'folder' === $type && function_exists( 'openstation_files_restore_folder' ) ) {
718 + return openstation_files_restore_folder( get_current_user_id(), $id );
669 719 }
670 720
671 721 $post = get_post( $id );
672 722 if ( ! $post ) {
673 - return new WP_Error( 'desktop_mode_recycle_bin_not_found', __( 'Item not found.', 'desktop-mode' ), array( 'status' => 404 ) );
723 + return new WP_Error( 'openstation_recycle_bin_not_found', __( 'Item not found.', 'desktop-mode' ), array( 'status' => 404 ) );
674 724 }
675 725 if ( 'trash' !== $post->post_status ) {
676 - return new WP_Error( 'desktop_mode_recycle_bin_not_trashed', __( 'Item is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
726 + return new WP_Error( 'openstation_recycle_bin_not_trashed', __( 'Item is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
677 727 }
678 - if ( ! desktop_mode_recycle_bin_user_can_restore( $post ) ) {
679 - return new WP_Error( 'desktop_mode_recycle_bin_forbidden', __( 'You are not allowed to restore this item.', 'desktop-mode' ), array( 'status' => 403 ) );
728 + if ( ! openstation_recycle_bin_user_can_restore( $post ) ) {
729 + return new WP_Error( 'openstation_recycle_bin_forbidden', __( 'You are not allowed to restore this item.', 'desktop-mode' ), array( 'status' => 403 ) );
680 730 }
681 731
682 732 /**
683 733 * Fires before a recycle-bin item is restored.
684 734 *
685 - * @since 0.19.0
686 - *
687 735 * @param int $id Post id about to be restored.
688 736 * @param WP_Post $post Trashed post object.
689 737 */
690 - do_action( 'desktop_mode_recycle_bin_before_restore', $id, $post );
738 + do_action( 'openstation_recycle_bin_before_restore', $id, $post );
691 739
692 740 $ok = wp_untrash_post( $id );
693 741 if ( ! $ok ) {
694 - return new WP_Error( 'desktop_mode_recycle_bin_restore_failed', __( 'Failed to restore item.', 'desktop-mode' ), array( 'status' => 500 ) );
742 + return new WP_Error( 'openstation_recycle_bin_restore_failed', __( 'Failed to restore item.', 'desktop-mode' ), array( 'status' => 500 ) );
695 743 }
696 744
697 745 delete_post_meta( $id, '_desktop_mode_trash_user_id' );
698 746 delete_post_meta( $id, '_desktop_mode_trash_time_gmt' );
@@ -699,13 +747,11 @@
699 747
700 748 /**
701 749 * Fires after a recycle-bin item is restored.
702 750 *
703 - * @since 0.19.0
704 - *
705 751 * @param int $id Post id that was restored.
706 752 */
707 - do_action( 'desktop_mode_recycle_bin_after_restore', $id );
753 + do_action( 'openstation_recycle_bin_after_restore', $id );
708 754
709 755 return true;
710 756 }
711 757
@@ -711,40 +757,36 @@
711 757
712 758 /**
713 759 * Restore a single trashed comment.
714 760 *
715 - * @since 0.21.0
716 - *
717 761 * @param int $comment_id Comment id.
718 762 * @return true|WP_Error
719 763 */
720 -function desktop_mode_recycle_bin_restore_comment( $comment_id ) {
764 +function openstation_recycle_bin_restore_comment( $comment_id ) {
721 765 $comment_id = (int) $comment_id;
722 766 $comment = get_comment( $comment_id );
723 767
724 768 if ( ! $comment ) {
725 - return new WP_Error( 'desktop_mode_recycle_bin_not_found', __( 'Comment not found.', 'desktop-mode' ), array( 'status' => 404 ) );
769 + return new WP_Error( 'openstation_recycle_bin_not_found', __( 'Comment not found.', 'desktop-mode' ), array( 'status' => 404 ) );
726 770 }
727 771 if ( 'trash' !== $comment->comment_approved ) {
728 - return new WP_Error( 'desktop_mode_recycle_bin_not_trashed', __( 'Comment is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
772 + return new WP_Error( 'openstation_recycle_bin_not_trashed', __( 'Comment is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
729 773 }
730 - if ( ! desktop_mode_recycle_bin_user_can_restore_comment( $comment ) ) {
731 - return new WP_Error( 'desktop_mode_recycle_bin_forbidden', __( 'You are not allowed to restore this comment.', 'desktop-mode' ), array( 'status' => 403 ) );
774 + if ( ! openstation_recycle_bin_user_can_restore_comment( $comment ) ) {
775 + return new WP_Error( 'openstation_recycle_bin_forbidden', __( 'You are not allowed to restore this comment.', 'desktop-mode' ), array( 'status' => 403 ) );
732 776 }
733 777
734 778 /**
735 779 * Fires before a comment is restored from the recycle bin.
736 780 *
737 - * @since 0.21.0
738 - *
739 781 * @param int $comment_id Comment id.
740 782 * @param WP_Comment $comment Trashed comment.
741 783 */
742 - do_action( 'desktop_mode_recycle_bin_before_restore_comment', $comment_id, $comment );
784 + do_action( 'openstation_recycle_bin_before_restore_comment', $comment_id, $comment );
743 785
744 786 $ok = wp_untrash_comment( $comment_id );
745 787 if ( ! $ok ) {
746 - return new WP_Error( 'desktop_mode_recycle_bin_restore_failed', __( 'Failed to restore comment.', 'desktop-mode' ), array( 'status' => 500 ) );
788 + return new WP_Error( 'openstation_recycle_bin_restore_failed', __( 'Failed to restore comment.', 'desktop-mode' ), array( 'status' => 500 ) );
747 789 }
748 790
749 791 delete_comment_meta( $comment_id, '_desktop_mode_trash_user_id' );
750 792 delete_comment_meta( $comment_id, '_desktop_mode_trash_time_gmt' );
@@ -751,13 +793,11 @@
751 793
752 794 /**
753 795 * Fires after a comment is restored from the recycle bin.
754 796 *
755 - * @since 0.21.0
756 - *
757 797 * @param int $comment_id Comment id.
758 798 */
759 - do_action( 'desktop_mode_recycle_bin_after_restore_comment', $comment_id );
799 + do_action( 'openstation_recycle_bin_after_restore_comment', $comment_id );
760 800
761 801 return true;
762 802 }
763 803
@@ -763,51 +803,48 @@
763 803
764 804 /**
765 805 * Permanently delete a single trashed item. Dispatches by `$type`.
766 806 *
767 - * @since 0.19.0
768 - * @since 0.21.0 Added `$type` parameter.
769 - *
770 807 * @param int $id Post id (or comment id when `$type === 'comment'`).
771 808 * @param string $type Entity type — '', 'post', 'page', 'attachment', or 'comment'.
772 809 * @return true|WP_Error
773 810 */
774 -function desktop_mode_recycle_bin_purge( $id, $type = '' ) {
811 +function openstation_recycle_bin_purge( $id, $type = '' ) {
775 812 $id = (int) $id;
776 813 if ( 'comment' === $type ) {
777 - return desktop_mode_recycle_bin_purge_comment( $id );
814 + return openstation_recycle_bin_purge_comment( $id );
778 815 }
779 - if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'desktop_mode_files_purge_placement' ) ) {
780 - return desktop_mode_files_purge_placement( get_current_user_id(), $id );
816 + if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'openstation_files_purge_placement' ) ) {
817 + return openstation_files_purge_placement( get_current_user_id(), $id );
781 818 }
782 - if ( 'folder' === $type && function_exists( 'desktop_mode_files_purge_folder' ) ) {
783 - return desktop_mode_files_purge_folder( get_current_user_id(), $id );
819 + if ( 'folder' === $type && function_exists( 'openstation_files_purge_folder' ) ) {
820 + return openstation_files_purge_folder( get_current_user_id(), $id );
784 821 }
785 822
786 823 $post = get_post( $id );
787 824 if ( ! $post ) {
788 - return new WP_Error( 'desktop_mode_recycle_bin_not_found', __( 'Item not found.', 'desktop-mode' ), array( 'status' => 404 ) );
825 + return new WP_Error( 'openstation_recycle_bin_not_found', __( 'Item not found.', 'desktop-mode' ), array( 'status' => 404 ) );
789 826 }
790 827 if ( 'trash' !== $post->post_status ) {
791 - return new WP_Error( 'desktop_mode_recycle_bin_not_trashed', __( 'Item is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
828 + return new WP_Error( 'openstation_recycle_bin_not_trashed', __( 'Item is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
792 829 }
793 - if ( ! desktop_mode_recycle_bin_user_can_purge( $post ) ) {
794 - return new WP_Error( 'desktop_mode_recycle_bin_forbidden', __( 'You are not allowed to permanently delete this item.', 'desktop-mode' ), array( 'status' => 403 ) );
830 + if ( ! openstation_recycle_bin_user_can_purge( $post ) ) {
831 + return new WP_Error( 'openstation_recycle_bin_forbidden', __( 'You are not allowed to permanently delete this item.', 'desktop-mode' ), array( 'status' => 403 ) );
795 832 }
796 833
797 834 /**
798 835 * Fires before a recycle-bin item is permanently deleted.
799 836 *
800 - * @since 0.19.0
801 - *
802 837 * @param int $id Post id about to be deleted.
803 838 * @param WP_Post $post Trashed post object.
804 839 */
805 - do_action( 'desktop_mode_recycle_bin_before_purge', $id, $post );
840 + do_action( 'openstation_recycle_bin_before_purge', $id, $post );
806 841
807 842 if ( 'attachment' === $post->post_type ) {
808 - // Force-delete bypasses our `pre_delete_attachment` interception
809 - // (which would loop us back into trash) and removes the file.
843 + // Force-delete (`true`) removes the attachment and its file
844 + // permanently. (The item is already trashed, so even with
845 + // MEDIA_TRASH enabled core would not re-route it to trash;
846 + // `true` simply makes the purge intent explicit.)
810 847 $result = wp_delete_attachment( $id, true );
811 848 } else {
812 849 $result = wp_delete_post( $id, true );
813 850 }
@@ -812,20 +849,18 @@
812 849 $result = wp_delete_post( $id, true );
813 850 }
814 851
815 852 if ( ! $result ) {
816 - return new WP_Error( 'desktop_mode_recycle_bin_purge_failed', __( 'Failed to permanently delete item.', 'desktop-mode' ), array( 'status' => 500 ) );
853 + return new WP_Error( 'openstation_recycle_bin_purge_failed', __( 'Failed to permanently delete item.', 'desktop-mode' ), array( 'status' => 500 ) );
817 854 }
818 855
819 856 /**
820 857 * Fires after a recycle-bin item is permanently deleted.
821 858 *
822 - * @since 0.19.0
823 - *
824 859 * @param int $id Post id that was purged.
825 860 * @param string $type Post type of the purged item.
826 861 */
827 - do_action( 'desktop_mode_recycle_bin_after_purge', $id, $post->post_type );
862 + do_action( 'openstation_recycle_bin_after_purge', $id, $post->post_type );
828 863
829 864 return true;
830 865 }
831 866
@@ -831,51 +866,45 @@
831 866
832 867 /**
833 868 * Permanently delete a single trashed comment.
834 869 *
835 - * @since 0.21.0
836 - *
837 870 * @param int $comment_id Comment id.
838 871 * @return true|WP_Error
839 872 */
840 -function desktop_mode_recycle_bin_purge_comment( $comment_id ) {
873 +function openstation_recycle_bin_purge_comment( $comment_id ) {
841 874 $comment_id = (int) $comment_id;
842 875 $comment = get_comment( $comment_id );
843 876
844 877 if ( ! $comment ) {
845 - return new WP_Error( 'desktop_mode_recycle_bin_not_found', __( 'Comment not found.', 'desktop-mode' ), array( 'status' => 404 ) );
878 + return new WP_Error( 'openstation_recycle_bin_not_found', __( 'Comment not found.', 'desktop-mode' ), array( 'status' => 404 ) );
846 879 }
847 880 if ( 'trash' !== $comment->comment_approved ) {
848 - return new WP_Error( 'desktop_mode_recycle_bin_not_trashed', __( 'Comment is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
881 + return new WP_Error( 'openstation_recycle_bin_not_trashed', __( 'Comment is not in the trash.', 'desktop-mode' ), array( 'status' => 409 ) );
849 882 }
850 - if ( ! desktop_mode_recycle_bin_user_can_purge_comment( $comment ) ) {
851 - return new WP_Error( 'desktop_mode_recycle_bin_forbidden', __( 'You are not allowed to permanently delete this comment.', 'desktop-mode' ), array( 'status' => 403 ) );
883 + if ( ! openstation_recycle_bin_user_can_purge_comment( $comment ) ) {
884 + return new WP_Error( 'openstation_recycle_bin_forbidden', __( 'You are not allowed to permanently delete this comment.', 'desktop-mode' ), array( 'status' => 403 ) );
852 885 }
853 886
854 887 /**
855 888 * Fires before a comment is permanently deleted via the bin.
856 889 *
857 - * @since 0.21.0
858 - *
859 890 * @param int $comment_id Comment id.
860 891 * @param WP_Comment $comment Trashed comment.
861 892 */
862 - do_action( 'desktop_mode_recycle_bin_before_purge_comment', $comment_id, $comment );
893 + do_action( 'openstation_recycle_bin_before_purge_comment', $comment_id, $comment );
863 894
864 895 $result = wp_delete_comment( $comment_id, true );
865 896
866 897 if ( ! $result ) {
867 - return new WP_Error( 'desktop_mode_recycle_bin_purge_failed', __( 'Failed to permanently delete comment.', 'desktop-mode' ), array( 'status' => 500 ) );
898 + return new WP_Error( 'openstation_recycle_bin_purge_failed', __( 'Failed to permanently delete comment.', 'desktop-mode' ), array( 'status' => 500 ) );
868 899 }
869 900
870 901 /**
871 902 * Fires after a comment is permanently deleted via the bin.
872 903 *
873 - * @since 0.21.0
874 - *
875 904 * @param int $comment_id Comment id.
876 905 */
877 - do_action( 'desktop_mode_recycle_bin_after_purge_comment', $comment_id );
906 + do_action( 'openstation_recycle_bin_after_purge_comment', $comment_id );
878 907
879 908 return true;
880 909 }
881 910
@@ -888,13 +917,11 @@
888 917 * Processes at most one chunk per call. The cap protects against PHP
889 918 * timeouts on large bins; the client iterates while `remaining > 0`
890 919 * (and bails when `remaining === skipped`, i.e. nothing the user can
891 920 * purge is left). Site owners with longer execution budgets can tune
892 - * the chunk size via the `desktop_mode_recycle_bin_empty_chunk_size`
921 + * the chunk size via the `openstation_recycle_bin_empty_chunk_size`
893 922 * filter.
894 923 *
895 - * @since 0.19.0
896 - *
897 924 * @return array {
898 925 * @type int $purged Items successfully purged in this call.
899 926 * @type int $skipped Items skipped (capability or error).
900 927 * @type int $remaining Items still in the bin after this call (across pages).
@@ -899,9 +926,9 @@
899 926 * @type int $skipped Items skipped (capability or error).
900 927 * @type int $remaining Items still in the bin after this call (across pages).
901 928 * }
902 929 */
903 -function desktop_mode_recycle_bin_empty() {
930 +function openstation_recycle_bin_empty() {
904 931 $purged = 0;
905 932 $skipped = 0;
906 933
907 934 /**
@@ -906,19 +933,17 @@
906 933
907 934 /**
908 935 * Filter the per-call chunk size for the empty-bin loop.
909 936 *
910 - * `desktop_mode_recycle_bin_empty()` only purges this many items
937 + * `openstation_recycle_bin_empty()` only purges this many items
911 938 * per invocation. The client iterates while `remaining > 0`. The
912 939 * default (200) is conservative for shared hosts; sites with
913 940 * generous PHP execution limits can raise it to make emptying a
914 941 * large bin take fewer roundtrips.
915 942 *
916 - * @since 0.21.1
917 - *
918 943 * @param int $chunk_size Items processed per call. Default 200.
919 944 */
920 - $chunk_size = (int) apply_filters( 'desktop_mode_recycle_bin_empty_chunk_size', 200 );
945 + $chunk_size = (int) apply_filters( 'openstation_recycle_bin_empty_chunk_size', 200 );
921 946 if ( $chunk_size < 1 ) {
922 947 $chunk_size = 1;
923 948 }
924 949
@@ -925,11 +950,16 @@
925 950 // Loop in chunks — `wp_delete_post()` is cheap individually but
926 951 // hammering it on a 10k-item bin without yielding back to PHP can
927 952 // still time out. The client re-invokes us until `remaining` hits
928 953 // zero (or stalls at `skipped`).
929 - $batch = desktop_mode_recycle_bin_get_items( array( 'per_page' => $chunk_size, 'page' => 1 ) );
954 + $batch = openstation_recycle_bin_get_items(
955 + array(
956 + 'per_page' => $chunk_size,
957 + 'page' => 1,
958 + )
959 + );
930 960 foreach ( $batch['items'] as $item ) {
931 - $result = desktop_mode_recycle_bin_purge(
961 + $result = openstation_recycle_bin_purge(
932 962 (int) $item['id'],
933 963 (string) ( $item['type'] ?? '' )
934 964 );
935 965 if ( is_wp_error( $result ) ) {
@@ -941,14 +971,12 @@
941 971
942 972 /**
943 973 * Fires after the recycle bin is emptied.
944 974 *
945 - * @since 0.19.0
946 - *
947 975 * @param int $purged Items successfully purged in this call.
948 976 * @param int $skipped Items skipped (capability or error).
949 977 */
950 - do_action( 'desktop_mode_recycle_bin_emptied', $purged, $skipped );
978 + do_action( 'openstation_recycle_bin_emptied', $purged, $skipped );
951 979
952 980 return array(
953 981 'purged' => $purged,
954 982 'skipped' => $skipped,