PluginProbe
ActivityPub / 2.1.0
ActivityPub v2.1.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / class-comment.php

class-comment.php in ActivityPub 2.1.0, at includes/class-comment.php

339 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Activitypub;
4
5 use WP_Comment_Query;
6
7 use function Activitypub\is_user_disabled;
8
9 /**
10 * ActivityPub Comment Class
11 *
12 * This class is a helper/utils class that provides a collection of static
13 * methods that are used to handle comments.
14 */
15 class Comment {
16 /**
17 * Initialize the class, registering WordPress hooks
18 */
19 public static function init() {
20 \add_filter( 'comment_reply_link', array( self::class, 'comment_reply_link' ), 10, 3 );
21 \add_filter( 'comment_class', array( self::class, 'comment_class' ), 10, 3 );
22 \add_filter( 'get_comment_link', array( self::class, 'remote_comment_link' ), 11, 3 );
23 }
24
25 /**
26 * Filter the comment reply link.
27 *
28 * We don't want to show the comment reply link for federated comments
29 * if the user is disabled for federation.
30 *
31 * @param string $link The HTML markup for the comment reply link.
32 * @param array $args An array of arguments overriding the defaults.
33 * @param WP_Comment $comment The object of the comment being replied.
34 *
35 * @return string The filtered HTML markup for the comment reply link.
36 */
37 public static function comment_reply_link( $link, $args, $comment ) {
38 if ( self::are_comments_allowed( $comment ) ) {
39 return $link;
40 }
41
42 return apply_filters( 'activitypub_comment_reply_link', '' );
43 }
44
45 /**
46 * Check if it is allowed to comment to a comment.
47 *
48 * Checks if the comment is local only or if the user can comment federated comments.
49 *
50 * @param mixed $comment Comment object or ID.
51 *
52 * @return boolean True if the user can comment, false otherwise.
53 */
54 public static function are_comments_allowed( $comment ) {
55 $comment = \get_comment( $comment );
56
57 if ( ! self::was_received( $comment ) ) {
58 return true;
59 }
60
61 $current_user = get_current_user_id();
62
63 if ( ! $current_user ) {
64 return false;
65 }
66
67 $is_user_disabled = is_user_disabled( $current_user );
68
69 if ( $is_user_disabled ) {
70 return false;
71 }
72
73 return true;
74 }
75
76 /**
77 * Check if a comment is federated.
78 *
79 * We consider a comment federated if comment was received via ActivityPub.
80 *
81 * Use this function to check if it is comment that was received via ActivityPub.
82 *
83 * @param mixed $comment Comment object or ID.
84 *
85 * @return boolean True if the comment is federated, false otherwise.
86 */
87 public static function was_received( $comment ) {
88 $comment = \get_comment( $comment );
89
90 if ( ! $comment ) {
91 return false;
92 }
93
94 $protocol = \get_comment_meta( $comment->comment_ID, 'protocol', true );
95
96 if ( 'activitypub' === $protocol ) {
97 return true;
98 }
99
100 return false;
101 }
102
103 /**
104 * Check if a comment was federated.
105 *
106 * This function checks if a comment was federated via ActivityPub.
107 *
108 * @param mixed $comment Comment object or ID.
109 *
110 * @return boolean True if the comment was federated, false otherwise.
111 */
112 public static function was_sent( $comment ) {
113 $comment = \get_comment( $comment );
114
115 if ( ! $comment ) {
116 return false;
117 }
118
119 $status = \get_comment_meta( $comment->comment_ID, 'activitypub_status', true );
120
121 if ( $status ) {
122 return true;
123 }
124
125 return false;
126 }
127
128 /**
129 * Check if a comment is local only.
130 *
131 * This function checks if a comment is local only and was not sent or received via ActivityPub.
132 *
133 * @param mixed $comment Comment object or ID.
134 *
135 * @return boolean True if the comment is local only, false otherwise.
136 */
137 public static function is_local( $comment ) {
138 if ( self::was_sent( $comment ) || self::was_received( $comment ) ) {
139 return false;
140 }
141
142 return true;
143 }
144
145 /**
146 * Check if a comment should be federated.
147 *
148 * We consider a comment should be federated if it is authored by a user that is
149 * not disabled for federation and if it is a reply directly to the post or to a
150 * federated comment.
151 *
152 * Use this function to check if a comment should be federated.
153 *
154 * @param mixed $comment Comment object or ID.
155 *
156 * @return boolean True if the comment should be federated, false otherwise.
157 */
158 public static function should_be_federated( $comment ) {
159 // we should not federate federated comments
160 if ( self::was_received( $comment ) ) {
161 return false;
162 }
163
164 $comment = \get_comment( $comment );
165 $user_id = $comment->user_id;
166
167 // comments without user can't be federated
168 if ( ! $user_id ) {
169 return false;
170 }
171
172 $is_user_disabled = is_user_disabled( $user_id );
173
174 // user is disabled for federation
175 if ( $is_user_disabled ) {
176 return false;
177 }
178
179 // it is a comment to the post and can be federated
180 if ( empty( $comment->comment_parent ) ) {
181 return true;
182 }
183
184 // check if parent comment is federated
185 $parent_comment = \get_comment( $comment->comment_parent );
186
187 return ! self::is_local( $parent_comment );
188 }
189
190 /**
191 * Examine a comment ID and look up an existing comment it represents.
192 *
193 * @param string $id ActivityPub object ID (usually a URL) to check.
194 *
195 * @return int|boolean Comment ID, or false on failure.
196 */
197 public static function object_id_to_comment( $id ) {
198 $comment_query = new WP_Comment_Query(
199 array(
200 'meta_key' => 'source_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
201 'meta_value' => $id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
202 )
203 );
204
205 if ( ! $comment_query->comments ) {
206 return false;
207 }
208
209 if ( count( $comment_query->comments ) > 1 ) {
210 return false;
211 }
212
213 return $comment_query->comments[0];
214 }
215
216 /**
217 * Verify if URL is a local comment, or if it is a previously received
218 * remote comment (For threading comments locally)
219 *
220 * @param string $url The URL to check.
221 *
222 * @return int comment_ID or null if not found
223 */
224 public static function url_to_commentid( $url ) {
225 if ( ! $url || ! filter_var( $url, \FILTER_VALIDATE_URL ) ) {
226 return null;
227 }
228
229 // check for local comment
230 if ( \wp_parse_url( \site_url(), \PHP_URL_HOST ) === \wp_parse_url( $url, \PHP_URL_HOST ) ) {
231 $query = \wp_parse_url( $url, \PHP_URL_QUERY );
232
233 if ( $query ) {
234 parse_str( $query, $params );
235
236 if ( ! empty( $params['c'] ) ) {
237 $comment = \get_comment( $params['c'] );
238
239 if ( $comment ) {
240 return $comment->comment_ID;
241 }
242 }
243 }
244 }
245
246 $args = array(
247 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
248 'meta_query' => array(
249 'relation' => 'OR',
250 array(
251 'key' => 'source_url',
252 'value' => $url,
253 ),
254 array(
255 'key' => 'source_id',
256 'value' => $url,
257 ),
258 ),
259 );
260
261 $query = new WP_Comment_Query();
262 $comments = $query->query( $args );
263
264 if ( $comments && is_array( $comments ) ) {
265 return $comments[0]->comment_ID;
266 }
267
268 return null;
269 }
270
271 /**
272 * Filters the CSS classes to add an ActivityPub class.
273 *
274 * @param string[] $classes An array of comment classes.
275 * @param string[] $css_class An array of additional classes added to the list.
276 * @param string $comment_id The comment ID as a numeric string.
277 *
278 * @return string[] An array of classes.
279 */
280 public static function comment_class( $classes, $css_class, $comment_id ) {
281 // check if ActivityPub comment
282 if ( 'activitypub' === get_comment_meta( $comment_id, 'protocol', true ) ) {
283 $classes[] = 'activitypub-comment';
284 }
285
286 return $classes;
287 }
288
289 /**
290 * Link remote comments to source url.
291 *
292 * @param string $comment_link
293 * @param object|WP_Comment $comment
294 *
295 * @return string $url
296 */
297 public static function remote_comment_link( $comment_link, $comment ) {
298 if ( ! $comment || is_admin() ) {
299 return $comment_link;
300 }
301
302 $comment_meta = \get_comment_meta( $comment->comment_ID );
303
304 if ( ! empty( $comment_meta['source_url'][0] ) ) {
305 return $comment_meta['source_url'][0];
306 } elseif ( ! empty( $comment_meta['source_id'][0] ) ) {
307 return $comment_meta['source_id'][0];
308 }
309
310 return $comment_link;
311 }
312
313
314 /**
315 * Generates an ActivityPub URI for a comment
316 *
317 * @param WP_Comment|int $comment A comment object or comment ID
318 *
319 * @return string ActivityPub URI for comment
320 */
321 public static function generate_id( $comment ) {
322 $comment = get_comment( $comment );
323
324 // show external comment ID if it exists
325 $source_id = get_comment_meta( $comment->comment_ID, 'source_id', true );
326 if ( ! empty( $source_id ) ) {
327 return $source_id;
328 }
329
330 // generate URI based on comment ID
331 return \add_query_arg(
332 array(
333 'c' => $comment->comment_ID,
334 ),
335 \trailingslashit( site_url() )
336 );
337 }
338 }
339