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

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