PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.8.7
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.8.7
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / content-graph / rest.php

rest.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.8.7, at includes/content-graph/rest.php

383 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Content Graph: REST routes.
4 *
5 * Three endpoints under `desktop-mode/v1/content-graph`:
6 *
7 * GET /post-types
8 * Lists the types eligible for the graph (`slug`, `label`, `icon`,
9 * `count`).
10 *
11 * GET /nodes?types=post,page,...
12 * Returns the full `{ nodes, edges, stats }` tuple. Cached server-
13 * side, see graph-builder.php.
14 *
15 * GET /post/<id>
16 * Returns the side-panel detail bundle for one post:
17 * { post: {...}, author, contributors, comments, categories,
18 * attached_media, revisions }.
19 *
20 * @package WPDesktopMode
21 * @since 0.8.2
22 */
23
24 defined( 'ABSPATH' ) || exit;
25
26 /**
27 * Capability check shared across every endpoint.
28 *
29 * @since 0.8.2
30 *
31 * @return bool
32 */
33 function desktop_mode_content_graph_rest_permission() {
34 return desktop_mode_content_graph_user_can_use();
35 }
36
37 /**
38 * Register the routes.
39 *
40 * @since 0.8.2
41 */
42 function desktop_mode_content_graph_register_routes() {
43 register_rest_route(
44 'desktop-mode/v1',
45 '/content-graph/post-types',
46 array(
47 'methods' => WP_REST_Server::READABLE,
48 'callback' => 'desktop_mode_content_graph_rest_post_types',
49 'permission_callback' => 'desktop_mode_content_graph_rest_permission',
50 )
51 );
52 register_rest_route(
53 'desktop-mode/v1',
54 '/content-graph/nodes',
55 array(
56 'methods' => WP_REST_Server::READABLE,
57 'callback' => 'desktop_mode_content_graph_rest_nodes',
58 'permission_callback' => 'desktop_mode_content_graph_rest_permission',
59 'args' => array(
60 'types' => array(
61 'description' => 'Comma-separated list of post type slugs to include.',
62 'type' => 'string',
63 'default' => '',
64 ),
65 ),
66 )
67 );
68 register_rest_route(
69 'desktop-mode/v1',
70 '/content-graph/post/(?P<id>\d+)',
71 array(
72 'methods' => WP_REST_Server::READABLE,
73 'callback' => 'desktop_mode_content_graph_rest_post_detail',
74 'permission_callback' => 'desktop_mode_content_graph_rest_permission',
75 'args' => array(
76 'id' => array(
77 'type' => 'integer',
78 'required' => true,
79 ),
80 ),
81 )
82 );
83 }
84 add_action( 'rest_api_init', 'desktop_mode_content_graph_register_routes' );
85
86 /**
87 * GET /post-types
88 *
89 * @since 0.8.2
90 *
91 * @return WP_REST_Response
92 */
93 function desktop_mode_content_graph_rest_post_types() {
94 $types = desktop_mode_content_graph_post_types();
95 $out = array();
96 foreach ( $types as $entry ) {
97 $slug = isset( $entry['slug'] ) ? (string) $entry['slug'] : '';
98 $counts = $slug ? wp_count_posts( $slug ) : null;
99 $count = 0;
100 if ( $counts && isset( $counts->publish ) ) {
101 $count = (int) $counts->publish;
102 if ( isset( $counts->private ) ) {
103 $count += (int) $counts->private;
104 }
105 }
106 $out[] = array(
107 'slug' => $slug,
108 'label' => isset( $entry['label'] ) ? (string) $entry['label'] : $slug,
109 'icon' => isset( $entry['icon'] ) ? (string) $entry['icon'] : 'dashicons-admin-post',
110 'count' => $count,
111 );
112 }
113 return rest_ensure_response( $out );
114 }
115
116 /**
117 * GET /nodes
118 *
119 * @since 0.8.2
120 *
121 * @param WP_REST_Request $request
122 * @return WP_REST_Response
123 */
124 function desktop_mode_content_graph_rest_nodes( WP_REST_Request $request ) {
125 $raw = (string) $request->get_param( 'types' );
126 $types = '' === $raw
127 ? wp_list_pluck( desktop_mode_content_graph_post_types(), 'slug' )
128 : array_map( 'trim', explode( ',', $raw ) );
129 return rest_ensure_response( desktop_mode_content_graph_build( (array) $types ) );
130 }
131
132 /**
133 * GET /post/<id>
134 *
135 * @since 0.8.2
136 *
137 * @param WP_REST_Request $request
138 * @return WP_REST_Response|WP_Error
139 */
140 function desktop_mode_content_graph_rest_post_detail( WP_REST_Request $request ) {
141 $id = (int) $request['id'];
142 $post = $id > 0 ? get_post( $id ) : null;
143 if ( ! $post ) {
144 return new WP_Error(
145 'desktop_mode_content_graph_post_not_found',
146 __( 'Post not found.', 'desktop-mode' ),
147 array( 'status' => 404 )
148 );
149 }
150 if ( ! current_user_can( 'read_post', $id ) ) {
151 return new WP_Error(
152 'desktop_mode_content_graph_forbidden',
153 __( 'Insufficient permissions.', 'desktop-mode' ),
154 array( 'status' => 403 )
155 );
156 }
157
158 $author = desktop_mode_content_graph_format_user( (int) $post->post_author );
159 $contributors = desktop_mode_content_graph_collect_contributors( $post );
160 $comments = desktop_mode_content_graph_collect_comments( $post );
161 $categories = desktop_mode_content_graph_collect_terms( $post );
162 $attached = desktop_mode_content_graph_collect_attached_media( $post );
163 $revisions = desktop_mode_content_graph_collect_revisions( $post );
164
165 return rest_ensure_response(
166 array(
167 'post' => array(
168 'id' => (int) $post->ID,
169 'type' => $post->post_type,
170 'title' => get_the_title( $post ),
171 'status' => $post->post_status,
172 'slug' => $post->post_name,
173 'edit_url' => (string) get_edit_post_link( $post->ID, 'raw' ),
174 'view_url' => (string) get_permalink( $post ),
175 'date' => mysql2date( 'c', $post->post_date_gmt, false ),
176 'modified' => mysql2date( 'c', $post->post_modified_gmt, false ),
177 ),
178 'author' => $author,
179 'contributors' => $contributors,
180 'comments' => $comments,
181 'categories' => $categories,
182 'attached_media' => $attached,
183 'revisions' => $revisions,
184 )
185 );
186 }
187
188 /**
189 * Format a user record for the side panel.
190 *
191 * @since 0.8.2
192 *
193 * @param int $user_id
194 * @return array|null
195 */
196 function desktop_mode_content_graph_format_user( $user_id ) {
197 $user_id = (int) $user_id;
198 if ( $user_id <= 0 ) {
199 return null;
200 }
201 $user = get_userdata( $user_id );
202 if ( ! $user ) {
203 return null;
204 }
205 return array(
206 'id' => $user_id,
207 'name' => (string) $user->display_name,
208 'slug' => (string) $user->user_nicename,
209 'avatar' => (string) get_avatar_url( $user_id, array( 'size' => 64 ) ),
210 'edit_url' => (string) get_edit_user_link( $user_id ),
211 );
212 }
213
214 /**
215 * Collect contributors: distinct revision authors (excluding the
216 * current author) plus distinct comment authors who have a
217 * registered user account.
218 *
219 * @since 0.8.2
220 *
221 * @param WP_Post $post
222 * @return array[]
223 */
224 function desktop_mode_content_graph_collect_contributors( WP_Post $post ) {
225 $author_id = (int) $post->post_author;
226 $ids = array();
227 $revs = wp_get_post_revisions(
228 $post->ID,
229 array(
230 'posts_per_page' => 100,
231 'fields' => 'ids',
232 )
233 );
234 foreach ( (array) $revs as $rev_id ) {
235 $rev = get_post( $rev_id );
236 if ( $rev && (int) $rev->post_author > 0 && (int) $rev->post_author !== $author_id ) {
237 $ids[ (int) $rev->post_author ] = true;
238 }
239 }
240 $comment_users = get_comments(
241 array(
242 'post_id' => $post->ID,
243 'status' => 'approve',
244 'fields' => 'ids',
245 )
246 );
247 foreach ( (array) $comment_users as $cid ) {
248 $comment = get_comment( $cid );
249 if ( $comment && (int) $comment->user_id > 0 && (int) $comment->user_id !== $author_id ) {
250 $ids[ (int) $comment->user_id ] = true;
251 }
252 }
253 $out = array();
254 foreach ( array_keys( $ids ) as $uid ) {
255 $entry = desktop_mode_content_graph_format_user( $uid );
256 if ( $entry ) {
257 $out[] = $entry;
258 }
259 }
260 return $out;
261 }
262
263 /**
264 * Collect approved comments (most recent first, capped at 50).
265 *
266 * @since 0.8.2
267 *
268 * @param WP_Post $post
269 * @return array[]
270 */
271 function desktop_mode_content_graph_collect_comments( WP_Post $post ) {
272 $comments = get_comments(
273 array(
274 'post_id' => $post->ID,
275 'status' => 'approve',
276 'number' => 50,
277 'orderby' => 'comment_date_gmt',
278 'order' => 'DESC',
279 )
280 );
281 $out = array();
282 foreach ( $comments as $comment ) {
283 $out[] = array(
284 'id' => (int) $comment->comment_ID,
285 'author' => (string) $comment->comment_author,
286 'user_id' => (int) $comment->user_id,
287 'date' => mysql2date( 'c', $comment->comment_date_gmt, false ),
288 'excerpt' => wp_html_excerpt( wp_strip_all_tags( (string) $comment->comment_content ), 140, '...' ),
289 'edit_url' => (string) admin_url( 'comment.php?action=editcomment&c=' . (int) $comment->comment_ID ),
290 );
291 }
292 return $out;
293 }
294
295 /**
296 * Collect every taxonomy term attached to the post (categories, tags,
297 * and any custom taxonomy registered for the post type).
298 *
299 * @since 0.8.2
300 *
301 * @param WP_Post $post
302 * @return array[]
303 */
304 function desktop_mode_content_graph_collect_terms( WP_Post $post ) {
305 $taxes = get_object_taxonomies( $post->post_type, 'objects' );
306 $out = array();
307 foreach ( $taxes as $tax ) {
308 if ( ! $tax->public && ! $tax->show_ui ) {
309 continue;
310 }
311 $terms = get_the_terms( $post, $tax->name );
312 if ( empty( $terms ) || is_wp_error( $terms ) ) {
313 continue;
314 }
315 foreach ( $terms as $term ) {
316 $out[] = array(
317 'id' => (int) $term->term_id,
318 'name' => (string) $term->name,
319 'slug' => (string) $term->slug,
320 'taxonomy' => (string) $term->taxonomy,
321 'tax_label' => (string) $tax->labels->singular_name,
322 'count' => (int) $term->count,
323 'edit_url' => (string) get_edit_term_link( $term->term_id, $term->taxonomy ),
324 );
325 }
326 }
327 return $out;
328 }
329
330 /**
331 * Collect attached media (anything with this post as its `post_parent`)
332 * plus any media referenced from a `wp:image` block. Returns up to 50.
333 *
334 * @since 0.8.2
335 *
336 * @param WP_Post $post
337 * @return array[]
338 */
339 function desktop_mode_content_graph_collect_attached_media( WP_Post $post ) {
340 $attachments = get_attached_media( '', $post );
341 $out = array();
342 foreach ( $attachments as $att ) {
343 $out[] = array(
344 'id' => (int) $att->ID,
345 'title' => (string) get_the_title( $att ),
346 'mime' => (string) $att->post_mime_type,
347 'thumb' => (string) wp_get_attachment_image_url( $att->ID, 'thumbnail' ),
348 'edit_url' => (string) get_edit_post_link( $att->ID, 'raw' ),
349 );
350 if ( count( $out ) >= 50 ) {
351 break;
352 }
353 }
354 return $out;
355 }
356
357 /**
358 * Collect post revisions (most recent first, capped at 30).
359 *
360 * @since 0.8.2
361 *
362 * @param WP_Post $post
363 * @return array[]
364 */
365 function desktop_mode_content_graph_collect_revisions( WP_Post $post ) {
366 $revs = wp_get_post_revisions(
367 $post->ID,
368 array(
369 'posts_per_page' => 30,
370 )
371 );
372 $out = array();
373 foreach ( $revs as $rev ) {
374 $out[] = array(
375 'id' => (int) $rev->ID,
376 'date' => mysql2date( 'c', $rev->post_date_gmt, false ),
377 'author' => desktop_mode_content_graph_format_user( (int) $rev->post_author ),
378 'edit_url' => (string) admin_url( 'revision.php?revision=' . (int) $rev->ID ),
379 );
380 }
381 return $out;
382 }
383