PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.7
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.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 / my-wordpress / comment-stats.php

comment-stats.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.7, at includes/my-wordpress/comment-stats.php

266 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — My WordPress: per-comment dossier endpoint.
4 *
5 * `GET /desktop-mode/v1/comment-stats/<id>` returns the rendered
6 * comment + author + parent post + thread context + reply tree +
7 * a count of how active the author has been across the site. Powers
8 * the right preview pane in the My WordPress folder when a comment
9 * is selected.
10 *
11 * Permissions:
12 * - The comment must be readable by the current user (approved,
13 * OR the user can `moderate_comments`, OR they're the comment
14 * author).
15 * - Author email / IP / user-agent only ship to viewers with
16 * `moderate_comments`.
17 *
18 * @package WPDesktopMode
19 * @since 0.8.0
20 */
21
22 defined( 'ABSPATH' ) || exit;
23
24 /**
25 * Register the route.
26 *
27 * @since 0.8.0
28 */
29 function desktop_mode_my_wordpress_register_comment_stats_route() {
30 register_rest_route(
31 'desktop-mode/v1',
32 '/comment-stats/(?P<id>\d+)',
33 array(
34 'methods' => WP_REST_Server::READABLE,
35 'callback' => 'desktop_mode_my_wordpress_comment_stats_callback',
36 'permission_callback' => static function () {
37 return is_user_logged_in();
38 },
39 'args' => array(
40 'id' => array(
41 'required' => true,
42 'type' => 'integer',
43 'sanitize_callback' => 'absint',
44 ),
45 ),
46 )
47 );
48 }
49 add_action( 'rest_api_init', 'desktop_mode_my_wordpress_register_comment_stats_route' );
50
51 /**
52 * Aggregator callback.
53 *
54 * @since 0.8.0
55 *
56 * @param WP_REST_Request $request REST request.
57 * @return array|WP_Error
58 */
59 function desktop_mode_my_wordpress_comment_stats_callback( $request ) {
60 global $wpdb;
61 $comment_id = (int) $request->get_param( 'id' );
62 $comment = get_comment( $comment_id );
63 if ( ! $comment ) {
64 return new WP_Error(
65 'desktop_mode_comment_not_found',
66 __( 'Comment not found.', 'desktop-mode' ),
67 array( 'status' => 404 )
68 );
69 }
70
71 $can_moderate = current_user_can( 'moderate_comments' );
72 $is_approved = '1' === (string) $comment->comment_approved;
73 $is_self = is_user_logged_in()
74 && (int) get_current_user_id() === (int) $comment->user_id
75 && (int) $comment->user_id > 0;
76
77 if ( ! $is_approved && ! $can_moderate && ! $is_self ) {
78 return new WP_Error(
79 'desktop_mode_comment_forbidden',
80 __( 'You do not have permission to view this comment.', 'desktop-mode' ),
81 array( 'status' => 403 )
82 );
83 }
84
85 // ----- Comment body ------------------------------------------------
86 $content_filtered = apply_filters( 'comment_text', $comment->comment_content, $comment, array() );
87 $body = array(
88 'id' => (int) $comment->comment_ID,
89 'parent' => (int) $comment->comment_parent,
90 'date' => mysql2date( 'c', $comment->comment_date_gmt, false ),
91 'status' => $is_approved
92 ? 'approved'
93 : ( '0' === (string) $comment->comment_approved
94 ? 'pending'
95 : (string) $comment->comment_approved ),
96 'rendered' => (string) $content_filtered,
97 'rendered_raw' => (string) $comment->comment_content,
98 'editLink' => $can_moderate
99 ? esc_url_raw(
100 admin_url(
101 'comment.php?action=editcomment&c=' . $comment->comment_ID
102 )
103 )
104 : '',
105 );
106 if ( $can_moderate ) {
107 $body['type'] = (string) $comment->comment_type;
108 $body['ip'] = (string) $comment->comment_author_IP;
109 $body['userAgent'] = (string) $comment->comment_agent;
110 $body['karma'] = (int) $comment->comment_karma;
111 }
112
113 // ----- Author ------------------------------------------------------
114 $author = array(
115 'name' => (string) $comment->comment_author,
116 'url' => esc_url_raw( (string) $comment->comment_author_url ),
117 'avatarUrl' => (string) get_avatar_url(
118 $comment,
119 array( 'size' => 96 )
120 ),
121 'userId' => (int) $comment->user_id,
122 );
123 if ( $can_moderate ) {
124 $author['email'] = (string) $comment->comment_author_email;
125 }
126 if ( $author['userId'] > 0 ) {
127 $user = get_userdata( $author['userId'] );
128 if ( $user ) {
129 $author['displayName'] = $user->display_name;
130 $author['profileLink'] = get_author_posts_url( $user->ID );
131 }
132 }
133
134 // ----- Parent post -------------------------------------------------
135 $post = get_post( (int) $comment->comment_post_ID );
136 $post_payload = null;
137 if ( $post ) {
138 $post_author = $post->post_author > 0
139 ? get_userdata( (int) $post->post_author )
140 : null;
141 $post_payload = array(
142 'id' => (int) $post->ID,
143 'title' => get_the_title( $post ),
144 'link' => (string) get_permalink( $post ),
145 'editLink' => current_user_can( 'edit_post', $post->ID )
146 ? (string) get_edit_post_link( $post->ID, 'raw' )
147 : '',
148 'status' => (string) $post->post_status,
149 'type' => (string) $post->post_type,
150 'date' => mysql2date( 'c', $post->post_date_gmt, false ),
151 'author' => $post_author
152 ? array(
153 'id' => (int) $post_author->ID,
154 'name' => $post_author->display_name,
155 'avatarUrl' => (string) get_avatar_url(
156 $post_author->ID,
157 array( 'size' => 48 )
158 ),
159 )
160 : null,
161 );
162 }
163
164 // ----- Parent comment (if this is a reply) -------------------------
165 $parent_payload = null;
166 if ( (int) $comment->comment_parent > 0 ) {
167 $parent_comment = get_comment( (int) $comment->comment_parent );
168 if ( $parent_comment ) {
169 $parent_payload = array(
170 'id' => (int) $parent_comment->comment_ID,
171 'authorName' => (string) $parent_comment->comment_author,
172 'date' => mysql2date( 'c', $parent_comment->comment_date_gmt, false ),
173 'excerpt' => wp_trim_words(
174 wp_strip_all_tags( $parent_comment->comment_content ),
175 40
176 ),
177 );
178 }
179 }
180
181 // ----- Replies (direct children) -----------------------------------
182 // Static SQL literal — must not go through a %s placeholder, which
183 // would quote it into an adjacent string literal and break the clause.
184 $reply_status_sql = $can_moderate
185 ? "comment_approved IN ( '0', '1' )"
186 : "comment_approved = '1'";
187 $reply_rows = $wpdb->get_results(
188 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $reply_status_sql is a fixed literal chosen above; no user input.
189 $wpdb->prepare(
190 "SELECT comment_ID, comment_author, comment_author_email,
191 comment_date_gmt, comment_content, comment_approved, user_id
192 FROM {$wpdb->comments}
193 WHERE comment_parent = %d
194 AND {$reply_status_sql}
195 ORDER BY comment_date_gmt ASC
196 LIMIT 20",
197 $comment->comment_ID
198 ),
199 ARRAY_A
200 );
201 $replies = array();
202 foreach ( (array) $reply_rows as $row ) {
203 $replies[] = array(
204 'id' => (int) $row['comment_ID'],
205 'authorName' => (string) $row['comment_author'],
206 'avatarUrl' => (string) get_avatar_url(
207 $row['comment_author_email'],
208 array( 'size' => 32 )
209 ),
210 'date' => mysql2date( 'c', (string) $row['comment_date_gmt'], false ),
211 'excerpt' => wp_trim_words(
212 wp_strip_all_tags( (string) $row['comment_content'] ),
213 40
214 ),
215 'status' => '1' === (string) $row['comment_approved']
216 ? 'approved'
217 : (string) $row['comment_approved'],
218 );
219 }
220
221 // ----- Author activity --------------------------------------------
222 // "How busy is this commenter site-wide?" — total approved
223 // comments by this email (or user_id when logged in).
224 $author_total = 0;
225 if ( $author['userId'] > 0 ) {
226 $author_total = (int) $wpdb->get_var(
227 $wpdb->prepare(
228 "SELECT COUNT(*) FROM {$wpdb->comments}
229 WHERE user_id = %d AND comment_approved = '1'",
230 $author['userId']
231 )
232 );
233 } elseif ( ! empty( $comment->comment_author_email ) ) {
234 $author_total = (int) $wpdb->get_var(
235 $wpdb->prepare(
236 "SELECT COUNT(*) FROM {$wpdb->comments}
237 WHERE comment_author_email = %s AND comment_approved = '1'",
238 (string) $comment->comment_author_email
239 )
240 );
241 }
242 $author['totalApprovedComments'] = $author_total;
243
244 $payload = array(
245 'comment' => $body,
246 'author' => $author,
247 'post' => $post_payload,
248 'parent' => $parent_payload,
249 'replies' => $replies,
250 );
251
252 /**
253 * Filter the per-comment dossier payload.
254 *
255 * @since 0.8.0
256 *
257 * @param array $payload Stats payload.
258 * @param int $comment_id Comment id.
259 */
260 return apply_filters(
261 'desktop_mode_my_wordpress_comment_stats',
262 $payload,
263 $comment_id
264 );
265 }
266