PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 All 74 releases
bbpress / includes / users / engagements.php

engagements.php in bbPress 2.6.19, at includes/users/engagements.php

1,300 lines 38.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress User Engagement Functions
5 *
6 * @package bbPress
7 * @subpackage Engagements
8 */
9
10 // Exit if accessed directly
11 defined( 'ABSPATH' ) || exit;
12
13 /** User Relationships ********************************************************/
14
15 /**
16 * Add a user id to an object
17 *
18 * @since 2.6.0 bbPress (r6109)
19 *
20 * @param int $object_id The object id
21 * @param int $user_id The user id
22 * @param string $rel_key The relationship key
23 * @param string $rel_type The relationship type (usually 'post')
24 * @param bool $unique Whether meta key should be unique to the object
25 *
26 * @return bool Returns true on success, false on failure
27 */
28 function bbp_add_user_to_object( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post', $unique = false ) {
29 $object_id = absint( $object_id );
30 $user_id = absint( $user_id );
31 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->add_user_to_object( $object_id, $user_id, $rel_key, $rel_type, $unique );
32
33 // Filter & return
34 return (bool) apply_filters( 'bbp_add_user_to_object', $retval, $object_id, $user_id, $rel_key, $rel_type, $unique );
35 }
36
37 /**
38 * Remove a user id from an object
39 *
40 * @since 2.6.0 bbPress (r6109)
41 *
42 * @param int $object_id The object id
43 * @param int $user_id The user id
44 * @param string $rel_key The relationship key
45 * @param string $rel_type The relationship type (usually 'post')
46 *
47 * @return bool Returns true on success, false on failure
48 */
49 function bbp_remove_user_from_object( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
50 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_user_from_object( $object_id, $user_id, $rel_key, $rel_type );
51
52 // Filter & return
53 return (bool) apply_filters( 'bbp_remove_user_from_object', $retval, $object_id, $user_id, $rel_key, $rel_type );
54 }
55
56 /**
57 * Remove a user id from all objects
58 *
59 * @since 2.6.0 bbPress (r6517)
60 *
61 * @param int $user_id The user id
62 * @param string $rel_key The relationship key
63 * @param string $rel_type The relationship type (usually 'post')
64 *
65 * @return bool Returns true on success, false on failure
66 */
67 function bbp_remove_user_from_all_objects( $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
68 $user_id = absint( $user_id );
69 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_user_from_all_objects( $user_id, $rel_key, $rel_type );
70
71 // Filter & return
72 return (bool) apply_filters( 'bbp_remove_user_from_all_objects', $retval, $user_id, $rel_key, $rel_type );
73 }
74
75 /**
76 * Remove an object from all users
77 *
78 * @since 2.6.0 bbPress (r6544)
79 *
80 * @param int $object_id The object id
81 * @param int $user_id The user id
82 * @param string $rel_key The relationship key
83 * @param string $rel_type The relationship type (usually 'post')
84 *
85 * @return bool Returns true on success, false on failure
86 */
87 function bbp_remove_object_from_all_users( $object_id = 0, $rel_key = '', $rel_type = 'post' ) {
88 $object_id = absint( $object_id );
89 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_object_from_all_users( $object_id, $rel_key, $rel_type );
90
91 // Filter & return
92 return (bool) apply_filters( 'bbp_remove_object_from_all_users', $retval, $object_id, $rel_key, $rel_type );
93 }
94
95 /**
96 * Remove all users from all objects
97 *
98 * @since 2.6.0 bbPress (r6520)
99 *
100 * @param string $rel_key The relationship key
101 * @param string $rel_type The relationship type (usually 'post')
102 *
103 * @return bool Returns true on success, false on failure
104 */
105 function bbp_remove_all_users_from_all_objects( $rel_key = '', $rel_type = 'post' ) {
106 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_all_users_from_all_objects( $rel_key, $rel_type );
107
108 // Filter & return
109 return (bool) apply_filters( 'bbp_remove_all_users_from_all_objects', $retval, $rel_key, $rel_type );
110 }
111
112 /**
113 * Get users of an object
114 *
115 * @since 2.6.0 bbPress (r6109)
116 *
117 * @param int $object_id The object id
118 * @param string $rel_key The key used to index this relationship
119 * @param string $rel_type The type of meta to look in
120 *
121 * @return array Returns ids of users
122 */
123 function bbp_get_users_for_object( $object_id = 0, $rel_key = '', $rel_type = 'post' ) {
124 $object_id = absint( $object_id );
125 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->get_users_for_object( $object_id, $rel_key, $rel_type );
126
127 // Filter & return
128 return (array) apply_filters( 'bbp_get_users_for_object', $retval, $object_id, $rel_key, $rel_type );
129 }
130
131 /**
132 * Check if an object has a specific user
133 *
134 * @since 2.6.0 bbPress (r6109)
135 *
136 * @param int $object_id The object id
137 * @param int $user_id The user id
138 * @param string $rel_key The relationship key
139 * @param string $rel_type The relationship type (usually 'post')
140 *
141 * @return bool Returns true if object has a user, false if not
142 */
143 function bbp_is_object_of_user( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
144 $object_id = absint( $object_id );
145 $user_id = absint( $user_id );
146 $user_ids = bbp_get_users_for_object( $object_id, $rel_key, $rel_type );
147 $retval = is_numeric( array_search( $user_id, $user_ids, true ) );
148
149 // Filter & return
150 return (bool) apply_filters( 'bbp_is_object_of_user', $retval, $object_id, $user_id, $rel_key, $rel_type );
151 }
152
153 /**
154 * Get the query part responsible for JOINing objects to user IDs
155 *
156 * @since 2.6.0 bbPress (r6739)
157 *
158 * @param array $args Default query arguments
159 * @param string $context Additional context
160 * @param string $rel_key The relationship key
161 * @param string $rel_type The relationship type (usually 'post')
162 *
163 * @return array
164 */
165 function bbp_get_user_object_query( $args = array(), $context = '', $rel_key = '', $rel_type = 'post' ) {
166 $retval = bbp_user_engagements_interface( $rel_key, $rel_type )->get_query( $args, "get_user_{$context}", $rel_key, $rel_type );
167
168 // Filter & return
169 return (array) apply_filters( 'bbp_get_user_object_query', $retval, $args, $context, $rel_key, $rel_type );
170 }
171
172 /** Engagements ***************************************************************/
173
174 /**
175 * Get the users who have engaged in a topic
176 *
177 * @since 2.6.0 bbPress (r6311)
178 *
179 * @param int $topic_id Optional. Topic id
180 *
181 * @return array|bool Results if the topic has any engagements, otherwise false
182 */
183 function bbp_get_topic_engagements( $topic_id = 0 ) {
184 $topic_id = bbp_get_topic_id( $topic_id );
185 $users = bbp_get_users_for_object( $topic_id, '_bbp_engagement' );
186
187 // Filter & return
188 return (array) apply_filters( 'bbp_get_topic_engagements', $users, $topic_id );
189 }
190
191 /**
192 * Return the users who have engaged in a topic, directly with a database query
193 *
194 * See: https://bbpress.trac.wordpress.org/ticket/3083
195 *
196 * @since 2.6.0 bbPress (r6522)
197 * @since 2.6.17 bbPress (r7468) Honor filtered public reply statuses.
198 *
199 * @param int $topic_id
200 *
201 * @return array
202 */
203 function bbp_get_topic_engagements_raw( $topic_id = 0 ) {
204
205 // Default variables
206 $topic_id = bbp_get_topic_id( $topic_id );
207 $bbp_db = bbp_db();
208 $topic_type = bbp_get_topic_post_type();
209 $reply_type = bbp_get_reply_post_type();
210 $topic_statuses = array_unique( array_filter( bbp_get_public_topic_statuses() ) );
211 $reply_statuses = array_unique( array_filter( bbp_get_public_reply_statuses() ) );
212 $sql = array();
213 $values = array();
214
215 // Add the topic author for countable topic statuses
216 if ( ! empty( $topic_statuses ) ) {
217 $placeholders = implode( ', ', array_fill( 0, count( $topic_statuses ), '%s' ) );
218 $sql[] = "SELECT post_author FROM {$bbp_db->posts} WHERE ID = %d AND post_status IN ( {$placeholders} ) AND post_type = %s";
219 $values = array_merge( $values, array( $topic_id ), $topic_statuses, array( $topic_type ) );
220 }
221
222 // Add reply authors for countable reply statuses
223 if ( ! empty( $reply_statuses ) ) {
224 $placeholders = implode( ', ', array_fill( 0, count( $reply_statuses ), '%s' ) );
225 $sql[] = "SELECT post_author FROM {$bbp_db->posts} WHERE post_parent = %d AND post_status IN ( {$placeholders} ) AND post_type = %s";
226 $values = array_merge( $values, array( $topic_id ), $reply_statuses, array( $reply_type ) );
227 }
228
229 // Query unique topic and reply authors
230 $results = ! empty( $sql )
231 ? $bbp_db->get_col( $bbp_db->prepare( implode( ' UNION ', $sql ), $values ) )
232 : array();
233
234 // Parse results into voices
235 $engagements = wp_parse_id_list( array_filter( $results ) );
236
237 // Filter & return
238 return (array) apply_filters( 'bbp_get_topic_engagements_raw', $engagements, $topic_id );
239 }
240
241 /**
242 * Get a user's topic engagements
243 *
244 * @since 2.6.0 bbPress (r6311)
245 * @since 2.6.0 bbPress (r6619) Signature changed to accept an array of arguments
246 *
247 * @param array $args Optional. Arguments to pass into bbp_has_replies()
248 *
249 * @return bool True if user has engaged, otherwise false
250 */
251 function bbp_get_user_engagements( $args = array() ) {
252 $r = bbp_get_user_object_query( $args, 'engagements', '_bbp_engagement' );
253 $query = bbp_has_topics( $r );
254
255 // Filter & return
256 return apply_filters( 'bbp_get_user_engagements', $query, 0, $r, $args );
257 }
258
259 /**
260 * Check if a user is engaged in a topic or not
261 *
262 * @since 2.6.0 bbPress (r6311)
263 *
264 * @param int $user_id Optional. User id
265 * @param int $topic_id Optional. Topic id
266 *
267 * @return bool True if the topic is in user's engagements, otherwise false
268 */
269 function bbp_is_user_engaged( $user_id = 0, $topic_id = 0 ) {
270 $user_id = bbp_get_user_id( $user_id, true, true );
271 $topic_id = bbp_get_topic_id( $topic_id );
272 $retval = bbp_is_object_of_user( $topic_id, $user_id, '_bbp_engagement' );
273
274 // Filter & return
275 return (bool) apply_filters( 'bbp_is_user_engaged', $retval, $user_id, $topic_id );
276 }
277
278 /**
279 * Add a topic to user's engagements
280 *
281 * Note that both the User and Topic should be verified to exist before using
282 * this function. Originally both were validated, but because this function is
283 * frequently used within a loop, those verifications were moved upstream to
284 * improve performance on topics with many engaged users.
285 *
286 * @since 2.6.0 bbPress (r6311)
287 *
288 * @param int $user_id Optional. User id
289 * @param int $topic_id Optional. Topic id
290 *
291 * @return bool Always true
292 */
293 function bbp_add_user_engagement( $user_id = 0, $topic_id = 0 ) {
294
295 // Bail if not enough info
296 if ( empty( $user_id ) || empty( $topic_id ) ) {
297 return false;
298 }
299
300 // Bail if already a engaged
301 if ( bbp_is_user_engaged( $user_id, $topic_id ) ) {
302 return false;
303 }
304
305 // Bail if add fails
306 if ( ! bbp_add_user_to_object( $topic_id, $user_id, '_bbp_engagement' ) ) {
307 return false;
308 }
309
310 do_action( 'bbp_add_user_engagement', $user_id, $topic_id );
311
312 return true;
313 }
314
315 /**
316 * Remove a topic from user's engagements
317 *
318 * @since 2.6.0 bbPress (r6311)
319 *
320 * @param int $user_id Optional. User id
321 * @param int $topic_id Optional. Topic id
322 *
323 * @return bool True if the topic was removed from user's engagements, otherwise
324 * false
325 */
326 function bbp_remove_user_engagement( $user_id = 0, $topic_id = 0 ) {
327
328 // Bail if not enough info
329 if ( empty( $user_id ) || empty( $topic_id ) ) {
330 return false;
331 }
332
333 // Bail if not already engaged
334 if ( ! bbp_is_user_engaged( $user_id, $topic_id ) ) {
335 return false;
336 }
337
338 // Bail if remove fails
339 if ( ! bbp_remove_user_from_object( $topic_id, $user_id, '_bbp_engagement' ) ) {
340 return false;
341 }
342
343 do_action( 'bbp_remove_user_engagement', $user_id, $topic_id );
344
345 return true;
346 }
347
348 /**
349 * Recalculate all of the users who have engaged in a topic.
350 *
351 * This happens when permanently deleting a reply, because that reply author may
352 * have authored other replies to that same topic, or the topic itself.
353 *
354 * You may need to do this manually on heavily active forums where engagement
355 * count accuracy is important.
356 *
357 * @since 2.6.0 bbPress (r6522)
358 *
359 * @param int $topic_id
360 * @param bool $force
361 *
362 * @return boolean True if any engagements are added, false otherwise
363 */
364 function bbp_recalculate_topic_engagements( $topic_id = 0, $force = false ) {
365
366 // Default return value
367 $retval = false;
368
369 // Check post type
370 $topic_id = bbp_is_reply( $topic_id )
371 ? bbp_get_reply_topic_id( $topic_id )
372 : bbp_get_topic_id( $topic_id );
373
374 // Bail if no topic ID
375 if ( empty( $topic_id ) ) {
376 return $retval;
377 }
378
379 // Query for engagements
380 $old_engagements = bbp_get_topic_engagements( $topic_id );
381 $new_engagements = bbp_get_topic_engagements_raw( $topic_id );
382
383 // Sort arrays
384 sort( $old_engagements, SORT_NUMERIC );
385 sort( $new_engagements, SORT_NUMERIC );
386
387 // Only recalculate on change
388 if ( ( true === $force ) || ( $old_engagements !== $new_engagements ) ) {
389
390 // Delete all engagements
391 bbp_remove_object_from_all_users( $topic_id, '_bbp_engagement' );
392
393 // Update the voice count for this topic id
394 foreach ( $new_engagements as $user_id ) {
395 $retval = bbp_add_user_engagement( $user_id, $topic_id );
396 }
397 }
398
399 // Filter & return
400 return (bool) apply_filters( 'bbp_recalculate_user_engagements', $retval, $topic_id );
401 }
402
403 /**
404 * Update the engagements of a topic.
405 *
406 * Hooked to 'bbp_new_topic' and 'bbp_new_reply', this gets the post author and
407 * if not anonymous, passes it into bbp_add_user_engagement().
408 *
409 * @since 2.6.0 bbPress (r6529)
410 *
411 * @param int $topic_id
412 */
413 function bbp_update_topic_engagements( $topic_id = 0 ) {
414
415 // Is a reply
416 if ( bbp_is_reply( $topic_id ) ) {
417
418 // Bail if reply isn't published
419 if ( ! bbp_is_reply_published( $topic_id ) ) {
420 return;
421 }
422
423 $author_id = bbp_get_reply_author_id( $topic_id );
424 $topic_id = bbp_get_reply_topic_id( $topic_id );
425
426 // Is a topic
427 } elseif ( bbp_is_topic( $topic_id ) ) {
428
429 // Bail if topic isn't published
430 if ( ! bbp_is_topic_published( $topic_id ) ) {
431 return;
432 }
433
434 $author_id = bbp_get_topic_author_id( $topic_id );
435 $topic_id = bbp_get_topic_id( $topic_id );
436
437 // Is unknown
438 } else {
439 return;
440 }
441
442 // Bail if topic is not public
443 if ( ! bbp_is_topic_public( $topic_id ) ) {
444 return;
445 }
446
447 // Return whether engagement was added
448 return bbp_add_user_engagement( $author_id, $topic_id );
449 }
450
451 /** Engagement Toggles ********************************************************/
452
453 /**
454 * Check whether the current user can toggle a favorite or subscription.
455 *
456 * Only topics may be favorited. Topics and forums may be subscribed to, and
457 * the user must be able to read both a topic and its containing forum when
458 * adding an engagement. Existing engagements may be removed after visibility
459 * changes.
460 *
461 * @since 2.6.19 bbPress (r7643)
462 *
463 * @param int $object_id Post ID.
464 * @param string $object_type Metadata object type; only post is supported.
465 * @param string $engagement Favorite or subscription.
466 * @param string $action Add or remove.
467 * @return bool Whether the current user can toggle the engagement.
468 */
469 function bbp_current_user_can_toggle_engagement( $object_id = 0, $object_type = 'post', $engagement = 'subscription', $action = 'add' ) {
470 if ( ( 'post' !== $object_type ) || ! in_array( $action, array( 'add', 'remove' ), true ) ) {
471 return false;
472 }
473
474 $post = get_post( $object_id );
475
476 if ( empty( $post ) ) {
477 return false;
478 }
479
480 if ( bbp_get_topic_post_type() === $post->post_type ) {
481 $forum_id = bbp_get_topic_forum_id( $post->ID );
482
483 return ! empty( $forum_id )
484 && bbp_is_forum( $forum_id )
485 && in_array( $engagement, array( 'favorite', 'subscription' ), true )
486 && ( ( 'remove' === $action ) || ( current_user_can( 'read_topic', $post->ID ) && current_user_can( 'read_forum', $forum_id ) ) );
487 }
488
489 return ( 'subscription' === $engagement )
490 && ( bbp_get_forum_post_type() === $post->post_type )
491 && ( ( 'remove' === $action ) || current_user_can( 'read_forum', $post->ID ) );
492 }
493
494 /** Favorites *****************************************************************/
495
496 /**
497 * Get the users who have made the topic favorite
498 *
499 * @since 2.0.0 bbPress (r2668)
500 *
501 * @param int $topic_id Optional. Topic id
502 *
503 * @return array|bool Results if the topic has any favoriters, otherwise false
504 */
505 function bbp_get_topic_favoriters( $topic_id = 0 ) {
506 $topic_id = bbp_get_topic_id( $topic_id );
507 $users = bbp_get_users_for_object( $topic_id, '_bbp_favorite' );
508
509 // Filter & return
510 return (array) apply_filters( 'bbp_get_topic_favoriters', $users, $topic_id );
511 }
512
513 /**
514 * Get a user's favorite topics
515 *
516 * @since 2.0.0 bbPress (r2652)
517 * @since 2.6.0 bbPress (r6619) Signature changed to accept an array of arguments
518 *
519 * @param array $args Optional. Arguments to pass into bbp_has_topics()
520 *
521 * @return array Array of topics if user has favorites, otherwise empty array
522 */
523 function bbp_get_user_favorites( $args = array() ) {
524 $r = bbp_get_user_object_query( $args, 'favorites', '_bbp_favorite' );
525 $query = ! empty( $r )
526 ? bbp_has_topics( $r )
527 : array();
528
529 // Filter & return
530 return apply_filters( 'bbp_get_user_favorites', $query, 0, $r, $args );
531 }
532
533 /**
534 * Check if a topic is in user's favorites or not
535 *
536 * @since 2.0.0 bbPress (r2652)
537 *
538 * @param int $user_id Optional. User id
539 * @param int $topic_id Optional. Topic id
540 *
541 * @return bool True if the topic is in user's favorites, otherwise false
542 */
543 function bbp_is_user_favorite( $user_id = 0, $topic_id = 0 ) {
544 $retval = bbp_is_object_of_user( $topic_id, $user_id, '_bbp_favorite' );
545
546 // Filter & return
547 return (bool) apply_filters( 'bbp_is_user_favorite', $retval, $user_id, $topic_id );
548 }
549
550 /**
551 * Add a topic to user's favorites
552 *
553 * Note that both the User and Topic should be verified to exist before using
554 * this function. Originally both were validated, but because this function is
555 * frequently used within a loop, those verifications were moved upstream to
556 * improve performance on topics with many engaged users.
557 *
558 * @since 2.0.0 bbPress (r2652)
559 *
560 * @param int $user_id Optional. User id
561 * @param int $topic_id Optional. Topic id
562 *
563 * @return bool True if the topic was added to user's favorites, otherwise false
564 */
565 function bbp_add_user_favorite( $user_id = 0, $topic_id = 0 ) {
566 $user_id = bbp_get_user_id( $user_id, false, false );
567 $topic_id = bbp_get_topic_id( $topic_id );
568
569 // Bail if not enough info
570 if ( empty( $user_id ) || empty( $topic_id ) ) {
571 return false;
572 }
573
574 // Bail if already a favorite
575 if ( bbp_is_user_favorite( $user_id, $topic_id ) ) {
576 return false;
577 }
578
579 // Bail if add fails
580 if ( ! bbp_add_user_to_object( $topic_id, $user_id, '_bbp_favorite' ) ) {
581 return false;
582 }
583
584 do_action( 'bbp_add_user_favorite', $user_id, $topic_id );
585
586 return true;
587 }
588
589 /**
590 * Remove a topic from user's favorites
591 *
592 * @since 2.0.0 bbPress (r2652)
593 *
594 * @param int $user_id Optional. User id
595 * @param int $topic_id Optional. Topic id
596 *
597 * @return bool True if the topic was removed from user's favorites, otherwise false
598 */
599 function bbp_remove_user_favorite( $user_id, $topic_id ) {
600 $user_id = bbp_get_user_id( $user_id, false, false );
601 $topic_id = bbp_get_topic_id( $topic_id );
602
603 // Bail if not enough info
604 if ( empty( $user_id ) || empty( $topic_id ) ) {
605 return false;
606 }
607
608 // Bail if not already a favorite
609 if ( ! bbp_is_user_favorite( $user_id, $topic_id ) ) {
610 return false;
611 }
612
613 // Bail if remove fails
614 if ( ! bbp_remove_user_from_object( $topic_id, $user_id, '_bbp_favorite' ) ) {
615 return false;
616 }
617
618 do_action( 'bbp_remove_user_favorite', $user_id, $topic_id );
619
620 return true;
621 }
622
623 /**
624 * Handles the front end adding and removing of favorite topics
625 *
626 * @param string $action The requested action to compare this function to
627 */
628 function bbp_favorites_handler( $action = '' ) {
629
630 // Default
631 $success = false;
632
633 // Bail if favorites not active
634 if ( ! bbp_is_favorites_active() ) {
635 return $success;
636 }
637
638 // Bail if no topic ID is passed
639 if ( empty( $_GET['object_id'] ) ) {
640 return $success;
641 }
642
643 // Setup possible get actions
644 $possible_actions = array(
645 'bbp_favorite_add',
646 'bbp_favorite_remove',
647 );
648
649 // Bail if actions aren't meant for this function
650 if ( ! in_array( $action, $possible_actions, true ) ) {
651 return $success;
652 }
653
654 // What action is taking place?
655 $topic_id = bbp_get_topic_id( $_GET['object_id'] );
656 $user_id = bbp_get_user_id( 0, true, true );
657 $toggle_action = ( 'bbp_favorite_remove' === $action ) ? 'remove' : 'add';
658
659 // Check for empty topic
660 if ( empty( $topic_id ) || ! bbp_current_user_can_toggle_engagement( $topic_id, 'post', 'favorite', $toggle_action ) ) {
661 bbp_add_error( 'bbp_favorite_topic_id', __( '<strong>Error</strong>: No topic was found. Which topic are you marking/unmarking as favorite?', 'bbpress' ) );
662
663 // Check nonce
664 } elseif ( ! bbp_verify_nonce_request( 'toggle-favorite_' . $topic_id ) ) {
665 bbp_add_error( 'bbp_favorite_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
666
667 // Check current user's ability to edit the user
668 } elseif ( ! current_user_can( 'edit_user', $user_id ) ) {
669 bbp_add_error( 'bbp_favorite_permission', __( '<strong>Error</strong>: You do not have permission to edit favorites for that user.', 'bbpress' ) );
670 }
671
672 // Bail if errors
673 if ( bbp_has_errors() ) {
674 return $success;
675 }
676
677 /** No errors *************************************************************/
678
679 if ( 'bbp_favorite_remove' === $action ) {
680 $success = bbp_remove_user_favorite( $user_id, $topic_id );
681 } elseif ( 'bbp_favorite_add' === $action ) {
682 $success = bbp_add_user_favorite( $user_id, $topic_id );
683 }
684
685 // Do additional favorites actions
686 do_action( 'bbp_favorites_handler', $success, $user_id, $topic_id, $action );
687
688 // Success!
689 if ( true === $success ) {
690
691 // Redirect back from whence we came
692 if ( ! empty( $_REQUEST['redirect_to'] ) ) {
693 $redirect = $_REQUEST['redirect_to']; // Validated later
694 } elseif ( bbp_is_favorites() ) {
695 $redirect = bbp_get_favorites_permalink( $user_id, true );
696 } elseif ( bbp_is_single_user() ) {
697 $redirect = bbp_get_user_profile_url();
698 } elseif ( is_singular( bbp_get_topic_post_type() ) ) {
699 $redirect = bbp_get_topic_permalink( $topic_id );
700 } elseif ( is_single() || is_page() ) {
701 $redirect = get_permalink();
702 } else {
703 $redirect = get_permalink( $topic_id );
704 }
705
706 bbp_redirect( $redirect );
707
708 // Fail! Handle errors
709 } elseif ( 'bbp_favorite_remove' === $action ) {
710 bbp_add_error( 'bbp_favorite_remove', __( '<strong>Error</strong>: There was a problem removing that topic from favorites.', 'bbpress' ) );
711 } elseif ( 'bbp_favorite_add' === $action ) {
712 bbp_add_error( 'bbp_favorite_add', __( '<strong>Error</strong>: There was a problem favoriting that topic.', 'bbpress' ) );
713 }
714
715 return (bool) $success;
716 }
717
718 /** Subscriptions *************************************************************/
719
720 /**
721 * Get the users who have subscribed
722 *
723 * @since 2.6.0 bbPress (r6544)
724 *
725 * @param int $object_id Optional. ID of object (forum, topic, or something else)
726 */
727 function bbp_get_subscribers( $object_id = 0, $type = 'post' ) {
728 $users = bbp_get_users_for_object( $object_id, '_bbp_subscription', $type );
729
730 // Filter & return
731 return (array) apply_filters( 'bbp_get_subscribers', $users, $object_id, $type );
732 }
733
734 /**
735 * Get a user's subscribed topics
736 *
737 * @since 2.5.0 bbPress (r5156)
738 * @since 2.6.0 bbPress (r6619) Signature changed to accept an array of arguments
739 *
740 * @param array $args Optional. Arguments to pass into bbp_has_topics()
741 *
742 * @return array Array of topics if user has topic subscriptions, otherwise empty array
743 */
744 function bbp_get_user_topic_subscriptions( $args = array() ) {
745 $r = bbp_get_user_object_query( $args, 'topic_subscriptions', '_bbp_subscription' );
746 $query = ! empty( $r )
747 ? bbp_has_topics( $r )
748 : array();
749
750 // Filter & return
751 return apply_filters( 'bbp_get_user_topic_subscriptions', $query, 0, $r, $args );
752 }
753
754 /**
755 * Get a user's subscribed forums
756 *
757 * @since 2.5.0 bbPress (r5156)
758 * @since 2.6.0 bbPress (r6619) Signature changed to accept an array of arguments
759 *
760 * @param array $args Optional. Arguments to pass into bbp_has_forums()
761 *
762 * @return array Array of forums if user has forum subscriptions, otherwise empty array
763 */
764 function bbp_get_user_forum_subscriptions( $args = array() ) {
765 $r = bbp_get_user_object_query( $args, 'forum_subscriptions', '_bbp_subscription' );
766 $query = ! empty( $r )
767 ? bbp_has_forums( $r )
768 : array();
769
770 // Filter & return
771 return apply_filters( 'bbp_get_user_forum_subscriptions', $query, 0, $r, $args );
772 }
773
774 /**
775 * Check if an object (forum or topic) is in user's subscription list or not
776 *
777 * @since 2.0.0 bbPress (r2668)
778 *
779 * @param int $user_id Optional. User id
780 * @param int $object_id Optional. Object id
781 *
782 * @return bool True if the object (forum or topic) is in user's subscriptions, otherwise false
783 */
784 function bbp_is_user_subscribed( $user_id = 0, $object_id = 0, $type = 'post' ) {
785 $retval = bbp_is_object_of_user( $object_id, $user_id, '_bbp_subscription', $type );
786
787 // Filter & return
788 return (bool) apply_filters( 'bbp_is_user_subscribed', $retval, $user_id, $object_id, $type );
789 }
790
791 /**
792 * Add a user subscription
793 *
794 * @since 2.0.0 bbPress (r2668)
795 * @since 2.6.0 bbPress (r6544) Added $type parameter
796 *
797 * @param int $user_id Optional. User id
798 * @param int $object_id Optional. Object id
799 * @param string $type Optional. Type of object being subscribed to
800 *
801 * @return bool True if the object was added to user subscriptions, otherwise false
802 */
803 function bbp_add_user_subscription( $user_id = 0, $object_id = 0, $type = 'post' ) {
804
805 // Bail if not enough info
806 if ( empty( $user_id ) || empty( $object_id ) ) {
807 return false;
808 }
809
810 // Bail if already subscribed
811 if ( bbp_is_user_subscribed( $user_id, $object_id, $type ) ) {
812 return false;
813 }
814
815 // Bail if add fails
816 if ( ! bbp_add_user_to_object( $object_id, $user_id, '_bbp_subscription', $type ) ) {
817 return false;
818 }
819
820 do_action( 'bbp_add_user_subscription', $user_id, $object_id, $type );
821
822 return true;
823 }
824
825 /**
826 * Remove a user subscription
827 *
828 * @since 2.0.0 bbPress (r2668)
829 * @since 2.6.0 bbPress (r6544) Added $type parameter
830 *
831 * @param int $user_id Optional. User id
832 * @param int $object_id Optional. Object id
833 * @param string $type Optional. Type of object being subscribed to
834 *
835 * @return bool True if the object was removed from user subscriptions, otherwise false
836 */
837 function bbp_remove_user_subscription( $user_id = 0, $object_id = 0, $type = 'post' ) {
838
839 // Bail if not enough info
840 if ( empty( $user_id ) || empty( $object_id ) ) {
841 return false;
842 }
843
844 // Bail if not subscribed
845 if ( ! bbp_is_user_subscribed( $user_id, $object_id, $type ) ) {
846 return false;
847 }
848
849 // Bail if remove fails
850 if ( ! bbp_remove_user_from_object( $object_id, $user_id, '_bbp_subscription', $type ) ) {
851 return false;
852 }
853
854 do_action( 'bbp_remove_user_subscription', $user_id, $object_id, $type );
855
856 return true;
857 }
858
859 /**
860 * Handles the front end toggling of user subscriptions
861 *
862 * @since 2.0.0 bbPress (r2668)
863 * @since 2.6.0 bbPress (r6544)
864 *
865 * @param string $action The requested action to compare this function to
866 */
867 function bbp_subscriptions_handler( $action = '' ) {
868
869 // Default
870 $success = false;
871
872 // Bail if subscriptions not active
873 if ( ! bbp_is_subscriptions_active() ) {
874 return $success;
875 }
876
877 // Bail if no object ID is passed
878 if ( empty( $_GET['object_id'] ) ) {
879 return $success;
880 }
881
882 // Setup possible get actions
883 $possible_actions = array(
884 'bbp_subscribe',
885 'bbp_unsubscribe'
886 );
887
888 // Bail if actions aren't meant for this function
889 if ( ! in_array( $action, $possible_actions, true ) ) {
890 return $success;
891 }
892
893 // Get required data
894 $user_id = bbp_get_current_user_id();
895 $object_id = absint( $_GET['object_id'] );
896 $object_type = 'post';
897 if ( ! empty( $_GET['object_type'] ) ) {
898 $object_type = is_string( $_GET['object_type'] ) ? sanitize_key( $_GET['object_type'] ) : '';
899 }
900 $toggle_action = ( 'bbp_unsubscribe' === $action ) ? 'remove' : 'add';
901
902 // Check for empty topic
903 if ( empty( $object_id ) || ! bbp_current_user_can_toggle_engagement( $object_id, $object_type, 'subscription', $toggle_action ) ) {
904 bbp_add_error( 'bbp_subscription_object_id', __( '<strong>Error</strong>: Not found. What are you subscribing/unsubscribing to?', 'bbpress' ) );
905
906 // Check nonce
907 } elseif ( ! bbp_verify_nonce_request( 'toggle-subscription_post_' . $object_id ) && ! bbp_verify_nonce_request( 'toggle-subscription_' . $object_id ) ) {
908 bbp_add_error( 'bbp_subscription_object_id', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
909
910 // Check current user's ability to edit the user
911 } elseif ( ! current_user_can( 'edit_user', $user_id ) ) {
912 bbp_add_error( 'bbp_subscription_permission', __( '<strong>Error</strong>: You do not have permission to edit subscriptions of that user.', 'bbpress' ) );
913 }
914
915 // Bail if we have errors
916 if ( bbp_has_errors() ) {
917 return $success;
918 }
919
920 /** No errors *************************************************************/
921
922 if ( 'bbp_unsubscribe' === $action ) {
923 $success = bbp_remove_user_subscription( $user_id, $object_id, $object_type );
924 } elseif ( 'bbp_subscribe' === $action ) {
925 $success = bbp_add_user_subscription( $user_id, $object_id, $object_type );
926 }
927
928 // Do additional subscriptions actions
929 do_action( 'bbp_subscriptions_handler', $success, $user_id, $object_id, $action, $object_type );
930
931 // Success!
932 if ( true === $success ) {
933
934 // Redirect back from whence we came
935 if ( ! empty( $_REQUEST['redirect_to'] ) ) {
936 $redirect = $_REQUEST['redirect_to']; // Validated later
937 } elseif ( bbp_is_subscriptions() ) {
938 $redirect = bbp_get_subscriptions_permalink( $user_id );
939 } elseif ( bbp_is_single_user() ) {
940 $redirect = bbp_get_user_profile_url();
941 } elseif ( is_singular( bbp_get_topic_post_type() ) ) {
942 $redirect = bbp_get_topic_permalink( $object_id );
943 } elseif ( is_singular( bbp_get_forum_post_type() ) ) {
944 $redirect = bbp_get_forum_permalink( $object_id );
945 } elseif ( is_single() || is_page() ) {
946 $redirect = get_permalink();
947 } else {
948 $redirect = get_permalink( $object_id );
949 }
950
951 bbp_redirect( $redirect );
952
953 // Fail! Handle errors
954 } elseif ( 'bbp_unsubscribe' === $action ) {
955 bbp_add_error( 'bbp_unsubscribe', __( '<strong>Error</strong>: There was a problem unsubscribing.', 'bbpress' ) );
956 } elseif ( 'bbp_subscribe' === $action ) {
957 bbp_add_error( 'bbp_subscribe', __( '<strong>Error</strong>: There was a problem subscribing.', 'bbpress' ) );
958 }
959
960 return (bool) $success;
961 }
962
963 /** Query Helpers *************************************************************/
964
965 /**
966 * These functions are no longer used in bbPress due to general performance
967 * concerns on large installations. They are provided here for convenience and
968 * backwards compatibility only.
969 */
970
971 /**
972 * Get a user's object IDs
973 *
974 * For the most part, you should not need to use this function, and may even
975 * want to come up with a more efficient way to get IDs on your own. Nevertheless,
976 * it is available here for your convenience, using the most efficient query
977 * parameters available inside of the various query APIs.
978 *
979 * @since 2.6.0 bbPress (r6607)
980 *
981 * @param int $user_id The user id
982 * @param string $rel_key The relationship key
983 * @param string $rel_type The relationship type (usually 'post')
984 * @param array $args The arguments to override defaults
985 *
986 * @return array|bool Results if user has objects, otherwise null
987 */
988 function bbp_get_user_object_ids( $args = array() ) {
989 $object_ids = $defaults = array();
990
991 // Parse arguments
992 $r = bbp_parse_args(
993 $args,
994 array(
995 'user_id' => 0,
996 'object_type' => bbp_get_topic_post_type(),
997 'rel_key' => '',
998 'rel_type' => 'post',
999 'filter' => 'user_object_ids',
1000 'args' => array()
1001 ),
1002 'get_user_object_ids'
1003 );
1004
1005 // Sanitize arguments
1006 $r['user_id'] = bbp_get_user_id( $r['user_id'] );
1007 $r['rel_key'] = sanitize_key( $r['rel_key'] );
1008 $r['rel_type'] = sanitize_key( $r['rel_type'] );
1009 $r['object_type'] = sanitize_key( $r['object_type'] );
1010 $r['filter'] = sanitize_key( $r['filter'] );
1011
1012 // Defaults
1013 if ( 'post' === $r['rel_type'] ) {
1014 $defaults = array(
1015 'fields' => 'ids',
1016 'post_type' => $r['object_type'],
1017 'posts_per_page' => -1,
1018 'meta_query' => array(
1019 array(
1020 'key' => $r['rel_key'],
1021 'value' => $r['user_id'],
1022 'compare' => 'NUMERIC'
1023 ),
1024 // Performance
1025 'nopaging' => true,
1026 'suppress_filters' => true,
1027 'update_post_term_cache' => false,
1028 'update_post_meta_cache' => false,
1029 'ignore_sticky_posts' => true,
1030 'no_found_rows' => true
1031 )
1032 );
1033 }
1034
1035 // Parse arguments
1036 $query_args = bbp_parse_args( $r['args'], $defaults, "get_{$r['filter']}_args" );
1037
1038 // Queries
1039 if ( 'post' === $r['rel_type'] ) {
1040 $query = new WP_Query( $query_args );
1041 $object_ids = $query->posts;
1042 }
1043
1044 // Filter & return
1045 return (array) apply_filters( "bbp_get_{$r['filter']}", $object_ids, $r, $args );
1046 }
1047
1048 /**
1049 * Get array of forum IDs that a user can moderate
1050 *
1051 * @since 2.6.0 bbPress (r5834)
1052 *
1053 * @param int $user_id User id.
1054 *
1055 * @return array Return array of forum ids, or empty array
1056 */
1057 function bbp_get_moderator_forum_ids( $user_id = 0 ) {
1058 return bbp_get_user_object_ids(
1059 array(
1060 'user_id' => $user_id,
1061 'rel_key' => '_bbp_moderator_id',
1062 'object_type' => bbp_get_forum_post_type(),
1063 'filter' => 'moderator_forum_ids'
1064 )
1065 );
1066 }
1067
1068 /**
1069 * Get a user's engaged topic ids
1070 *
1071 * @since 2.6.0 bbPress (r6311)
1072 *
1073 * @param int $user_id Optional. User id
1074 *
1075 * @return array Return array of topic ids, or empty array
1076 */
1077 function bbp_get_user_engaged_topic_ids( $user_id = 0 ) {
1078 return bbp_get_user_object_ids(
1079 array(
1080 'user_id' => $user_id,
1081 'rel_key' => '_bbp_engagement',
1082 'filter' => 'user_engaged_topic_ids'
1083 )
1084 );
1085 }
1086
1087 /**
1088 * Get a user's favorite topic ids
1089 *
1090 * @since 2.0.0 bbPress (r2652)
1091 *
1092 * @param int $user_id Optional. User id
1093 *
1094 * @return array Return array of favorite topic ids, or empty array
1095 */
1096 function bbp_get_user_favorites_topic_ids( $user_id = 0 ) {
1097 return bbp_get_user_object_ids(
1098 array(
1099 'user_id' => $user_id,
1100 'rel_key' => '_bbp_favorite',
1101 'filter' => 'user_favorites_topic_ids'
1102 )
1103 );
1104 }
1105
1106 /**
1107 * Get a user's subscribed forum ids
1108 *
1109 * @since 2.5.0 bbPress (r5156)
1110 *
1111 * @param int $user_id Optional. User id
1112 *
1113 * @return array Return array of subscribed forum ids, or empty array
1114 */
1115 function bbp_get_user_subscribed_forum_ids( $user_id = 0 ) {
1116 return bbp_get_user_object_ids(
1117 array(
1118 'user_id' => $user_id,
1119 'rel_key' => '_bbp_subscription',
1120 'object_type' => bbp_get_forum_post_type(),
1121 'filter' => 'user_subscribed_forum_ids'
1122 )
1123 );
1124 }
1125
1126 /**
1127 * Get a user's subscribed topic ids
1128 *
1129 * @since 2.0.0 bbPress (r2668)
1130 *
1131 * @param int $user_id Optional. User id
1132 *
1133 * @return array Return array of subscribed topic ids, or empty array
1134 */
1135 function bbp_get_user_subscribed_topic_ids( $user_id = 0 ) {
1136 return bbp_get_user_object_ids(
1137 array(
1138 'user_id' => $user_id,
1139 'rel_key' => '_bbp_subscription',
1140 'filter' => 'user_subscribed_topic_ids'
1141 )
1142 );
1143 }
1144
1145 /** Deprecated ****************************************************************/
1146
1147 /**
1148 * Get a user's subscribed topics
1149 *
1150 * @since 2.0.0 bbPress (r2668)
1151 * @deprecated 2.5.0 bbPress (r5156)
1152 *
1153 * @param int $user_id Optional. User id
1154 *
1155 * @return array|bool Results if user has subscriptions, otherwise false
1156 */
1157 function bbp_get_user_subscriptions( $user_id = 0 ) {
1158 _deprecated_function( __FUNCTION__, '2.5', 'bbp_get_user_topic_subscriptions()' );
1159 $query = bbp_get_user_topic_subscriptions( $user_id );
1160
1161 // Filter & return
1162 return apply_filters( 'bbp_get_user_subscriptions', $query, $user_id );
1163 }
1164
1165 /**
1166 * Get the users who have subscribed to the forum
1167 *
1168 * @since 2.5.0 bbPress (r5156)
1169 * @deprecated 2.6.0 bbPress (r6543)
1170 *
1171 * @param int $forum_id Optional. forum id
1172 *
1173 * @return array|bool Results if the forum has any subscribers, otherwise false
1174 */
1175 function bbp_get_forum_subscribers( $forum_id = 0 ) {
1176 $users = bbp_get_users_for_object( $forum_id, '_bbp_subscription' );
1177
1178 // Filter & return
1179 return (array) apply_filters( 'bbp_get_forum_subscribers', $users, $forum_id );
1180 }
1181
1182 /**
1183 * Get the users who have subscribed to the topic
1184 *
1185 * @since 2.0.0 bbPress (r2668)
1186 * @deprecated 2.6.0 bbPress (r6543)
1187 *
1188 * @param int $topic_id Optional. Topic id
1189 *
1190 * @return array|bool Results if the topic has any subscribers, otherwise false
1191 */
1192 function bbp_get_topic_subscribers( $topic_id = 0 ) {
1193 $users = bbp_get_users_for_object( $topic_id, '_bbp_subscription' );
1194
1195 // Filter & return
1196 return (array) apply_filters( 'bbp_get_topic_subscribers', $users, $topic_id );
1197 }
1198
1199 /**
1200 * Check if a forum is in user's subscription list or not
1201 *
1202 * @since 2.5.0 bbPress (r5156)
1203 * @deprecated 2.6.0 bbPress (r6543)
1204 *
1205 * @param int $user_id Optional. User id
1206 * @param int $forum_id Optional. Forum id
1207 *
1208 * @return bool True if the forum is in user's subscriptions, otherwise false
1209 */
1210 function bbp_is_user_subscribed_to_forum( $user_id = 0, $forum_id = 0 ) {
1211 return bbp_is_user_subscribed( $user_id, $forum_id );
1212 }
1213
1214 /**
1215 * Check if a topic is in user's subscription list or not
1216 *
1217 * @since 2.5.0 bbPress (r5156)
1218 * @deprecated 2.6.0 bbPress (r6543) Use bbp_is_user_subscribed()
1219 *
1220 * @param int $user_id Optional. User id
1221 * @param int $topic_id Optional. Topic id
1222 * @return bool True if the topic is in user's subscriptions, otherwise false
1223 */
1224 function bbp_is_user_subscribed_to_topic( $user_id = 0, $topic_id = 0 ) {
1225 return bbp_is_user_subscribed( $user_id, $topic_id );
1226 }
1227
1228 /**
1229 * Remove a forum from user's subscriptions
1230 *
1231 * @since 2.5.0 bbPress (r5156)
1232 * @deprecated 2.6.0 bbPress (r6543)
1233 *
1234 * @param int $user_id Optional. User id
1235 * @param int $forum_id Optional. forum id
1236 * @return bool True if the forum was removed from user's subscriptions,
1237 * otherwise false
1238 */
1239 function bbp_remove_user_forum_subscription( $user_id = 0, $forum_id = 0 ) {
1240 return bbp_remove_user_subscription( $user_id, $forum_id );
1241 }
1242
1243 /**
1244 * Remove a topic from user's subscriptions
1245 *
1246 * @since 2.5.0 bbPress (r5156)
1247 * @deprecated 2.6.0 bbPress (r6543)
1248 *
1249 * @param int $user_id Optional. User id
1250 * @param int $topic_id Optional. Topic id
1251 * @return bool True if the topic was removed from user's subscriptions,
1252 * otherwise false
1253 */
1254 function bbp_remove_user_topic_subscription( $user_id = 0, $topic_id = 0 ) {
1255 return bbp_remove_user_subscription( $user_id, $topic_id );
1256 }
1257
1258 /**
1259 * Add a forum to user's subscriptions
1260 *
1261 * @since 2.5.0 bbPress (r5156)
1262 * @deprecated 2.6.0 bbPress (r6543)
1263 *
1264 * @param int $user_id Optional. User id
1265 * @param int $forum_id Optional. forum id
1266 * @return bool Always true
1267 */
1268 function bbp_add_user_forum_subscription( $user_id = 0, $forum_id = 0 ) {
1269 return bbp_add_user_subscription( $user_id, $forum_id );
1270 }
1271
1272 /**
1273 * Add a topic to user's subscriptions
1274 *
1275 * Note that both the User and Topic should be verified to exist before using
1276 * this function. Originally both were validated, but because this function is
1277 * frequently used within a loop, those verifications were moved upstream to
1278 * improve performance on topics with many engaged users.
1279 *
1280 * @since 2.5.0 bbPress (r5156)
1281 * @deprecated 2.6.0 bbPress (r6543)
1282 *
1283 * @param int $user_id Optional. User id
1284 * @param int $topic_id Optional. Topic id
1285 * @return bool Always true
1286 */
1287 function bbp_add_user_topic_subscription( $user_id = 0, $topic_id = 0 ) {
1288 return bbp_add_user_subscription( $user_id, $topic_id );
1289 }
1290
1291 /**
1292 * Handles the front end toggling of forum subscriptions
1293 *
1294 * @since 2.5.0 bbPress (r5156)
1295 * @deprecated 2.6.0 bbPress (r6543)
1296 */
1297 function bbp_forum_subscriptions_handler( $action = '' ) {
1298 return bbp_subscriptions_handler( $action );
1299 }
1300