| 1 |
<?php |
| 2 |
/** |
| 3 |
* OpenStation — Pinned notes in the Recycle Bin. |
| 4 |
* |
| 5 |
* `wpd_note` is a headless CPT (`show_ui => false`), so the bin's |
| 6 |
* auto-capture of admin-UI post types skips it — this file opts it in |
| 7 |
* through the bin's existing filter pipeline and adapts the generic |
| 8 |
* post handling to the notes ownership model: |
| 9 |
* |
| 10 |
* - OWNER-ONLY visibility. The bin's default gates use `edit_post` |
| 11 |
* / `delete_post`, which (a) let administrators manage everyone's |
| 12 |
* trashed notes (the live-notes REST controller deliberately does |
| 13 |
* NOT allow that, and a private note's text should not surface in |
| 14 |
* someone else's bin) and (b) lock out subscribers entirely (they |
| 15 |
* hold no `edit_posts`-family caps, yet they own their notes). |
| 16 |
* Both are replaced with a plain `post_author` check. |
| 17 |
* |
| 18 |
* - Badge-count correction. The generic count buckets post types by |
| 19 |
* the viewer's `edit_posts`/`edit_others_posts` caps, which counts |
| 20 |
* other users' notes for editors/admins and zero notes for |
| 21 |
* subscribers — both diverge from what the list shows. The count |
| 22 |
* filter re-scopes the notes contribution to owned-only. |
| 23 |
* |
| 24 |
* - A paper-flavored row: sticky-note icon, "Note" label, and the |
| 25 |
* note text as the subtitle. |
| 26 |
* |
| 27 |
* Restoring from the bin runs `wp_untrash_post()`, so the |
| 28 |
* `wp_untrash_post_status` filter in `cpt.php` brings the note back |
| 29 |
* with its original private/publish status, and the Heartbeat delta |
| 30 |
* re-pins it on the wall without a reload. |
| 31 |
* |
| 32 |
* @package OpenStation |
| 33 |
*/ |
| 34 |
|
| 35 |
defined( 'ABSPATH' ) || exit; |
| 36 |
|
| 37 |
/** |
| 38 |
* Opt `wpd_note` into the recycle bin's capture list. |
| 39 |
* |
| 40 |
* @param string[] $types Tracked post types. |
| 41 |
* @return string[] |
| 42 |
*/ |
| 43 |
function openstation_notes_recycle_bin_capture_types( $types ) { |
| 44 |
$types = (array) $types; |
| 45 |
$types[] = OPENSTATION_NOTES_POST_TYPE; |
| 46 |
return $types; |
| 47 |
} |
| 48 |
add_filter( 'openstation_recycle_bin_capture_post_types', 'openstation_notes_recycle_bin_capture_types' ); |
| 49 |
|
| 50 |
/** |
| 51 |
* Whether a trashed post is a note owned by the current user. |
| 52 |
* |
| 53 |
* @param WP_Post $post Trashed post. |
| 54 |
* @return bool |
| 55 |
*/ |
| 56 |
function openstation_notes_recycle_bin_owns( $post ) { |
| 57 |
return get_current_user_id() === (int) $post->post_author; |
| 58 |
} |
| 59 |
|
| 60 |
/** |
| 61 |
* Owner-only view/restore/purge for notes — replaces the bin's |
| 62 |
* default `edit_post`/`delete_post` gates for this post type. |
| 63 |
* |
| 64 |
* @param bool $can The bin's default answer. |
| 65 |
* @param WP_Post $post Trashed post. |
| 66 |
* @return bool |
| 67 |
*/ |
| 68 |
function openstation_notes_recycle_bin_gate( $can, $post ) { |
| 69 |
if ( OPENSTATION_NOTES_POST_TYPE !== $post->post_type ) { |
| 70 |
return $can; |
| 71 |
} |
| 72 |
return openstation_notes_recycle_bin_owns( $post ); |
| 73 |
} |
| 74 |
add_filter( 'openstation_recycle_bin_user_can_view', 'openstation_notes_recycle_bin_gate', 10, 2 ); |
| 75 |
add_filter( 'openstation_recycle_bin_user_can_restore', 'openstation_notes_recycle_bin_gate', 10, 2 ); |
| 76 |
add_filter( 'openstation_recycle_bin_user_can_purge', 'openstation_notes_recycle_bin_gate', 10, 2 ); |
| 77 |
|
| 78 |
/** |
| 79 |
* Paper-flavored row shape for trashed notes. |
| 80 |
* |
| 81 |
* @param array $item Bin item shape. |
| 82 |
* @param WP_Post $post Source post. |
| 83 |
* @return array |
| 84 |
*/ |
| 85 |
function openstation_notes_recycle_bin_item( $item, $post ) { |
| 86 |
if ( OPENSTATION_NOTES_POST_TYPE !== $post->post_type ) { |
| 87 |
return $item; |
| 88 |
} |
| 89 |
$item['type_label'] = __( 'Note', 'desktop-mode' ); |
| 90 |
$item['icon'] = 'dashicons-sticky'; |
| 91 |
$item['subtitle'] = wp_trim_words( openstation_recycle_bin_plain_text( (string) $post->post_content ), 18, '…' ); |
| 92 |
// Notes have no admin edit screen — a chromeless post.php iframe |
| 93 |
// would 403 on the headless CPT. |
| 94 |
$item['edit_link'] = ''; |
| 95 |
|
| 96 |
// "Deleted by" fallback. The bin's who-deleted stamp is written at |
| 97 |
// trash time, so notes trashed before wpd_note joined the capture |
| 98 |
// list (or trashed with no logged-in user: WP-CLI, cron) have none. |
| 99 |
// For notes the owner is the only principal who can trash, so |
| 100 |
// attributing an unstamped row to the author is correct by |
| 101 |
// construction. Display-time only — nothing is written back. |
| 102 |
if ( '' === (string) $item['deleted_by'] ) { |
| 103 |
$owner = get_userdata( (int) $post->post_author ); |
| 104 |
if ( $owner instanceof WP_User ) { |
| 105 |
$item['deleted_by'] = $owner->display_name; |
| 106 |
$item['deleted_by_id'] = (int) $post->post_author; |
| 107 |
} |
| 108 |
} |
| 109 |
|
| 110 |
return $item; |
| 111 |
} |
| 112 |
add_filter( 'openstation_recycle_bin_item', 'openstation_notes_recycle_bin_item', 10, 2 ); |
| 113 |
|
| 114 |
/** |
| 115 |
* Number of trashed notes for a given scope. |
| 116 |
* |
| 117 |
* @param int|null $author_id Scope to one author, or null for all. |
| 118 |
* @return int |
| 119 |
*/ |
| 120 |
function openstation_notes_recycle_bin_trashed_count( $author_id = null ) { |
| 121 |
$args = array( |
| 122 |
'post_type' => OPENSTATION_NOTES_POST_TYPE, |
| 123 |
'post_status' => 'trash', |
| 124 |
'posts_per_page' => 1, |
| 125 |
'fields' => 'ids', |
| 126 |
'no_found_rows' => false, |
| 127 |
); |
| 128 |
if ( null !== $author_id ) { |
| 129 |
$args['author'] = (int) $author_id; |
| 130 |
} |
| 131 |
$query = new WP_Query( $args ); |
| 132 |
return (int) $query->found_posts; |
| 133 |
} |
| 134 |
|
| 135 |
/** |
| 136 |
* Re-scope the badge count's notes contribution to owned-only, so |
| 137 |
* the badge always matches what the (owner-gated) list shows. |
| 138 |
* |
| 139 |
* The generic count already included: ALL trashed notes for users |
| 140 |
* holding `edit_others_posts`, OWN trashed notes for `edit_posts` |
| 141 |
* holders, and none for anyone else. Normalize every case to "own |
| 142 |
* trashed notes". |
| 143 |
* |
| 144 |
* @param int $total Generic total. |
| 145 |
* @return int |
| 146 |
*/ |
| 147 |
function openstation_notes_recycle_bin_count( $total ) { |
| 148 |
$total = (int) $total; |
| 149 |
$own = openstation_notes_recycle_bin_trashed_count( get_current_user_id() ); |
| 150 |
|
| 151 |
if ( current_user_can( 'edit_others_posts' ) ) { |
| 152 |
// Counted everyone's notes; keep only ours. |
| 153 |
$total = $total - openstation_notes_recycle_bin_trashed_count() + $own; |
| 154 |
} elseif ( ! current_user_can( 'edit_posts' ) ) { |
| 155 |
// Counted none of ours; add them. |
| 156 |
$total = $total + $own; |
| 157 |
} |
| 158 |
// `edit_posts`-only users were already counted author-scoped. |
| 159 |
|
| 160 |
return max( 0, $total ); |
| 161 |
} |
| 162 |
add_filter( 'openstation_recycle_bin_count', 'openstation_notes_recycle_bin_count' ); |
| 163 |
|