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 +137 -110 0.9.8 → 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,13 +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
14 + * @package OpenStation
15 15 */
16 16
17 17 defined( 'ABSPATH' ) || exit;
18 18
@@ -32,9 +32,9 @@
32 32 * @type array $items List of items shaped for the JS layer.
33 33 * @type int $total Total matching rows (across pages).
34 34 * }
35 35 */
36 -function desktop_mode_recycle_bin_get_items( $args = array() ) {
36 +function openstation_recycle_bin_get_items( $args = array() ) {
37 37 $args = wp_parse_args(
38 38 $args,
39 39 array(
40 40 'per_page' => 100,
@@ -56,9 +56,9 @@
56 56
57 57 // Source gates: each `$type` filter narrows down to the
58 58 // owning store. `''` (All) loads every source. The files-on-
59 59 // desktop sources (`shortcut` / `placement` / `folder`) live in
60 - // `desktop_mode_files_list_trashed_for_recycle_bin` — never run
60 + // `openstation_files_list_trashed_for_recycle_bin` — never run
61 61 // the WP-core post / comment queries when one of those is the
62 62 // active filter, otherwise trashed posts leak into the
63 63 // "Shortcuts" / "Folders" tabs.
64 64 $files_types = array( 'desktop', 'placement', 'shortcut', 'folder' );
@@ -65,12 +65,12 @@
65 65 $is_files_filter = in_array( $type, $files_types, true );
66 66 $wants_post_types = '' === $type
67 67 || ( 'comment' !== $type && ! $is_files_filter );
68 68 $wants_comments = ( '' === $type || 'comment' === $type )
69 - && desktop_mode_recycle_bin_comments_enabled();
69 + && openstation_recycle_bin_comments_enabled();
70 70
71 71 if ( $wants_post_types ) {
72 - $post_types = desktop_mode_recycle_bin_capture_post_types();
72 + $post_types = openstation_recycle_bin_capture_post_types();
73 73 if ( '' !== $type && in_array( $type, $post_types, true ) ) {
74 74 $post_types = array( $type );
75 75 }
76 76
@@ -90,16 +90,16 @@
90 90 *
91 91 * @param array $query_args Args passed to WP_Query.
92 92 * @param array $args Caller-provided args.
93 93 */
94 - $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 );
95 95
96 96 $query = new WP_Query( $query_args );
97 97 foreach ( $query->posts as $post ) {
98 - if ( ! desktop_mode_recycle_bin_user_can_view( $post ) ) {
98 + if ( ! openstation_recycle_bin_user_can_view( $post ) ) {
99 99 continue;
100 100 }
101 - $items_posts[] = desktop_mode_recycle_bin_shape_item( $post );
101 + $items_posts[] = openstation_recycle_bin_shape_item( $post );
102 102 }
103 103 }
104 104
105 105 if ( $wants_comments ) {
@@ -115,15 +115,15 @@
115 115
116 116 /**
117 117 * Filter the `WP_Comment_Query` args used to populate the
118 118 * recycle bin's comments. Mirror of
119 - * `desktop_mode_recycle_bin_query_args` for comments.
119 + * `openstation_recycle_bin_query_args` for comments.
120 120 *
121 121 * @param array $comment_args Args passed to `get_comments()`.
122 122 * @param array $args Caller-provided args.
123 123 */
124 124 $comment_args = apply_filters(
125 - 'desktop_mode_recycle_bin_comment_query_args',
125 + 'openstation_recycle_bin_comment_query_args',
126 126 $comment_args,
127 127 $args
128 128 );
129 129
@@ -129,12 +129,12 @@
129 129
130 130 $comments = get_comments( $comment_args );
131 131 if ( is_array( $comments ) ) {
132 132 foreach ( $comments as $comment ) {
133 - if ( ! desktop_mode_recycle_bin_user_can_view_comment( $comment ) ) {
133 + if ( ! openstation_recycle_bin_user_can_view_comment( $comment ) ) {
134 134 continue;
135 135 }
136 - $items_comments[] = desktop_mode_recycle_bin_shape_comment_item( $comment );
136 + $items_comments[] = openstation_recycle_bin_shape_comment_item( $comment );
137 137 }
138 138 }
139 139 }
140 140
@@ -141,9 +141,9 @@
141 141 // Files-on-the-Desktop trash — soft-trashed placements
142 142 // (shortcuts) and folders. Returned in the same item shape so
143 143 // the JS layer treats them uniformly. The `placement` and
144 144 // `folder` types route to the desktop-files trash module on
145 - // restore / purge (see `desktop_mode_recycle_bin_handle_files_*`).
145 + // restore / purge (see `openstation_recycle_bin_handle_files_*`).
146 146 $items_files = array();
147 147 // Map UI filter → set of `type` values to keep from the
148 148 // files-on-desktop helper. The "Shortcuts" segment in the bin
149 149 // UI now covers both registered icons (`shortcut`) AND user
@@ -167,11 +167,11 @@
167 167 break;
168 168 }
169 169 if (
170 170 ! empty( $wanted_files_types )
171 - && function_exists( 'desktop_mode_files_list_trashed_for_recycle_bin' )
171 + && function_exists( 'openstation_files_list_trashed_for_recycle_bin' )
172 172 ) {
173 - $file_items = desktop_mode_files_list_trashed_for_recycle_bin(
173 + $file_items = openstation_files_list_trashed_for_recycle_bin(
174 174 get_current_user_id()
175 175 );
176 176 foreach ( (array) $file_items as $item ) {
177 177 if ( ! in_array( (string) $item['type'], $wanted_files_types, true ) ) {
@@ -186,11 +186,14 @@
186 186 // Sort the merged list chronologically by deleted_at desc. The
187 187 // shape always carries a sortable string in `deleted_at`, so a
188 188 // straight string compare is enough (`Y-m-d H:i:s` is sortable
189 189 // lexicographically).
190 - usort( $items, static function ( $a, $b ) {
191 - return strcmp( (string) $b['deleted_at'], (string) $a['deleted_at'] );
192 - } );
190 + usort(
191 + $items,
192 + static function ( $a, $b ) {
193 + return strcmp( (string) $b['deleted_at'], (string) $a['deleted_at'] );
194 + }
195 + );
193 196
194 197 // `total` reports the GLOBAL trash count (every type, every
195 198 // row, ignoring the current filter / search). The dock-tile
196 199 // + desktop-icon badge consume this directly — `setRecycleBinBadge`
@@ -196,9 +199,9 @@
196 199 // + desktop-icon badge consume this directly — `setRecycleBinBadge`
197 200 // only cares about "how many things are sitting in the bin
198 201 // right now". A future paginated UI that needs a filtered
199 202 // count can compute it from `count( $items )` itself.
200 - $total = desktop_mode_recycle_bin_count();
203 + $total = openstation_recycle_bin_count();
201 204
202 205 $offset = max( 0, ( max( 1, (int) $args['page'] ) - 1 ) * $per_page );
203 206 $sliced = array_slice( $items, $offset, $per_page );
204 207
@@ -208,9 +211,9 @@
208 211 * @param array $items Shaped list (id, title, type, deleted_at, …).
209 212 * @param array|null $query Underlying post query, or null for the
210 213 * merged post+comment shape.
211 214 */
212 - $sliced = apply_filters( 'desktop_mode_recycle_bin_items', $sliced, null );
215 + $sliced = apply_filters( 'openstation_recycle_bin_items', $sliced, null );
213 216
214 217 return array(
215 218 'items' => $sliced,
216 219 'total' => $total,
@@ -220,9 +223,9 @@
220 223 /**
221 224 * Total number of items in the recycle bin, summed across every
222 225 * tracked source (post types + comments).
223 226 *
224 - * Cheaper than `desktop_mode_recycle_bin_get_items()` because it never
227 + * Cheaper than `openstation_recycle_bin_get_items()` because it never
225 228 * loads the row data — just the COUNT(*) under the hood. Used by
226 229 * the badge on the dock tile + desktop icon, and by the REST
227 230 * `/count` endpoint subscribers refresh on broadcasts.
228 231 *
@@ -233,10 +236,10 @@
233 236 * the global trash total to low-capability users.
234 237 *
235 238 * @return int
236 239 */
237 -function desktop_mode_recycle_bin_count() {
238 - $post_types = desktop_mode_recycle_bin_capture_post_types();
240 +function openstation_recycle_bin_count() {
241 + $post_types = openstation_recycle_bin_capture_post_types();
239 242
240 243 // Bucket the tracked types by what the current user may edit:
241 244 // full count when they hold the type's `edit_others_posts`,
242 245 // author-scoped count when they only hold `edit_posts`, nothing
@@ -287,9 +290,9 @@
287 290 $post_count += (int) $own_query->found_posts;
288 291 }
289 292
290 293 $comment_count = 0;
291 - if ( desktop_mode_recycle_bin_comments_enabled() ) {
294 + if ( openstation_recycle_bin_comments_enabled() ) {
292 295 $comment_count = (int) get_comments(
293 296 array(
294 297 'status' => 'trash',
295 298 'count' => true,
@@ -297,10 +300,10 @@
297 300 );
298 301 }
299 302
300 303 $files_count = 0;
301 - if ( function_exists( 'desktop_mode_files_count_trashed_for_recycle_bin' ) ) {
302 - $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() );
303 306 }
304 307
305 308 $total = $post_count + $comment_count + $files_count;
306 309
@@ -312,9 +315,9 @@
312 315 * to what the current user can edit.
313 316 * @param int $comment_count Items in trash from the comment query.
314 317 * @param int $files_count Items in trash from the desktop-files trash.
315 318 */
316 - 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 );
317 320 }
318 321
319 322 /**
320 323 * Whether comments are part of the bin. Filterable so installs
@@ -322,9 +325,9 @@
322 325 * setups) can hide the segment without touching the JS.
323 326 *
324 327 * @return bool
325 328 */
326 -function desktop_mode_recycle_bin_comments_enabled() {
329 +function openstation_recycle_bin_comments_enabled() {
327 330 $on = current_user_can( 'moderate_comments' );
328 331
329 332 /**
330 333 * Filter whether the recycle bin tracks comments.
@@ -330,9 +333,9 @@
330 333 * Filter whether the recycle bin tracks comments.
331 334 *
332 335 * @param bool $on Default: current user has `moderate_comments`.
333 336 */
334 - return (bool) apply_filters( 'desktop_mode_recycle_bin_comments_enabled', $on );
337 + return (bool) apply_filters( 'openstation_recycle_bin_comments_enabled', $on );
335 338 }
336 339
337 340 /**
338 341 * Whether the current user can see a given trashed item.
@@ -343,9 +346,9 @@
343 346 *
344 347 * @param WP_Post $post Trashed post.
345 348 * @return bool
346 349 */
347 -function desktop_mode_recycle_bin_user_can_view( $post ) {
350 +function openstation_recycle_bin_user_can_view( $post ) {
348 351 $can = current_user_can( 'edit_post', $post->ID );
349 352
350 353 /**
351 354 * Filter whether the current user can see a given trashed item.
@@ -352,9 +355,9 @@
352 355 *
353 356 * @param bool $can Default: edit_post capability check.
354 357 * @param WP_Post $post Trashed post.
355 358 */
356 - 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 );
357 360 }
358 361
359 362 /**
360 363 * Whether the current user can restore a given trashed item.
@@ -361,9 +364,9 @@
361 364 *
362 365 * @param WP_Post $post Trashed post.
363 366 * @return bool
364 367 */
365 -function desktop_mode_recycle_bin_user_can_restore( $post ) {
368 +function openstation_recycle_bin_user_can_restore( $post ) {
366 369 $can = current_user_can( 'delete_post', $post->ID );
367 370
368 371 /**
369 372 * Filter whether the current user can restore a given trashed item.
@@ -371,9 +374,9 @@
371 374 * @param bool $can Default: delete_post capability check (the same
372 375 * gate WP itself uses for trash/untrash).
373 376 * @param WP_Post $post Trashed post.
374 377 */
375 - 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 );
376 379 }
377 380
378 381 /**
379 382 * Whether the current user can permanently delete a trashed item.
@@ -380,9 +383,9 @@
380 383 *
381 384 * @param WP_Post $post Trashed post.
382 385 * @return bool
383 386 */
384 -function desktop_mode_recycle_bin_user_can_purge( $post ) {
387 +function openstation_recycle_bin_user_can_purge( $post ) {
385 388 $can = current_user_can( 'delete_post', $post->ID );
386 389
387 390 /**
388 391 * Filter whether the current user can permanently delete a trashed item.
@@ -389,9 +392,9 @@
389 392 *
390 393 * @param bool $can Default: delete_post capability check.
391 394 * @param WP_Post $post Trashed post.
392 395 */
393 - 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 );
394 397 }
395 398
396 399 /**
397 400 * Capability gates for trashed comments. Mirror of the post gates,
@@ -399,9 +402,9 @@
399 402 *
400 403 * @param WP_Comment $comment Trashed comment.
401 404 * @return bool
402 405 */
403 -function desktop_mode_recycle_bin_user_can_view_comment( $comment ) {
406 +function openstation_recycle_bin_user_can_view_comment( $comment ) {
404 407 $can = current_user_can( 'edit_comment', $comment->comment_ID );
405 408
406 409 /**
407 410 * @param bool $can Default: edit_comment capability check.
@@ -406,9 +409,9 @@
406 409 /**
407 410 * @param bool $can Default: edit_comment capability check.
408 411 * @param WP_Comment $comment Trashed comment.
409 412 */
410 - 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 );
411 414 }
412 415
413 416 /**
414 417 * @param WP_Comment $comment Trashed comment.
@@ -413,9 +416,9 @@
413 416 /**
414 417 * @param WP_Comment $comment Trashed comment.
415 418 * @return bool
416 419 */
417 -function desktop_mode_recycle_bin_user_can_restore_comment( $comment ) {
420 +function openstation_recycle_bin_user_can_restore_comment( $comment ) {
418 421 $can = current_user_can( 'edit_comment', $comment->comment_ID );
419 422
420 423 /**
421 424 * @param bool $can Default: edit_comment capability check.
@@ -420,9 +423,9 @@
420 423 /**
421 424 * @param bool $can Default: edit_comment capability check.
422 425 * @param WP_Comment $comment Trashed comment.
423 426 */
424 - 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 );
425 428 }
426 429
427 430 /**
428 431 * @param WP_Comment $comment Trashed comment.
@@ -427,9 +430,9 @@
427 430 /**
428 431 * @param WP_Comment $comment Trashed comment.
429 432 * @return bool
430 433 */
431 -function desktop_mode_recycle_bin_user_can_purge_comment( $comment ) {
434 +function openstation_recycle_bin_user_can_purge_comment( $comment ) {
432 435 $can = current_user_can( 'edit_comment', $comment->comment_ID );
433 436
434 437 /**
435 438 * @param bool $can Default: edit_comment capability check.
@@ -434,9 +437,9 @@
434 437 /**
435 438 * @param bool $can Default: edit_comment capability check.
436 439 * @param WP_Comment $comment Trashed comment.
437 440 */
438 - 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 );
439 442 }
440 443
441 444 /**
442 445 * Shape a `WP_Comment` into the JSON the JS table consumes.
@@ -448,9 +451,9 @@
448 451 *
449 452 * @param WP_Comment $comment Trashed comment.
450 453 * @return array
451 454 */
452 -function desktop_mode_recycle_bin_shape_comment_item( $comment ) {
455 +function openstation_recycle_bin_shape_comment_item( $comment ) {
453 456 $user_id = (int) get_comment_meta( $comment->comment_ID, '_desktop_mode_trash_user_id', true );
454 457 $deleted_at = (string) get_comment_meta( $comment->comment_ID, '_desktop_mode_trash_time_gmt', true );
455 458
456 459 if ( '' === $deleted_at ) {
@@ -457,9 +460,9 @@
457 460 $deleted_at = (string) $comment->comment_date_gmt;
458 461 }
459 462
460 463 $parent = $comment->comment_post_ID ? get_post( (int) $comment->comment_post_ID ) : null;
461 - $parent_text = $parent ? desktop_mode_recycle_bin_plain_text( get_the_title( $parent ) ) : '';
464 + $parent_text = $parent ? openstation_recycle_bin_plain_text( get_the_title( $parent ) ) : '';
462 465 $author = $comment->comment_author
463 466 ? (string) $comment->comment_author
464 467 : __( 'Anonymous', 'desktop-mode' );
465 468
@@ -471,9 +474,9 @@
471 474 $parent_text
472 475 )
473 476 : $author;
474 477
475 - $subtitle = wp_trim_words( desktop_mode_recycle_bin_plain_text( (string) $comment->comment_content ), 18, '…' );
478 + $subtitle = openstation_recycle_bin_excerpt( (string) $comment->comment_content );
476 479
477 480 $user = $user_id ? get_userdata( $user_id ) : false;
478 481 $user_name = $user ? $user->display_name : '';
479 482
@@ -488,10 +491,10 @@
488 491 'icon' => 'dashicons-admin-comments',
489 492 'deleted_at' => $deleted_at,
490 493 'deleted_by' => $user_name,
491 494 'deleted_by_id' => $user_id,
492 - 'can_restore' => desktop_mode_recycle_bin_user_can_restore_comment( $comment ),
493 - '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 ),
494 497 'edit_link' => (string) get_edit_comment_link( $comment->comment_ID ),
495 498 );
496 499
497 500 /**
@@ -499,9 +502,9 @@
499 502 *
500 503 * @param array $item Item shape.
501 504 * @param WP_Comment $comment Source comment.
502 505 */
503 - return (array) apply_filters( 'desktop_mode_recycle_bin_comment_item', $item, $comment );
506 + return (array) apply_filters( 'openstation_recycle_bin_comment_item', $item, $comment );
504 507 }
505 508
506 509 /**
507 510 * Collapse a title/subtitle to plain text for the wire.
@@ -515,11 +518,11 @@
515 518 *
516 519 * @param string $text Raw filtered text.
517 520 * @return string
518 521 */
519 -function desktop_mode_recycle_bin_plain_text( $text ) {
522 +function openstation_recycle_bin_plain_text( $text ) {
520 523 return html_entity_decode(
521 - wp_strip_all_tags( (string) $text ),
524 + openstation_strip_all_tags( $text ),
522 525 ENT_QUOTES,
523 526 get_bloginfo( 'charset' )
524 527 );
525 528 }
@@ -524,14 +527,31 @@
524 527 );
525 528 }
526 529
527 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 +/**
528 548 * Shape one WP_Post into the JSON the JS table consumes.
529 549 *
530 550 * @param WP_Post $post Trashed post.
531 551 * @return array
532 552 */
533 -function desktop_mode_recycle_bin_shape_item( $post ) {
553 +function openstation_recycle_bin_shape_item( $post ) {
534 554 $user_id = (int) get_post_meta( $post->ID, '_desktop_mode_trash_user_id', true );
535 555 $deleted_at = (string) get_post_meta( $post->ID, '_desktop_mode_trash_time_gmt', true );
536 556
537 557 // Fall back to post_modified_gmt — set when wp_trash_post runs and
@@ -540,9 +560,9 @@
540 560 $deleted_at = (string) $post->post_modified_gmt;
541 561 }
542 562
543 563 $type = (string) $post->post_type;
544 - $title = desktop_mode_recycle_bin_plain_text( (string) get_the_title( $post ) );
564 + $title = openstation_recycle_bin_plain_text( (string) get_the_title( $post ) );
545 565 $mime = (string) $post->post_mime_type;
546 566 $preview = '';
547 567 $icon = '';
548 568 $subtitle = '';
@@ -554,16 +574,17 @@
554 574 $thumb = wp_get_attachment_image_src( $post->ID, array( 64, 64 ), true );
555 575 if ( is_array( $thumb ) ) {
556 576 $preview = (string) $thumb[0];
557 577 }
558 - $icon = desktop_mode_recycle_bin_icon_for_mime( $mime );
578 + $icon = openstation_recycle_bin_icon_for_mime( $mime );
559 579 $subtitle = $mime;
560 580 } elseif ( 'post' === $type ) {
561 581 $icon = 'dashicons-admin-post';
562 - $subtitle = wp_trim_words( desktop_mode_recycle_bin_plain_text( (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 );
563 584 } elseif ( 'page' === $type ) {
564 585 $icon = 'dashicons-admin-page';
565 - $subtitle = wp_trim_words( desktop_mode_recycle_bin_plain_text( (string) $post->post_content ), 18, '…' );
586 + $subtitle = openstation_recycle_bin_excerpt( (string) $post->post_content );
566 587 } else {
567 588 // Custom post types: reuse the type's own menu Dashicon when it
568 589 // registered one, so a trashed product row reads as a product
569 590 // instead of a generic file. Content excerpt as the subtitle,
@@ -576,9 +597,10 @@
576 597 && str_starts_with( $post_type_obj->menu_icon, 'dashicons-' )
577 598 ) {
578 599 $icon = $post_type_obj->menu_icon;
579 600 }
580 - $subtitle = wp_trim_words( desktop_mode_recycle_bin_plain_text( (string) $post->post_excerpt ?: (string) $post->post_content ), 18, '…' );
601 + $excerpt = (string) $post->post_excerpt;
602 + $subtitle = openstation_recycle_bin_excerpt( $excerpt ? $excerpt : (string) $post->post_content );
581 603 }
582 604
583 605 $user = $user_id ? get_userdata( $user_id ) : false;
584 606 $user_name = $user ? $user->display_name : '';
@@ -610,10 +632,10 @@
610 632 'icon' => $icon,
611 633 'deleted_at' => $deleted_at,
612 634 'deleted_by' => $user_name,
613 635 'deleted_by_id' => $user_id,
614 - 'can_restore' => desktop_mode_recycle_bin_user_can_restore( $post ),
615 - '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 ),
616 638 'edit_link' => (string) get_edit_post_link( $post->ID, 'raw' ),
617 639 );
618 640
619 641 /**
@@ -625,9 +647,9 @@
625 647 *
626 648 * @param array $item Item shape.
627 649 * @param WP_Post $post Source post.
628 650 */
629 - return (array) apply_filters( 'desktop_mode_recycle_bin_item', $item, $post );
651 + return (array) apply_filters( 'openstation_recycle_bin_item', $item, $post );
630 652 }
631 653
632 654 /**
633 655 * Map a mime type to a Dashicon for the type cell.
@@ -634,9 +656,9 @@
634 656 *
635 657 * @param string $mime Mime type.
636 658 * @return string Dashicon class.
637 659 */
638 -function desktop_mode_recycle_bin_icon_for_mime( $mime ) {
660 +function openstation_recycle_bin_icon_for_mime( $mime ) {
639 661 if ( '' === $mime ) {
640 662 return 'dashicons-media-default';
641 663 }
642 664 if ( str_starts_with( $mime, 'image/' ) ) {
@@ -683,29 +705,29 @@
683 705 * @param int $id Post id (or comment id when `$type === 'comment'`).
684 706 * @param string $type Entity type — '', 'post', 'page', 'attachment', or 'comment'.
685 707 * @return true|WP_Error
686 708 */
687 -function desktop_mode_recycle_bin_restore( $id, $type = '' ) {
709 +function openstation_recycle_bin_restore( $id, $type = '' ) {
688 710 $id = (int) $id;
689 711 if ( 'comment' === $type ) {
690 - return desktop_mode_recycle_bin_restore_comment( $id );
712 + return openstation_recycle_bin_restore_comment( $id );
691 713 }
692 - if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'desktop_mode_files_restore_placement' ) ) {
693 - 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 );
694 716 }
695 - if ( 'folder' === $type && function_exists( 'desktop_mode_files_restore_folder' ) ) {
696 - 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 );
697 719 }
698 720
699 721 $post = get_post( $id );
700 722 if ( ! $post ) {
701 - 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 ) );
702 724 }
703 725 if ( 'trash' !== $post->post_status ) {
704 - 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 ) );
705 727 }
706 - if ( ! desktop_mode_recycle_bin_user_can_restore( $post ) ) {
707 - 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 ) );
708 730 }
709 731
710 732 /**
711 733 * Fires before a recycle-bin item is restored.
@@ -712,13 +734,13 @@
712 734 *
713 735 * @param int $id Post id about to be restored.
714 736 * @param WP_Post $post Trashed post object.
715 737 */
716 - do_action( 'desktop_mode_recycle_bin_before_restore', $id, $post );
738 + do_action( 'openstation_recycle_bin_before_restore', $id, $post );
717 739
718 740 $ok = wp_untrash_post( $id );
719 741 if ( ! $ok ) {
720 - 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 ) );
721 743 }
722 744
723 745 delete_post_meta( $id, '_desktop_mode_trash_user_id' );
724 746 delete_post_meta( $id, '_desktop_mode_trash_time_gmt' );
@@ -727,9 +749,9 @@
727 749 * Fires after a recycle-bin item is restored.
728 750 *
729 751 * @param int $id Post id that was restored.
730 752 */
731 - do_action( 'desktop_mode_recycle_bin_after_restore', $id );
753 + do_action( 'openstation_recycle_bin_after_restore', $id );
732 754
733 755 return true;
734 756 }
735 757
@@ -738,20 +760,20 @@
738 760 *
739 761 * @param int $comment_id Comment id.
740 762 * @return true|WP_Error
741 763 */
742 -function desktop_mode_recycle_bin_restore_comment( $comment_id ) {
764 +function openstation_recycle_bin_restore_comment( $comment_id ) {
743 765 $comment_id = (int) $comment_id;
744 766 $comment = get_comment( $comment_id );
745 767
746 768 if ( ! $comment ) {
747 - 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 ) );
748 770 }
749 771 if ( 'trash' !== $comment->comment_approved ) {
750 - 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 ) );
751 773 }
752 - if ( ! desktop_mode_recycle_bin_user_can_restore_comment( $comment ) ) {
753 - 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 ) );
754 776 }
755 777
756 778 /**
757 779 * Fires before a comment is restored from the recycle bin.
@@ -758,13 +780,13 @@
758 780 *
759 781 * @param int $comment_id Comment id.
760 782 * @param WP_Comment $comment Trashed comment.
761 783 */
762 - do_action( 'desktop_mode_recycle_bin_before_restore_comment', $comment_id, $comment );
784 + do_action( 'openstation_recycle_bin_before_restore_comment', $comment_id, $comment );
763 785
764 786 $ok = wp_untrash_comment( $comment_id );
765 787 if ( ! $ok ) {
766 - 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 ) );
767 789 }
768 790
769 791 delete_comment_meta( $comment_id, '_desktop_mode_trash_user_id' );
770 792 delete_comment_meta( $comment_id, '_desktop_mode_trash_time_gmt' );
@@ -773,9 +795,9 @@
773 795 * Fires after a comment is restored from the recycle bin.
774 796 *
775 797 * @param int $comment_id Comment id.
776 798 */
777 - do_action( 'desktop_mode_recycle_bin_after_restore_comment', $comment_id );
799 + do_action( 'openstation_recycle_bin_after_restore_comment', $comment_id );
778 800
779 801 return true;
780 802 }
781 803
@@ -785,29 +807,29 @@
785 807 * @param int $id Post id (or comment id when `$type === 'comment'`).
786 808 * @param string $type Entity type — '', 'post', 'page', 'attachment', or 'comment'.
787 809 * @return true|WP_Error
788 810 */
789 -function desktop_mode_recycle_bin_purge( $id, $type = '' ) {
811 +function openstation_recycle_bin_purge( $id, $type = '' ) {
790 812 $id = (int) $id;
791 813 if ( 'comment' === $type ) {
792 - return desktop_mode_recycle_bin_purge_comment( $id );
814 + return openstation_recycle_bin_purge_comment( $id );
793 815 }
794 - if ( ( 'placement' === $type || 'shortcut' === $type ) && function_exists( 'desktop_mode_files_purge_placement' ) ) {
795 - 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 );
796 818 }
797 - if ( 'folder' === $type && function_exists( 'desktop_mode_files_purge_folder' ) ) {
798 - 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 );
799 821 }
800 822
801 823 $post = get_post( $id );
802 824 if ( ! $post ) {
803 - 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 ) );
804 826 }
805 827 if ( 'trash' !== $post->post_status ) {
806 - 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 ) );
807 829 }
808 - if ( ! desktop_mode_recycle_bin_user_can_purge( $post ) ) {
809 - 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 ) );
810 832 }
811 833
812 834 /**
813 835 * Fires before a recycle-bin item is permanently deleted.
@@ -814,9 +836,9 @@
814 836 *
815 837 * @param int $id Post id about to be deleted.
816 838 * @param WP_Post $post Trashed post object.
817 839 */
818 - do_action( 'desktop_mode_recycle_bin_before_purge', $id, $post );
840 + do_action( 'openstation_recycle_bin_before_purge', $id, $post );
819 841
820 842 if ( 'attachment' === $post->post_type ) {
821 843 // Force-delete (`true`) removes the attachment and its file
822 844 // permanently. (The item is already trashed, so even with
@@ -827,9 +849,9 @@
827 849 $result = wp_delete_post( $id, true );
828 850 }
829 851
830 852 if ( ! $result ) {
831 - 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 ) );
832 854 }
833 855
834 856 /**
835 857 * Fires after a recycle-bin item is permanently deleted.
@@ -836,9 +858,9 @@
836 858 *
837 859 * @param int $id Post id that was purged.
838 860 * @param string $type Post type of the purged item.
839 861 */
840 - do_action( 'desktop_mode_recycle_bin_after_purge', $id, $post->post_type );
862 + do_action( 'openstation_recycle_bin_after_purge', $id, $post->post_type );
841 863
842 864 return true;
843 865 }
844 866
@@ -847,20 +869,20 @@
847 869 *
848 870 * @param int $comment_id Comment id.
849 871 * @return true|WP_Error
850 872 */
851 -function desktop_mode_recycle_bin_purge_comment( $comment_id ) {
873 +function openstation_recycle_bin_purge_comment( $comment_id ) {
852 874 $comment_id = (int) $comment_id;
853 875 $comment = get_comment( $comment_id );
854 876
855 877 if ( ! $comment ) {
856 - 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 ) );
857 879 }
858 880 if ( 'trash' !== $comment->comment_approved ) {
859 - 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 ) );
860 882 }
861 - if ( ! desktop_mode_recycle_bin_user_can_purge_comment( $comment ) ) {
862 - 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 ) );
863 885 }
864 886
865 887 /**
866 888 * Fires before a comment is permanently deleted via the bin.
@@ -867,14 +889,14 @@
867 889 *
868 890 * @param int $comment_id Comment id.
869 891 * @param WP_Comment $comment Trashed comment.
870 892 */
871 - do_action( 'desktop_mode_recycle_bin_before_purge_comment', $comment_id, $comment );
893 + do_action( 'openstation_recycle_bin_before_purge_comment', $comment_id, $comment );
872 894
873 895 $result = wp_delete_comment( $comment_id, true );
874 896
875 897 if ( ! $result ) {
876 - 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 ) );
877 899 }
878 900
879 901 /**
880 902 * Fires after a comment is permanently deleted via the bin.
@@ -880,9 +902,9 @@
880 902 * Fires after a comment is permanently deleted via the bin.
881 903 *
882 904 * @param int $comment_id Comment id.
883 905 */
884 - do_action( 'desktop_mode_recycle_bin_after_purge_comment', $comment_id );
906 + do_action( 'openstation_recycle_bin_after_purge_comment', $comment_id );
885 907
886 908 return true;
887 909 }
888 910
@@ -895,9 +917,9 @@
895 917 * Processes at most one chunk per call. The cap protects against PHP
896 918 * timeouts on large bins; the client iterates while `remaining > 0`
897 919 * (and bails when `remaining === skipped`, i.e. nothing the user can
898 920 * purge is left). Site owners with longer execution budgets can tune
899 - * the chunk size via the `desktop_mode_recycle_bin_empty_chunk_size`
921 + * the chunk size via the `openstation_recycle_bin_empty_chunk_size`
900 922 * filter.
901 923 *
902 924 * @return array {
903 925 * @type int $purged Items successfully purged in this call.
@@ -904,9 +926,9 @@
904 926 * @type int $skipped Items skipped (capability or error).
905 927 * @type int $remaining Items still in the bin after this call (across pages).
906 928 * }
907 929 */
908 -function desktop_mode_recycle_bin_empty() {
930 +function openstation_recycle_bin_empty() {
909 931 $purged = 0;
910 932 $skipped = 0;
911 933
912 934 /**
@@ -911,9 +933,9 @@
911 933
912 934 /**
913 935 * Filter the per-call chunk size for the empty-bin loop.
914 936 *
915 - * `desktop_mode_recycle_bin_empty()` only purges this many items
937 + * `openstation_recycle_bin_empty()` only purges this many items
916 938 * per invocation. The client iterates while `remaining > 0`. The
917 939 * default (200) is conservative for shared hosts; sites with
918 940 * generous PHP execution limits can raise it to make emptying a
919 941 * large bin take fewer roundtrips.
@@ -919,9 +941,9 @@
919 941 * large bin take fewer roundtrips.
920 942 *
921 943 * @param int $chunk_size Items processed per call. Default 200.
922 944 */
923 - $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 );
924 946 if ( $chunk_size < 1 ) {
925 947 $chunk_size = 1;
926 948 }
927 949
@@ -928,11 +950,16 @@
928 950 // Loop in chunks — `wp_delete_post()` is cheap individually but
929 951 // hammering it on a 10k-item bin without yielding back to PHP can
930 952 // still time out. The client re-invokes us until `remaining` hits
931 953 // zero (or stalls at `skipped`).
932 - $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 + );
933 960 foreach ( $batch['items'] as $item ) {
934 - $result = desktop_mode_recycle_bin_purge(
961 + $result = openstation_recycle_bin_purge(
935 962 (int) $item['id'],
936 963 (string) ( $item['type'] ?? '' )
937 964 );
938 965 if ( is_wp_error( $result ) ) {
@@ -947,9 +974,9 @@
947 974 *
948 975 * @param int $purged Items successfully purged in this call.
949 976 * @param int $skipped Items skipped (capability or error).
950 977 */
951 - do_action( 'desktop_mode_recycle_bin_emptied', $purged, $skipped );
978 + do_action( 'openstation_recycle_bin_emptied', $purged, $skipped );
952 979
953 980 return array(
954 981 'purged' => $purged,
955 982 'skipped' => $skipped,