PluginProbe
bbPress / 2.6.17
bbPress v2.6.17
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 2.2 2.2.1 All 72 releases
bbpress / includes / forums / functions.php

functions.php in bbPress 2.6.17, at includes/forums/functions.php

3,502 lines 103.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress Forum Functions
5 *
6 * @package bbPress
7 * @subpackage Functions
8 */
9
10 // Exit if accessed directly
11 defined( 'ABSPATH' ) || exit;
12
13 /** Insert ********************************************************************/
14
15 /**
16 * A wrapper for wp_insert_post() that also includes the necessary meta values
17 * for the forum to function properly.
18 *
19 * @since 2.0.0 bbPress (r3349)
20 *
21 * @param array $forum_data Forum post data
22 * @param array $forum_meta Forum meta data
23 */
24 function bbp_insert_forum( $forum_data = array(), $forum_meta = array() ) {
25
26 // Forum
27 $forum_data = bbp_parse_args(
28 $forum_data,
29 array(
30 'post_parent' => 0, // forum ID
31 'post_status' => bbp_get_public_status_id(),
32 'post_type' => bbp_get_forum_post_type(),
33 'post_author' => bbp_get_current_user_id(),
34 'post_password' => '',
35 'post_content' => '',
36 'post_title' => '',
37 'menu_order' => 0,
38 'comment_status' => 'closed'
39 ),
40 'insert_forum'
41 );
42
43 // Insert forum
44 $forum_id = wp_insert_post( $forum_data, false );
45
46 // Bail if no forum was added
47 if ( empty( $forum_id ) ) {
48 return false;
49 }
50
51 // Forum meta
52 $forum_meta = bbp_parse_args(
53 $forum_meta,
54 array(
55 'forum_type' => 'forum',
56 'status' => 'open',
57 'reply_count' => 0,
58 'topic_count' => 0,
59 'topic_count_hidden' => 0,
60 'total_reply_count' => 0,
61 'total_topic_count' => 0,
62 'last_topic_id' => 0,
63 'last_reply_id' => 0,
64 'last_active_id' => 0,
65 'last_active_time' => 0,
66 'forum_subforum_count' => 0,
67 ),
68 'insert_forum_meta'
69 );
70
71 // Insert forum meta
72 foreach ( $forum_meta as $meta_key => $meta_value ) {
73
74 // Prefix if not prefixed
75 if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
76 $meta_key = '_bbp_' . $meta_key;
77 }
78
79 // Update the meta
80 update_post_meta( $forum_id, $meta_key, $meta_value );
81 }
82
83 // Update the forum and hierarchy
84 bbp_update_forum(
85 array(
86 'forum_id' => $forum_id,
87 'post_parent' => $forum_data['post_parent']
88 )
89 );
90
91 // Maybe make private
92 if ( bbp_is_forum_private( $forum_id, false ) ) {
93 bbp_privatize_forum( $forum_id );
94
95 // Maybe make hidden
96 } elseif ( bbp_is_forum_hidden( $forum_id, false ) ) {
97 bbp_hide_forum( $forum_id );
98
99 // Publicize
100 } else {
101 bbp_publicize_forum( $forum_id );
102 }
103
104 /**
105 * Fires after forum has been inserted via `bbp_insert_forum`.
106 *
107 * @since 2.6.0 bbPress (r6036)
108 *
109 * @param int $forum_id The forum id.
110 */
111 do_action( 'bbp_insert_forum', (int) $forum_id );
112
113 // Bump the last changed cache
114 wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
115
116 // Return forum_id
117 return $forum_id;
118 }
119
120 /** Post Form Handlers ********************************************************/
121
122 /**
123 * Handles the front end forum submission
124 *
125 * @param string $action The requested action to compare this function to
126 */
127 function bbp_new_forum_handler( $action = '' ) {
128
129 // Bail if action is not bbp-new-forum
130 if ( 'bbp-new-forum' !== $action ) {
131 return;
132 }
133
134 // Nonce check
135 if ( ! bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
136 bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
137 return;
138 }
139
140 // Define local variable(s)
141 $view_all = false;
142 $forum_parent_id = $forum_author = 0;
143 $forum_title = $forum_content = '';
144 $anonymous_data = array();
145
146 /** Forum Author **********************************************************/
147
148 // User cannot create forums
149 if ( ! current_user_can( 'publish_forums' ) ) {
150 bbp_add_error( 'bbp_forum_permission', __( '<strong>Error</strong>: You do not have permission to create new forums.', 'bbpress' ) );
151 return;
152 }
153
154 // Forum author is current user
155 $forum_author = bbp_get_current_user_id();
156
157 // Remove kses filters from title and content for capable users and if the nonce is verified
158 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) === $_POST['_bbp_unfiltered_html_forum'] ) {
159 remove_filter( 'bbp_new_forum_pre_title', 'wp_filter_kses' );
160 remove_filter( 'bbp_new_forum_pre_content', 'bbp_encode_bad', 10 );
161 remove_filter( 'bbp_new_forum_pre_content', 'bbp_filter_kses', 30 );
162 }
163
164 /** Forum Title ***********************************************************/
165
166 if ( ! empty( $_POST['bbp_forum_title'] ) ) {
167 $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
168 }
169
170 // Filter and sanitize
171 $forum_title = apply_filters( 'bbp_new_forum_pre_title', $forum_title );
172
173 // No forum title
174 if ( empty( $forum_title ) ) {
175 bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
176 }
177
178 // Title too long
179 if ( bbp_is_title_too_long( $forum_title ) ) {
180 bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
181 }
182
183 /** Forum Content *********************************************************/
184
185 if ( ! empty( $_POST['bbp_forum_content'] ) ) {
186 $forum_content = $_POST['bbp_forum_content'];
187 }
188
189 // Filter and sanitize
190 $forum_content = apply_filters( 'bbp_new_forum_pre_content', $forum_content );
191
192 // No forum content
193 if ( empty( $forum_content ) ) {
194 bbp_add_error( 'bbp_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
195 }
196
197 /** Forum Parent **********************************************************/
198
199 // Forum parent was passed (the norm)
200 if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
201 $forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
202 }
203
204 // Filter and sanitize
205 $forum_parent_id = apply_filters( 'bbp_new_forum_pre_parent_id', $forum_parent_id );
206
207 // No forum parent was passed (should never happen)
208 if ( empty( $forum_parent_id ) ) {
209 bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>Error</strong>: Your forum must have a parent.', 'bbpress' ) );
210
211 // Forum exists
212 } elseif ( ! empty( $forum_parent_id ) ) {
213
214 // Forum is a category
215 if ( bbp_is_forum_category( $forum_parent_id ) ) {
216 bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>Error</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
217 }
218
219 // Forum is closed and user cannot access
220 if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
221 bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
222 }
223
224 // Forum is private and user cannot access
225 if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
226 bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
227 }
228
229 // Forum is hidden and user cannot access
230 if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
231 bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
232 }
233 }
234
235 /** Forum Flooding ********************************************************/
236
237 if ( ! bbp_check_for_flood( $anonymous_data, $forum_author ) ) {
238 bbp_add_error( 'bbp_forum_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
239 }
240
241 /** Forum Duplicate *******************************************************/
242
243 $dupe_args = array(
244 'post_type' => bbp_get_forum_post_type(),
245 'post_author' => $forum_author,
246 'post_content' => $forum_content,
247 'post_parent' => $forum_parent_id,
248 'anonymous_data' => $anonymous_data
249 );
250
251 if ( ! bbp_check_for_duplicate( $dupe_args ) ) {
252 bbp_add_error( 'bbp_forum_duplicate', __( '<strong>Error</strong>: This forum already exists.', 'bbpress' ) );
253 }
254
255 /** Forum Bad Words *******************************************************/
256
257 if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content, true ) ) {
258 bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
259 }
260
261 /** Forum Moderation ******************************************************/
262
263 // Default to published
264 $forum_status = bbp_get_public_status_id();
265
266 // Maybe force into pending
267 if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) ) {
268 $forum_status = bbp_get_pending_status_id();
269 }
270
271 /** Additional Actions (Before Save) **************************************/
272
273 do_action( 'bbp_new_forum_pre_extras', $forum_parent_id );
274
275 // Bail if errors
276 if ( bbp_has_errors() ) {
277 return;
278 }
279
280 /** No Errors *************************************************************/
281
282 // Add the content of the form to $forum_data as an array
283 // Just in time manipulation of forum data before being created
284 $forum_data = apply_filters(
285 'bbp_new_forum_pre_insert',
286 array(
287 'post_author' => $forum_author,
288 'post_title' => $forum_title,
289 'post_content' => $forum_content,
290 'post_parent' => $forum_parent_id,
291 'post_status' => $forum_status,
292 'post_type' => bbp_get_forum_post_type(),
293 'comment_status' => 'closed'
294 )
295 );
296
297 // Insert forum
298 $forum_id = wp_insert_post( $forum_data, true );
299
300 /** No Errors *************************************************************/
301
302 if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
303
304 /** Trash Check *******************************************************/
305
306 // If the forum is trash, or the forum_status is switched to
307 // trash, trash it properly
308 if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( bbp_get_trash_status_id() === $forum_data['post_status'] ) ) {
309
310 // Trash the reply
311 wp_trash_post( $forum_id );
312
313 // Force view=all
314 $view_all = true;
315 }
316
317 /** Spam Check ********************************************************/
318
319 // If reply or forum are spam, officially spam this reply
320 if ( bbp_get_spam_status_id() === $forum_data['post_status'] ) {
321 add_post_meta( $forum_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
322
323 // Force view=all
324 $view_all = true;
325 }
326
327 /** Update counts, etc... *********************************************/
328
329 do_action(
330 'bbp_new_forum',
331 array(
332 'forum_id' => $forum_id,
333 'post_parent' => $forum_data['post_parent'],
334 'forum_author' => $forum_data['post_author'],
335 'last_topic_id' => 0,
336 'last_reply_id' => 0,
337 'last_active_id' => 0,
338 'last_active_time' => 0,
339 'last_active_status' => bbp_get_public_status_id()
340 )
341 );
342
343 /** Additional Actions (After Save) ***********************************/
344
345 do_action( 'bbp_new_forum_post_extras', $forum_id );
346
347 /** Redirect **********************************************************/
348
349 // Redirect to
350 $redirect_to = bbp_get_redirect_to();
351
352 // Get the forum URL
353 $redirect_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
354
355 // Add view all?
356 if ( bbp_get_view_all() || ! empty( $view_all ) ) {
357
358 // User can moderate, so redirect to forum with view all set
359 if ( current_user_can( 'moderate', $forum_id ) ) {
360 $redirect_url = bbp_add_view_all( $redirect_url );
361
362 // User cannot moderate, so redirect to forum
363 } else {
364 $redirect_url = bbp_get_forum_permalink( $forum_id );
365 }
366 }
367
368 // Allow to be filtered
369 $redirect_url = apply_filters( 'bbp_new_forum_redirect_to', $redirect_url, $redirect_to );
370
371 /** Successful Save ***************************************************/
372
373 // Redirect back to new forum
374 bbp_redirect( $redirect_url );
375
376 /** Errors ****************************************************************/
377
378 // WP_Error
379
380 } elseif ( is_wp_error( $forum_id ) ) {
381 bbp_add_error(
382 'bbp_forum_error',
383 sprintf( /* translators: %s: Error message(s) */ __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ),
384 $forum_id->get_error_message()
385 )
386 );
387
388 // Generic error
389 } else {
390 bbp_add_error( 'bbp_forum_error', __( '<strong>Error</strong>: The forum was not created.', 'bbpress' ) );
391 }
392 }
393
394 /**
395 * Handles the front end edit forum submission
396 *
397 * @param string $action The requested action to compare this function to
398 */
399 function bbp_edit_forum_handler( $action = '' ) {
400
401 // Bail if action is not bbp-edit-forum
402 if ( 'bbp-edit-forum' !== $action ) {
403 return;
404 }
405
406 // Define local variable(s)
407 $anonymous_data = array();
408 $forum = $forum_id = $forum_author = $forum_parent_id = 0;
409 $forum_title = $forum_content = $forum_edit_reason = '';
410
411 /** Forum *****************************************************************/
412
413 // Forum id was not passed
414 if ( empty( $_POST['bbp_forum_id'] ) ) {
415 bbp_add_error( 'bbp_edit_forum_id', __( '<strong>Error</strong>: Forum ID not found.', 'bbpress' ) );
416 return;
417
418 // Forum id was passed
419 } elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
420 $forum_id = (int) $_POST['bbp_forum_id'];
421 $forum = bbp_get_forum( $forum_id );
422 }
423
424 // Nonce check
425 if ( ! bbp_verify_nonce_request( 'bbp-edit-forum_' . $forum_id ) ) {
426 bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
427 return;
428
429 // Forum does not exist
430 } elseif ( empty( $forum ) ) {
431 bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>Error</strong>: The forum you want to edit was not found.', 'bbpress' ) );
432 return;
433
434 // User cannot edit this forum
435 } elseif ( ! current_user_can( 'edit_forum', $forum_id ) ) {
436 bbp_add_error( 'bbp_edit_forum_permission', __( '<strong>Error</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
437 return;
438 }
439
440 // Remove kses filters from title and content for capable users and if the nonce is verified
441 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) === $_POST['_bbp_unfiltered_html_forum'] ) ) {
442 remove_filter( 'bbp_edit_forum_pre_title', 'wp_filter_kses' );
443 remove_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad', 10 );
444 remove_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
445 }
446
447 // Get forum author
448 $forum_author = bbp_get_forum_author_id( $forum_id );
449
450 /** Forum Parent ***********************************************************/
451
452 // Current forum this forum is in
453 $current_parent_forum_id = bbp_get_forum_parent_id( $forum_id );
454
455 // Only users who can assign forum moderators can change forum structure
456 if ( current_user_can( 'assign_moderators' ) ) {
457 $forum_parent_id = ! empty( $_POST['bbp_forum_parent_id'] )
458 ? bbp_get_forum_id( $_POST['bbp_forum_parent_id'] )
459 : 0;
460 } else {
461 $forum_parent_id = $current_parent_forum_id;
462 }
463
464 // Forum exists
465 if ( ! empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {
466
467 // Forum is closed and user cannot access
468 if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
469 bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
470 }
471
472 // Forum is private and user cannot access
473 if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
474 bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
475 }
476
477 // Forum is hidden and user cannot access
478 if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
479 bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
480 }
481 }
482
483 /** Forum Title ***********************************************************/
484
485 if ( ! empty( $_POST['bbp_forum_title'] ) ) {
486 $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
487 }
488
489 // Filter and sanitize
490 $forum_title = apply_filters( 'bbp_edit_forum_pre_title', $forum_title, $forum_id );
491
492 // No forum title
493 if ( empty( $forum_title ) ) {
494 bbp_add_error( 'bbp_edit_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
495 }
496
497 // Title too long
498 if ( bbp_is_title_too_long( $forum_title ) ) {
499 bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
500 }
501
502 /** Forum Content *********************************************************/
503
504 if ( ! empty( $_POST['bbp_forum_content'] ) ) {
505 $forum_content = $_POST['bbp_forum_content'];
506 }
507
508 // Filter and sanitize
509 $forum_content = apply_filters( 'bbp_edit_forum_pre_content', $forum_content, $forum_id );
510
511 // No forum content
512 if ( empty( $forum_content ) ) {
513 bbp_add_error( 'bbp_edit_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
514 }
515
516 /** Forum Bad Words *******************************************************/
517
518 if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content, true ) ) {
519 bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
520 }
521
522 /** Forum Moderation ******************************************************/
523
524 // Use existing post_status
525 $forum_status = $forum->post_status;
526
527 // Maybe force into pending
528 if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) ) {
529 $forum_status = bbp_get_pending_status_id();
530 }
531
532 /** Additional Actions (Before Save) **************************************/
533
534 do_action( 'bbp_edit_forum_pre_extras', $forum_id );
535
536 // Bail if errors
537 if ( bbp_has_errors() ) {
538 return;
539 }
540
541 /** No Errors *************************************************************/
542
543 // Add the content of the form to $forum_data as an array
544 // Just in time manipulation of forum data before being edited
545 $forum_data = apply_filters(
546 'bbp_edit_forum_pre_insert',
547 array(
548 'ID' => $forum_id,
549 'post_title' => $forum_title,
550 'post_content' => $forum_content,
551 'post_status' => $forum_status,
552 'post_parent' => $forum_parent_id,
553 'post_author' => $forum_author
554 )
555 );
556
557 // Insert forum
558 $forum_id = wp_update_post( $forum_data );
559
560 /** No Errors *************************************************************/
561
562 if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
563
564 // Update counts, etc...
565 do_action(
566 'bbp_edit_forum',
567 array(
568 'forum_id' => $forum_id,
569 'post_parent' => $forum_data['post_parent'],
570 'forum_author' => $forum_data['post_author'],
571 'last_topic_id' => 0,
572 'last_reply_id' => 0,
573 'last_active_id' => 0,
574 'last_active_time' => 0,
575 'last_active_status' => bbp_get_public_status_id()
576 )
577 );
578
579 /** Revisions *********************************************************/
580
581 // Update locks
582 update_post_meta( $forum_id, '_edit_last', bbp_get_current_user_id() );
583 delete_post_meta( $forum_id, '_edit_lock' );
584
585 /**
586 * @todo omitted for now
587 // Revision Reason
588 if ( ! empty( $_POST['bbp_forum_edit_reason'] ) )
589 $forum_edit_reason = sanitize_text_field( $_POST['bbp_forum_edit_reason'] );
590
591 // Update revision log
592 if ( ! empty( $_POST['bbp_log_forum_edit'] ) && ( "1" === $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
593 bbp_update_forum_revision_log( array(
594 'forum_id' => $forum_id,
595 'revision_id' => $revision_id,
596 'author_id' => bbp_get_current_user_id(),
597 'reason' => $forum_edit_reason
598 ) );
599 }
600
601 // If the new forum parent id is not equal to the old forum parent
602 // id, run the bbp_move_forum action and pass the forum's parent id
603 // as the first argument and new forum parent id as the second.
604 // @todo implement
605 if ( $forum_id !== $forum->post_parent ) {
606 bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
607 }
608
609 */
610
611 /** Additional Actions (After Save) ***********************************/
612
613 do_action( 'bbp_edit_forum_post_extras', $forum_id );
614
615 /** Redirect **********************************************************/
616
617 // Redirect to
618 $redirect_to = bbp_get_redirect_to();
619
620 // View all?
621 $view_all = bbp_get_view_all();
622
623 // Get the forum URL
624 $forum_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
625
626 // Add view all?
627 if ( ! empty( $view_all ) ) {
628 $forum_url = bbp_add_view_all( $forum_url );
629 }
630
631 // Allow to be filtered
632 $forum_url = apply_filters( 'bbp_edit_forum_redirect_to', $forum_url, $view_all, $redirect_to );
633
634 /** Successful Edit ***************************************************/
635
636 // Redirect back to new forum
637 bbp_redirect( $forum_url );
638
639 /** Errors ****************************************************************/
640
641 } else {
642 $append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
643 bbp_add_error(
644 'bbp_forum_error',
645 sprintf(
646 /* translators: %s: Error message */
647 __( '<strong>Error</strong>: The following problem(s) have been found with your forum: %sPlease try again.', 'bbpress' ),
648 $append_error
649 )
650 );
651 }
652 }
653
654 /**
655 * Filter forum data submitted through the WordPress administration area.
656 *
657 * @since 2.6.17 bbPress
658 *
659 * @param array $data Sanitized post data.
660 * @param array $postarr Raw post data.
661 * @return array Filtered post data.
662 */
663 function bbp_filter_admin_forum_post_data( $data = array(), $postarr = array() ) {
664
665 // Bail unless an existing forum is being updated in wp-admin
666 if ( ! is_admin() || empty( $postarr['ID'] ) || empty( $data['post_type'] ) || ( bbp_get_forum_post_type() !== $data['post_type'] ) ) {
667 return $data;
668 }
669
670 $forum_id = bbp_get_forum_id( $postarr['ID'] );
671 $forum = bbp_get_forum( $forum_id );
672
673 if ( empty( $forum ) ) {
674 return $data;
675 }
676
677 // Preserve structure unless the user can assign forum moderators
678 if ( ! current_user_can( 'assign_moderators' ) ) {
679 $data['post_parent'] = $forum->post_parent;
680 $data['menu_order'] = $forum->menu_order;
681 }
682
683 // Preserve visibility unless the user can manage forum attributes
684 if ( ! current_user_can( 'manage_forum_attributes', $forum_id ) ) {
685 $data['post_status'] = $forum->post_status;
686 }
687
688 return $data;
689 }
690
691 /**
692 * Handle the saving of core forum metadata (Status, Visibility, and Type)
693 *
694 * @since 2.1.0 bbPress (r3678)
695 *
696 * @param int $forum_id
697 * @return If forum ID is empty
698 */
699 function bbp_save_forum_extras( $forum_id = 0 ) {
700
701 // Validate the forum ID
702 $forum_id = bbp_get_forum_id( $forum_id );
703
704 // Bail if forum ID is empty
705 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
706 return;
707 }
708
709 /** Forum Status **********************************************************/
710
711 if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ), true ) ) {
712 if ( 'closed' === $_POST['bbp_forum_status'] && ! bbp_is_forum_closed( $forum_id, false ) ) {
713 bbp_close_forum( $forum_id );
714 } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_open( $forum_id, false ) ) {
715 bbp_open_forum( $forum_id );
716 } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
717 bbp_open_forum( $forum_id );
718 }
719 }
720
721 /** Forum Type ************************************************************/
722
723 if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ), true ) ) {
724 if ( 'category' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
725 bbp_categorize_forum( $forum_id );
726 } elseif ( 'forum' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
727 bbp_normalize_forum( $forum_id );
728 } elseif ( 'forum' === $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
729 bbp_normalize_forum( $forum_id );
730 }
731 }
732
733 /** Forum Visibility ******************************************************/
734
735 if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array_keys( bbp_get_forum_visibilities() ), true ) ) {
736
737 // Get forums current visibility
738 $old_visibility = bbp_get_forum_visibility( $forum_id );
739
740 // Sanitize the new visibility
741 $new_visibility = sanitize_key( $_POST['bbp_forum_visibility'] );
742
743 // What is the new forum visibility setting?
744 switch ( $new_visibility ) {
745
746 // Hidden
747 case bbp_get_hidden_status_id() :
748 bbp_hide_forum( $forum_id, $old_visibility );
749 break;
750
751 // Private
752 case bbp_get_private_status_id() :
753 bbp_privatize_forum( $forum_id, $old_visibility );
754 break;
755
756 // Publish (default)
757 case bbp_get_public_status_id() :
758 default :
759 bbp_publicize_forum( $forum_id, $old_visibility );
760 break;
761 }
762
763 /**
764 * Allow custom forum visibility save actions
765 *
766 * @since 2.6.0 bbPress (r5855)
767 *
768 * @param int $forum_id The forum ID
769 * @param string $old_visibility The current forum visibility
770 * @param string $new_visibility The new forum visibility
771 */
772 do_action( 'bbp_update_forum_visibility', $forum_id, $old_visibility, $new_visibility );
773 }
774
775 /** Forum Moderators ******************************************************/
776
777 // Either replace terms
778 if ( bbp_allow_forum_mods() && current_user_can( 'assign_moderators' ) ) {
779 if ( ! empty( $_POST['bbp_moderators'] ) ) {
780
781 // Escape tag input
782 $users = sanitize_text_field( $_POST['bbp_moderators'] );
783 $user_ids = bbp_get_user_ids_from_nicenames( $users );
784
785 // Update forum moderators
786 if ( ! empty( $user_ids ) ) {
787
788 // Remove all moderators
789 bbp_remove_moderator( $forum_id, null );
790
791 // Add moderators
792 foreach ( $user_ids as $user_id ) {
793 bbp_add_moderator( $forum_id, $user_id );
794 }
795 }
796
797 // ...or remove them.
798 } elseif ( isset( $_POST['bbp_moderators'] ) ) {
799 bbp_remove_moderator( $forum_id, null );
800 }
801 }
802 }
803
804 /** Forum Open/Close **********************************************************/
805
806 /**
807 * Closes a forum
808 *
809 * @since 2.0.0 bbPress (r2746)
810 *
811 * @param int $forum_id forum id
812 * @return mixed False or {@link WP_Error} on failure, forum id on success
813 */
814 function bbp_close_forum( $forum_id = 0 ) {
815
816 $forum_id = bbp_get_forum_id( $forum_id );
817
818 do_action( 'bbp_close_forum', $forum_id );
819
820 update_post_meta( $forum_id, '_bbp_status', 'closed' );
821
822 do_action( 'bbp_closed_forum', $forum_id );
823
824 return $forum_id;
825 }
826
827 /**
828 * Opens a forum
829 *
830 * @since 2.0.0 bbPress (r2746)
831 *
832 * @param int $forum_id forum id
833 * @return mixed False or {@link WP_Error} on failure, forum id on success
834 */
835 function bbp_open_forum( $forum_id = 0 ) {
836
837 $forum_id = bbp_get_forum_id( $forum_id );
838
839 do_action( 'bbp_open_forum', $forum_id );
840
841 update_post_meta( $forum_id, '_bbp_status', 'open' );
842
843 do_action( 'bbp_opened_forum', $forum_id );
844
845 return $forum_id;
846 }
847
848 /** Forum Type ****************************************************************/
849
850 /**
851 * Make the forum a category
852 *
853 * @since 2.0.0 bbPress (r2746)
854 *
855 * @param int $forum_id Optional. Forum id
856 * @return bool False on failure, true on success
857 */
858 function bbp_categorize_forum( $forum_id = 0 ) {
859
860 $forum_id = bbp_get_forum_id( $forum_id );
861
862 do_action( 'bbp_categorize_forum', $forum_id );
863
864 update_post_meta( $forum_id, '_bbp_forum_type', 'category' );
865
866 do_action( 'bbp_categorized_forum', $forum_id );
867
868 return $forum_id;
869 }
870
871 /**
872 * Remove the category status from a forum
873 *
874 * @since 2.0.0 bbPress (r2746)
875 *
876 * @param int $forum_id Optional. Forum id
877 * @return bool False on failure, true on success
878 */
879 function bbp_normalize_forum( $forum_id = 0 ) {
880
881 $forum_id = bbp_get_forum_id( $forum_id );
882
883 do_action( 'bbp_normalize_forum', $forum_id );
884
885 update_post_meta( $forum_id, '_bbp_forum_type', 'forum' );
886
887 do_action( 'bbp_normalized_forum', $forum_id );
888
889 return $forum_id;
890 }
891
892 /** Forum Visibility **********************************************************/
893
894 /**
895 * Mark the forum as public
896 *
897 * @since 2.0.0 bbPress (r2746)
898 *
899 * @param int $forum_id Optional. Forum id
900 * @return bool False on failure, true on success
901 */
902 function bbp_publicize_forum( $forum_id = 0, $current_visibility = '' ) {
903
904 $forum_id = bbp_get_forum_id( $forum_id );
905
906 do_action( 'bbp_publicize_forum', $forum_id );
907
908 // Get private forums
909 $private = bbp_get_private_forum_ids();
910
911 // Find this forum in the array
912 if ( in_array( $forum_id, $private, true ) ) {
913
914 $offset = array_search( $forum_id, $private, true );
915
916 // Splice around it
917 array_splice( $private, $offset, 1 );
918
919 // Update private forums minus this one
920 update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
921 }
922
923 // Get hidden forums
924 $hidden = bbp_get_hidden_forum_ids();
925
926 // Find this forum in the array
927 if ( in_array( $forum_id, $hidden, true ) ) {
928
929 $offset = array_search( $forum_id, $hidden, true );
930
931 // Splice around it
932 array_splice( $hidden, $offset, 1 );
933
934 // Update hidden forums minus this one
935 update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
936 }
937
938 // Only run queries if visibility is changing
939 if ( bbp_get_public_status_id() !== $current_visibility ) {
940 $bbp_db = bbp_db();
941 $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
942 wp_transition_post_status( bbp_get_public_status_id(), $current_visibility, get_post( $forum_id ) );
943 clean_post_cache( $forum_id );
944 }
945
946 do_action( 'bbp_publicized_forum', $forum_id );
947
948 return $forum_id;
949 }
950
951 /**
952 * Mark the forum as private
953 *
954 * @since 2.0.0 bbPress (r2746)
955 *
956 * @param int $forum_id Optional. Forum id
957 * @return bool False on failure, true on success
958 */
959 function bbp_privatize_forum( $forum_id = 0, $current_visibility = '' ) {
960
961 $forum_id = bbp_get_forum_id( $forum_id );
962
963 do_action( 'bbp_privatize_forum', $forum_id );
964
965 // Only run queries if visibility is changing
966 if ( bbp_get_private_status_id() !== $current_visibility ) {
967
968 // Get hidden forums
969 $hidden = bbp_get_hidden_forum_ids();
970
971 // Find this forum in the array
972 if ( in_array( $forum_id, $hidden, true ) ) {
973
974 $offset = array_search( $forum_id, $hidden, true );
975
976 // Splice around it
977 array_splice( $hidden, $offset, 1 );
978
979 // Update hidden forums minus this one
980 update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
981 }
982
983 // Add to '_bbp_private_forums' site option
984 $private = bbp_get_private_forum_ids();
985 $private[] = $forum_id;
986 update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
987
988 // Update forums visibility setting
989 $bbp_db = bbp_db();
990 $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
991 wp_transition_post_status( bbp_get_private_status_id(), $current_visibility, get_post( $forum_id ) );
992 clean_post_cache( $forum_id );
993 }
994
995 do_action( 'bbp_privatized_forum', $forum_id );
996
997 return $forum_id;
998 }
999
1000 /**
1001 * Mark the forum as hidden
1002 *
1003 * @since 2.0.0 bbPress (r2996)
1004 *
1005 * @param int $forum_id Optional. Forum id
1006 * @return bool False on failure, true on success
1007 */
1008 function bbp_hide_forum( $forum_id = 0, $current_visibility = '' ) {
1009
1010 $forum_id = bbp_get_forum_id( $forum_id );
1011
1012 do_action( 'bbp_hide_forum', $forum_id );
1013
1014 // Only run queries if visibility is changing
1015 if ( bbp_get_hidden_status_id() !== $current_visibility ) {
1016
1017 // Get private forums
1018 $private = bbp_get_private_forum_ids();
1019
1020 // Find this forum in the array
1021 if ( in_array( $forum_id, $private, true ) ) {
1022
1023 $offset = array_search( $forum_id, $private, true );
1024
1025 // Splice around it
1026 array_splice( $private, $offset, 1 );
1027
1028 // Update private forums minus this one
1029 update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
1030 }
1031
1032 // Add to '_bbp_hidden_forums' site option
1033 $hidden = bbp_get_hidden_forum_ids();
1034 $hidden[] = $forum_id;
1035 update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
1036
1037 // Update forums visibility setting
1038 $bbp_db = bbp_db();
1039 $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
1040 wp_transition_post_status( bbp_get_hidden_status_id(), $current_visibility, get_post( $forum_id ) );
1041 clean_post_cache( $forum_id );
1042 }
1043
1044 do_action( 'bbp_hid_forum', $forum_id );
1045
1046 return $forum_id;
1047 }
1048
1049 /**
1050 * Recaches the private and hidden forums
1051 *
1052 * @since 2.4.0 bbPress (r5017)
1053 *
1054 * @return array An array of the status code and the message
1055 */
1056 function bbp_repair_forum_visibility() {
1057
1058 // First, delete everything.
1059 delete_option( '_bbp_private_forums' );
1060 delete_option( '_bbp_hidden_forums' );
1061
1062 /**
1063 * Don't search for both private/hidden statuses. Since 'pre_get_posts' is an
1064 * action, it's not removed by suppress_filters. We need to make sure that
1065 * we're only searching for the supplied post_status.
1066 *
1067 * @see https://bbpress.trac.wordpress.org/ticket/2512
1068 */
1069 remove_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
1070
1071 // Query for private forums
1072 $private_forums = new WP_Query(
1073 array(
1074 'fields' => 'ids',
1075 'post_type' => bbp_get_forum_post_type(),
1076 'post_status' => bbp_get_private_status_id(),
1077 'posts_per_page' => -1,
1078
1079 // Performance
1080 'nopaging' => true,
1081 'suppress_filters' => true,
1082 'update_post_term_cache' => false,
1083 'update_post_meta_cache' => false,
1084 'ignore_sticky_posts' => true,
1085 'no_found_rows' => true
1086 )
1087 );
1088
1089 // Query for hidden forums
1090 $hidden_forums = new WP_Query(
1091 array(
1092 'fields' => 'ids',
1093 'post_type' => bbp_get_forum_post_type(),
1094 'post_status' => bbp_get_hidden_status_id(),
1095 'posts_per_page' => -1,
1096
1097 // Performance
1098 'nopaging' => true,
1099 'suppress_filters' => true,
1100 'update_post_term_cache' => false,
1101 'update_post_meta_cache' => false,
1102 'ignore_sticky_posts' => true,
1103 'no_found_rows' => true
1104 )
1105 );
1106
1107 // Enable forum visibilty normalization
1108 add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
1109
1110 // Reset the $post global
1111 wp_reset_postdata();
1112
1113 // Private
1114 if ( ! is_wp_error( $private_forums ) ) {
1115 update_option( '_bbp_private_forums', $private_forums->posts );
1116 }
1117
1118 // Hidden forums
1119 if ( ! is_wp_error( $hidden_forums ) ) {
1120 update_option( '_bbp_hidden_forums', $hidden_forums->posts );
1121 }
1122
1123 // Complete results
1124 return true;
1125 }
1126
1127 /** Subscriptions *************************************************************/
1128
1129 /**
1130 * Remove a deleted forum from all user subscriptions
1131 *
1132 * @since 2.5.0 bbPress (r5156)
1133 *
1134 * @param int $forum_id Get the forum ID to remove
1135 */
1136 function bbp_remove_forum_from_all_subscriptions( $forum_id = 0 ) {
1137
1138 // Subscriptions are not active
1139 if ( ! bbp_is_subscriptions_active() ) {
1140 return;
1141 }
1142
1143 // Bail if no forum
1144 $forum_id = bbp_get_forum_id( $forum_id );
1145 if ( empty( $forum_id ) ) {
1146 return;
1147 }
1148
1149 // Remove forum from all subscriptions
1150 return bbp_remove_object_from_all_users( $forum_id, '_bbp_subscription', 'post' );
1151 }
1152
1153 /** Count Bumpers *************************************************************/
1154
1155 /**
1156 * Bump the total topic count of a forum
1157 *
1158 * @since 2.1.0 bbPress (r3825)
1159 * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1160 *
1161 * @param int $forum_id Optional. Forum id.
1162 * @param int $difference Optional. Default 1
1163 * @param bool $update_ancestors Optional. Default true
1164 *
1165 * @return int Forum topic count
1166 */
1167 function bbp_bump_forum_topic_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1168
1169 // Bail if no bump
1170 if ( empty( $difference ) ) {
1171 return false;
1172 }
1173
1174 // Get some counts
1175 $forum_id = bbp_get_forum_id( $forum_id );
1176 $topic_count = bbp_get_forum_topic_count( $forum_id, false, true );
1177 $total_topic_count = bbp_get_forum_topic_count( $forum_id, true, true );
1178 $difference = (int) $difference;
1179
1180 // Update this forum id
1181 bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count', $difference, $topic_count );
1182 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count', $difference, $total_topic_count );
1183
1184 // Check for ancestors
1185 if ( true === $update_ancestors ) {
1186
1187 // Get post ancestors
1188 $forum = get_post( $forum_id );
1189 $ancestors = get_post_ancestors( $forum );
1190
1191 // If has ancestors, loop through them...
1192 if ( ! empty( $ancestors ) ) {
1193 foreach ( (array) $ancestors as $parent_forum_id ) {
1194
1195 // Only update topic count when an ancestor is not a category.
1196 if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1197
1198 $parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, true );
1199 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count', $difference, $parent_topic_count );
1200 }
1201
1202 // Update the total topic count.
1203 $parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true, true );
1204 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count', $difference, $parent_total_topic_count );
1205 }
1206 }
1207 }
1208
1209 $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference );
1210
1211 // Filter & return
1212 return (int) apply_filters( 'bbp_bump_forum_topic_count', $forum_topic_count, $forum_id, $difference, $update_ancestors );
1213 }
1214
1215 /**
1216 * Increase the total topic count of a forum by one.
1217 *
1218 * @since 2.6.0 bbPress (r6036)
1219 *
1220 * @param int $forum_id The forum id.
1221 * @return void
1222 */
1223 function bbp_increase_forum_topic_count( $forum_id = 0 ) {
1224
1225 // Bail early if no id is passed.
1226 if ( empty( $forum_id ) ) {
1227 return;
1228 }
1229
1230 // If it's a topic, get the forum id.
1231 if ( bbp_is_topic( $forum_id ) ) {
1232 $topic_id = $forum_id;
1233 $forum_id = bbp_get_topic_forum_id( $topic_id );
1234
1235 // Update inverse based on item status
1236 if ( ! bbp_is_topic_public( $topic_id ) ) {
1237 bbp_increase_forum_topic_count_hidden( $forum_id );
1238 return;
1239 }
1240 }
1241
1242 // Bump up
1243 bbp_bump_forum_topic_count( $forum_id );
1244 }
1245
1246 /**
1247 * Decrease the total topic count of a forum by one.
1248 *
1249 * @since 2.6.0 bbPress (r6036)
1250 *
1251 * @param int $forum_id The forum id.
1252 *
1253 * @return void
1254 */
1255 function bbp_decrease_forum_topic_count( $forum_id = 0 ) {
1256
1257 // Bail early if no id is passed.
1258 if ( empty( $forum_id ) ) {
1259 return;
1260 }
1261
1262 // If it's a topic, get the forum id.
1263 if ( bbp_is_topic( $forum_id ) ) {
1264 $topic_id = $forum_id;
1265 $forum_id = bbp_get_topic_forum_id( $topic_id );
1266
1267 // Update inverse based on item status
1268 if ( ! bbp_is_topic_public( $topic_id ) ) {
1269 bbp_decrease_forum_topic_count_hidden( $forum_id );
1270 return;
1271 }
1272 }
1273
1274 // Bump down
1275 bbp_bump_forum_topic_count( $forum_id, -1 );
1276 }
1277
1278 /**
1279 * Bump the total topic count of a forum
1280 *
1281 * @since 2.1.0 bbPress (r3825)
1282 * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1283 *
1284 * @param int $forum_id Optional. Forum id.
1285 * @param int $difference Optional. Default 1
1286 * @param bool $update_ancestors Optional. Default true
1287 *
1288 * @return int Forum topic count
1289 */
1290 function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1291
1292 // Bail if no bump
1293 if ( empty( $difference ) ) {
1294 return false;
1295 }
1296
1297 // Get some counts
1298 $forum_id = bbp_get_forum_id( $forum_id );
1299 $reply_count = bbp_get_forum_topic_count_hidden( $forum_id, false, true );
1300 $total_topic_count = bbp_get_forum_topic_count_hidden( $forum_id, true, true );
1301 $difference = (int) $difference;
1302
1303 // Update this forum id
1304 bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count_hidden', $difference, $reply_count );
1305 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count_hidden', $difference, $total_topic_count );
1306
1307 // Check for ancestors
1308 if ( true === $update_ancestors ) {
1309
1310 // Get post ancestors
1311 $forum = get_post( $forum_id );
1312 $ancestors = get_post_ancestors( $forum );
1313
1314 // If has ancestors, loop through them...
1315 if ( ! empty( $ancestors ) ) {
1316 foreach ( (array) $ancestors as $parent_forum_id ) {
1317
1318 // Only update topic count when an ancestor is not a category.
1319 if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1320
1321 $parent_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, false, true );
1322 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count_hidden', $difference, $parent_topic_count );
1323 }
1324
1325 // Update the total topic count.
1326 $parent_total_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, true, true );
1327 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count_hidden', $difference, $parent_total_topic_count );
1328 }
1329 }
1330 }
1331
1332 $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference );
1333
1334 // Filter & return
1335 return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', $forum_topic_count, $forum_id, $difference, $update_ancestors );
1336 }
1337
1338 /**
1339 * Increase the total hidden topic count of a forum by one.
1340 *
1341 * @since 2.6.0 bbPress (r6036)
1342 *
1343 * @param int $forum_id The forum id.
1344 *
1345 * @return void
1346 */
1347 function bbp_increase_forum_topic_count_hidden( $forum_id = 0 ) {
1348
1349 // Bail early if no id is passed.
1350 if ( empty( $forum_id ) ) {
1351 return;
1352 }
1353
1354 // If it's a topic, get the forum id.
1355 if ( bbp_is_topic( $forum_id ) ) {
1356 $topic_id = $forum_id;
1357 $forum_id = bbp_get_topic_forum_id( $topic_id );
1358
1359 // Update inverse based on item status
1360 if ( bbp_is_topic_public( $topic_id ) ) {
1361 bbp_increase_forum_topic_count( $forum_id );
1362 return;
1363 }
1364 }
1365
1366 // Bump up
1367 bbp_bump_forum_topic_count_hidden( $forum_id );
1368 }
1369
1370 /**
1371 * Decrease the total hidden topic count of a forum by one.
1372 *
1373 * @since 2.6.0 bbPress (r6036)
1374 *
1375 * @param int $forum_id The forum id.
1376 *
1377 * @return void
1378 */
1379 function bbp_decrease_forum_topic_count_hidden( $forum_id = 0 ) {
1380
1381 // Bail early if no id is passed.
1382 if ( empty( $forum_id ) ) {
1383 return;
1384 }
1385
1386 // If it's a topic, get the forum id.
1387 if ( bbp_is_topic( $forum_id ) ) {
1388 $topic_id = $forum_id;
1389 $forum_id = bbp_get_topic_forum_id( $topic_id );
1390
1391 // Update inverse based on item status
1392 if ( bbp_is_topic_public( $topic_id ) ) {
1393 bbp_decrease_forum_topic_count( $forum_id );
1394 return;
1395 }
1396 }
1397
1398 // Bump down
1399 bbp_bump_forum_topic_count_hidden( $forum_id, -1 );
1400 }
1401
1402 /**
1403 * Bump the total topic count of a forum
1404 *
1405 * @since 2.1.0 bbPress (r3825)
1406 * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1407 *
1408 * @param int $forum_id Optional. Forum id.
1409 * @param int $difference Optional. Default 1
1410 * @param bool $update_ancestors Optional. Default true
1411 *
1412 * @return int Forum topic count
1413 */
1414 function bbp_bump_forum_reply_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1415
1416 // Bail if no bump
1417 if ( empty( $difference ) ) {
1418 return false;
1419 }
1420
1421 // Get some counts
1422 $forum_id = bbp_get_forum_id( $forum_id );
1423 $reply_count = bbp_get_forum_reply_count( $forum_id, false, true );
1424 $total_reply_count = bbp_get_forum_reply_count( $forum_id, true, true );
1425 $difference = (int) $difference;
1426
1427 // Update this forum id
1428 bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count', $difference, $reply_count );
1429 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count', $difference, $total_reply_count );
1430
1431 // Check for ancestors
1432 if ( true === $update_ancestors ) {
1433
1434 // Get post ancestors
1435 $forum = get_post( $forum_id );
1436 $ancestors = get_post_ancestors( $forum );
1437
1438 // If has ancestors, loop through them...
1439 if ( ! empty( $ancestors ) ) {
1440 foreach ( (array) $ancestors as $parent_forum_id ) {
1441
1442 // Only update reply count when an ancestor is not a category.
1443 if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1444
1445 $parent_reply_count = bbp_get_forum_reply_count( $parent_forum_id, false, true );
1446 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count', $difference, $parent_reply_count );
1447 }
1448
1449 // Update the total reply count.
1450 $parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true, true );
1451 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count', $difference, $parent_total_reply_count );
1452 }
1453 }
1454 }
1455
1456 $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference );
1457
1458 // Filter & return
1459 return (int) apply_filters( 'bbp_bump_forum_reply_count', $forum_reply_count, $forum_id, $difference, $update_ancestors );
1460 }
1461
1462 /**
1463 * Bump the total topic count of a forum
1464 *
1465 * @since 2.6.0 bbPress (r6922)
1466 * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1467 *
1468 * @param int $forum_id Optional. Forum id.
1469 * @param int $difference Optional. Default 1
1470 * @param bool $update_ancestors Optional. Default true
1471 *
1472 * @return int Forum topic count
1473 */
1474 function bbp_bump_forum_reply_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1475
1476 // Bail if no bump
1477 if ( empty( $difference ) ) {
1478 return false;
1479 }
1480
1481 // Get some counts
1482 $forum_id = bbp_get_forum_id( $forum_id );
1483 $reply_count = bbp_get_forum_reply_count_hidden( $forum_id, false, true );
1484 $total_reply_count = bbp_get_forum_reply_count_hidden( $forum_id, true, true );
1485 $difference = (int) $difference;
1486
1487 // Update this forum id
1488 bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count_hidden', $difference, $reply_count );
1489 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count_hidden', $difference, $total_reply_count );
1490
1491 // Check for ancestors
1492 if ( true === $update_ancestors ) {
1493
1494 // Get post ancestors
1495 $forum = get_post( $forum_id );
1496 $ancestors = get_post_ancestors( $forum );
1497
1498 // If has ancestors, loop through them...
1499 if ( ! empty( $ancestors ) ) {
1500 foreach ( (array) $ancestors as $parent_forum_id ) {
1501
1502 // Only update reply count when an ancestor is not a category.
1503 if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1504
1505 $parent_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, false, true );
1506 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count_hidden', $difference, $parent_reply_count );
1507 }
1508
1509 // Update the total reply count.
1510 $parent_total_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, true, true );
1511 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count_hidden', $difference, $parent_total_reply_count );
1512 }
1513 }
1514 }
1515
1516 $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference );
1517
1518 // Filter & return
1519 return (int) apply_filters( 'bbp_bump_forum_reply_count_hidden', $forum_reply_count, $forum_id, $difference, $update_ancestors );
1520 }
1521
1522 /**
1523 * Bump one total count through a forum's ancestors.
1524 *
1525 * This is used after recounting a forum that may be nested as a subforum. The
1526 * starting forum's total has already been updated, so only its parent forums
1527 * receive the difference between the old and new totals. The supplied metadata
1528 * key identifies which total topic or reply count is propagated.
1529 *
1530 * Forum hierarchy is stored in `post_parent`, making get_post_ancestors() the
1531 * canonical, cache-aware way to walk from a subforum toward its root forum.
1532 * Only parent forums are traversed: topics and replies are never ancestors in
1533 * a valid forum hierarchy, even when the metadata key stores their totals. The
1534 * walk stops if a malformed parent relationship leaves the forum post type.
1535 *
1536 * @since 2.6.17
1537 *
1538 * @param int $forum_id Starting forum ID. Its own count is not changed.
1539 * @param string $meta_key Topic or reply total count metadata key.
1540 * @param int $difference Amount to add to the stored value.
1541 * @return bool True when all ancestor counts were updated, false otherwise.
1542 */
1543 function bbp_bump_forum_ancestor_count( $forum_id = 0, $meta_key = '', $difference = 0 ) {
1544 $forum_id = bbp_get_forum_id( $forum_id );
1545 $difference = (int) $difference;
1546
1547 // Bail if nothing can change
1548 if ( empty( $forum_id ) || empty( $meta_key ) || empty( $difference ) ) {
1549 return false;
1550 }
1551
1552 $updated = true;
1553 $ancestor_ids = get_post_ancestors( $forum_id );
1554
1555 // Return if this forum has no ancestors
1556 if ( empty( $ancestor_ids ) ) {
1557 return $updated;
1558 }
1559
1560 // Update only total counts on ancestor forums
1561 foreach ( $ancestor_ids as $ancestor_id ) {
1562
1563 // Stop if malformed data leaves the subforum hierarchy
1564 if ( ! bbp_is_forum( $ancestor_id ) ) {
1565 break;
1566 }
1567
1568 $count = (int) get_post_meta( $ancestor_id, $meta_key, true );
1569
1570 if ( ! bbp_bump_count_meta( 'post', $ancestor_id, $meta_key, $difference, $count ) ) {
1571 $updated = false;
1572 }
1573 }
1574
1575 return $updated;
1576 }
1577
1578 /**
1579 * Increase the total reply count of a forum by one.
1580 *
1581 * @since 2.6.0 bbPress (r6036)
1582 *
1583 * @param int $forum_id The forum id.
1584 *
1585 * @return void
1586 */
1587 function bbp_increase_forum_reply_count( $forum_id = 0 ) {
1588
1589 // Bail early if no id is passed.
1590 if ( empty( $forum_id ) ) {
1591 return;
1592 }
1593
1594 // If it's a reply, get the forum id.
1595 if ( bbp_is_reply( $forum_id ) ) {
1596 $reply_id = $forum_id;
1597 $forum_id = bbp_get_reply_forum_id( $reply_id );
1598
1599 // Update inverse based on item status
1600 if ( ! bbp_is_reply_public( $reply_id ) ) {
1601 bbp_increase_forum_reply_count_hidden( $forum_id );
1602 return;
1603 }
1604 }
1605
1606 // Bump up
1607 bbp_bump_forum_reply_count( $forum_id );
1608 }
1609
1610 /**
1611 * Decrease the total reply count of a forum by one.
1612 *
1613 * @since 2.6.0 bbPress (r6036)
1614 *
1615 * @param int $forum_id The forum id.
1616 *
1617 * @return void
1618 */
1619 function bbp_decrease_forum_reply_count( $forum_id = 0 ) {
1620
1621 // Bail early if no id is passed.
1622 if ( empty( $forum_id ) ) {
1623 return;
1624 }
1625
1626 // If it's a reply, get the forum id.
1627 if ( bbp_is_reply( $forum_id ) ) {
1628 $reply_id = $forum_id;
1629 $forum_id = bbp_get_reply_forum_id( $reply_id );
1630
1631 // Update inverse based on item status
1632 if ( ! bbp_is_reply_public( $reply_id ) ) {
1633 bbp_decrease_forum_reply_count_hidden( $forum_id );
1634 return;
1635 }
1636 }
1637
1638 // Bump down
1639 bbp_bump_forum_reply_count( $forum_id, -1 );
1640 }
1641
1642 /**
1643 * Increase the total hidden reply count of a forum by one.
1644 *
1645 * @since 2.6.0 bbPress (r6036)
1646 *
1647 * @param int $forum_id The forum id.
1648 *
1649 * @return void
1650 */
1651 function bbp_increase_forum_reply_count_hidden( $forum_id = 0 ) {
1652
1653 // Bail early if no id is passed.
1654 if ( empty( $forum_id ) ) {
1655 return;
1656 }
1657
1658 // If it's a reply, get the forum id.
1659 if ( bbp_is_reply( $forum_id ) ) {
1660 $reply_id = $forum_id;
1661 $forum_id = bbp_get_reply_forum_id( $reply_id );
1662
1663 // Update inverse based on item status
1664 if ( bbp_is_reply_public( $reply_id ) ) {
1665 bbp_increase_forum_reply_count( $forum_id );
1666 return;
1667 }
1668 }
1669
1670 // Bump up
1671 bbp_bump_forum_reply_count_hidden( $forum_id );
1672 }
1673
1674 /**
1675 * Decrease the total hidden reply count of a forum by one.
1676 *
1677 * @since 2.6.0 bbPress (r6036)
1678 *
1679 * @param int $forum_id The forum id.
1680 *
1681 * @return void
1682 */
1683 function bbp_decrease_forum_reply_count_hidden( $forum_id = 0 ) {
1684
1685 // Bail early if no id is passed.
1686 if ( empty( $forum_id ) ) {
1687 return;
1688 }
1689
1690 // If it's a reply, get the forum id.
1691 if ( bbp_is_reply( $forum_id ) ) {
1692 $reply_id = $forum_id;
1693 $forum_id = bbp_get_reply_forum_id( $reply_id );
1694
1695 // Update inverse based on item status
1696 if ( bbp_is_reply_public( $reply_id ) ) {
1697 bbp_decrease_forum_reply_count( $forum_id );
1698 return;
1699 }
1700 }
1701
1702 // Bump down
1703 bbp_bump_forum_reply_count_hidden( $forum_id, -1 );
1704 }
1705
1706 /**
1707 * Update forum reply counts when a topic is approved or unapproved.
1708 *
1709 * @since 2.6.0 bbPress (r6036)
1710 *
1711 * @param int $topic_id The topic id.
1712 *
1713 * @return void
1714 */
1715 function bbp_approved_unapproved_topic_update_forum_reply_count( $topic_id = 0 ) {
1716
1717 // Bail early if we don't have a topic id.
1718 if ( empty( $topic_id ) ) {
1719 return;
1720 }
1721
1722 // Get the topic's replies.
1723 $count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
1724
1725 // If we're unapproving, set count to negative.
1726 if ( 'bbp_unapproved_topic' === current_filter() ) {
1727 $count = -$count;
1728 }
1729
1730 // Bump up or down
1731 bbp_bump_forum_reply_count( bbp_get_topic_forum_id( $topic_id ), $count );
1732 }
1733
1734 /** Forum Updaters ************************************************************/
1735
1736 /**
1737 * Update the forum last topic id
1738 *
1739 * @since 2.0.0 bbPress (r2625)
1740 *
1741 * @param int $forum_id Optional. Forum id.
1742 * @param int $topic_id Optional. Topic id.
1743 * @return int Id of the forums most recent topic
1744 */
1745 function bbp_update_forum_last_topic_id( $forum_id = 0, $topic_id = 0 ) {
1746 $forum_id = bbp_get_forum_id( $forum_id );
1747
1748 // Define local variable(s)
1749 $children_last_topic = 0;
1750
1751 // Do some calculation if not manually set
1752 if ( empty( $topic_id ) ) {
1753
1754 // Loop through children and add together forum reply counts
1755 $children = bbp_forum_query_subforum_ids( $forum_id );
1756 if ( ! empty( $children ) ) {
1757 foreach ( $children as $child ) {
1758 $children_last_topic = bbp_update_forum_last_topic_id( $child ); // Recursive
1759 }
1760 }
1761
1762 // Setup recent topic query vars
1763 $post_vars = array(
1764 'post_parent' => $forum_id,
1765 'post_type' => bbp_get_topic_post_type(),
1766 'meta_key' => '_bbp_last_active_time',
1767 'meta_type' => 'DATETIME',
1768 'orderby' => 'meta_value',
1769 'numberposts' => 1
1770 );
1771
1772 // Get the most recent topic in this forum_id
1773 $recent_topic = get_posts( $post_vars );
1774 if ( ! empty( $recent_topic ) ) {
1775 $topic_id = $recent_topic[0]->ID;
1776 }
1777 }
1778
1779 // Cast as integer in case of empty or string
1780 $topic_id = (int) $topic_id;
1781 $children_last_topic = (int) $children_last_topic;
1782
1783 // If child forums have higher id, use that instead
1784 if ( ! empty( $children ) && ( $children_last_topic > $topic_id ) ) {
1785 $topic_id = $children_last_topic;
1786 }
1787
1788 // Update the last public topic ID
1789 update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );
1790
1791 // Filter & return
1792 return (int) apply_filters( 'bbp_update_forum_last_topic_id', $topic_id, $forum_id );
1793 }
1794
1795 /**
1796 * Update the forum last reply id
1797 *
1798 * @since 2.0.0 bbPress (r2625)
1799 *
1800 * @param int $forum_id Optional. Forum id.
1801 * @param int $reply_id Optional. Reply id.
1802 * @return int Id of the forums most recent reply
1803 */
1804 function bbp_update_forum_last_reply_id( $forum_id = 0, $reply_id = 0 ) {
1805 $forum_id = bbp_get_forum_id( $forum_id );
1806
1807 // Define local variable(s)
1808 $children_last_reply = 0;
1809
1810 // Do some calculation if not manually set
1811 if ( empty( $reply_id ) ) {
1812
1813 // Loop through children and get the most recent reply id
1814 $children = bbp_forum_query_subforum_ids( $forum_id );
1815 if ( ! empty( $children ) ) {
1816 foreach ( $children as $child ) {
1817 $children_last_reply = bbp_update_forum_last_reply_id( $child ); // Recursive
1818 }
1819 }
1820
1821 // If this forum has topics...
1822 $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1823 if ( ! empty( $topic_ids ) ) {
1824
1825 // ...get the most recent reply from those topics...
1826 $reply_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1827
1828 // ...and compare it to the most recent topic id...
1829 $reply_id = ( $reply_id > max( $topic_ids ) )
1830 ? $reply_id
1831 : max( $topic_ids );
1832 }
1833 }
1834
1835 // Cast as integer in case of empty or string
1836 $reply_id = (int) $reply_id;
1837 $children_last_reply = (int) $children_last_reply;
1838
1839 // If child forums have higher ID, check for newer reply id
1840 if ( ! empty( $children ) && ( $children_last_reply > $reply_id ) ) {
1841 $reply_id = $children_last_reply;
1842 }
1843
1844 // Update the last public reply ID
1845 update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );
1846
1847 // Filter & return
1848 return (int) apply_filters( 'bbp_update_forum_last_reply_id', $reply_id, $forum_id );
1849 }
1850
1851 /**
1852 * Update the forum last active post id
1853 *
1854 * @since 2.0.0 bbPress (r2860)
1855 *
1856 * @param int $forum_id Optional. Forum id.
1857 * @param int $active_id Optional. Active post id.
1858 * @return int Id of the forums last active post
1859 */
1860 function bbp_update_forum_last_active_id( $forum_id = 0, $active_id = 0 ) {
1861
1862 $forum_id = bbp_get_forum_id( $forum_id );
1863
1864 // Define local variable(s)
1865 $children_last_active = 0;
1866
1867 // Do some calculation if not manually set
1868 if ( empty( $active_id ) ) {
1869
1870 // Loop through children and get the last active ID
1871 $children = bbp_forum_query_subforum_ids( $forum_id );
1872 if ( ! empty( $children ) ) {
1873 foreach ( $children as $child ) {
1874 $children_last_active = bbp_update_forum_last_active_id( $child, $active_id );
1875 }
1876 }
1877
1878 // Get topic IDs and only accept larger IDs
1879 $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1880 if ( ! empty( $topic_ids ) ) {
1881
1882 // Make sure ID is larger
1883 $active_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1884 $active_id = $active_id > max( $topic_ids )
1885 ? $active_id
1886 : max( $topic_ids );
1887
1888 // Forum has no topics
1889 } else {
1890 $active_id = 0;
1891 }
1892 }
1893
1894 // Cast as integer in case of empty or string
1895 $active_id = (int) $active_id;
1896 $children_last_active = (int) $children_last_active;
1897
1898 // If child forums have higher ID, use that instead
1899 if ( ! empty( $children ) && ( $children_last_active > $active_id ) ) {
1900 $active_id = $children_last_active;
1901 }
1902
1903 update_post_meta( $forum_id, '_bbp_last_active_id', $active_id );
1904
1905 // Filter & return
1906 return (int) apply_filters( 'bbp_update_forum_last_active_id', $active_id, $forum_id );
1907 }
1908
1909 /**
1910 * Update the forums last active date/time (aka freshness)
1911 *
1912 * @since 2.0.0 bbPress (r2680)
1913 *
1914 * @param int $forum_id Optional. Topic id.
1915 * @param string $new_time Optional. New time in mysql format.
1916 *
1917 * @return string MySQL timestamp of last active topic or reply
1918 */
1919 function bbp_update_forum_last_active_time( $forum_id = 0, $new_time = '' ) {
1920 $forum_id = bbp_get_forum_id( $forum_id );
1921
1922 // Check time and use current if empty
1923 if ( empty( $new_time ) ) {
1924 $new_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $forum_id ) );
1925 }
1926
1927 // Update only if there is a time
1928 if ( ! empty( $new_time ) ) {
1929 update_post_meta( $forum_id, '_bbp_last_active_time', $new_time );
1930 }
1931
1932 // Filter & return
1933 return apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
1934 }
1935
1936 /**
1937 * Update the forum sub-forum count
1938 *
1939 * @since 2.0.0 bbPress (r2625)
1940 * @since 2.6.17 Count supported forum visibilities from the post hierarchy.
1941 *
1942 * @param int $forum_id Optional. Forum ID.
1943 * @param int|bool $subforums Optional. Number of subforums, or false to query.
1944 * @return int|false Number of subforums, or false on query failure.
1945 */
1946 function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = false ) {
1947 $forum_id = bbp_get_forum_id( $forum_id );
1948
1949 // Maybe query for counts
1950 if ( ! is_int( $subforums ) ) {
1951 $bbp_db = bbp_db();
1952 $post_type = bbp_get_forum_post_type();
1953 $statuses = bbp_get_countable_forum_statuses();
1954
1955 if ( ! empty( $statuses ) ) {
1956 $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
1957 $sql = "SELECT COUNT(*) FROM {$bbp_db->posts} WHERE post_parent = %d AND post_type = %s AND post_status IN ({$placeholders})";
1958 $query = $bbp_db->prepare( $sql, array_merge( array( $forum_id, $post_type ), $statuses ) );
1959 $subforums = $bbp_db->get_var( $query );
1960
1961 // Bail if the count query failed
1962 if ( ! empty( $bbp_db->last_error ) ) {
1963 return false;
1964 }
1965
1966 $subforums = bbp_number_not_negative( $subforums );
1967 } else {
1968 $subforums = 0;
1969 }
1970 }
1971
1972 update_post_meta( $forum_id, '_bbp_forum_subforum_count', $subforums );
1973
1974 // Filter & return
1975 return (int) apply_filters( 'bbp_update_forum_subforum_count', $subforums, $forum_id );
1976 }
1977
1978 /**
1979 * Synchronize child-forum metadata after WordPress reparents deleted children.
1980 *
1981 * @since 2.6.17
1982 *
1983 * @param int $forum_id Deleted forum ID.
1984 * @param WP_Post $forum Deleted forum post object.
1985 */
1986 function bbp_reparent_forum_subforums( $forum_id = 0, $forum = false ) {
1987 $bbp_db = bbp_db();
1988 $post_type = bbp_get_forum_post_type();
1989 $meta_key = '_bbp_forum_id';
1990 $sql = "SELECT posts.ID
1991 FROM {$bbp_db->posts} AS posts
1992 INNER JOIN {$bbp_db->postmeta} AS postmeta
1993 ON posts.ID = postmeta.post_id
1994 AND postmeta.meta_key = %s
1995 WHERE posts.post_type = %s
1996 AND posts.post_parent = %d
1997 AND postmeta.meta_value = %d";
1998 $query = $bbp_db->prepare( $sql, $meta_key, $post_type, $forum->post_parent, $forum_id );
1999
2000 foreach ( wp_parse_id_list( $bbp_db->get_col( $query ) ) as $subforum_id ) {
2001 bbp_update_forum_id( $subforum_id, $forum->post_parent );
2002 }
2003 }
2004
2005 /**
2006 * Update a parent forum's subforum count after a child is permanently deleted.
2007 *
2008 * @since 2.6.17
2009 *
2010 * @param int $forum_id Forum ID.
2011 * @param WP_Post|bool $forum Optional. Forum post object.
2012 * @return int|false Updated subforum count, or false if there is no parent.
2013 */
2014 function bbp_update_parent_forum_subforum_count( $forum_id = 0, $forum = false ) {
2015 $forum = ( $forum instanceof WP_Post )
2016 ? $forum
2017 : get_post( $forum_id );
2018
2019 // Bail if the forum has no parent
2020 if ( empty( $forum ) || empty( $forum->post_parent ) ) {
2021 return false;
2022 }
2023
2024 return bbp_update_forum_subforum_count( $forum->post_parent );
2025 }
2026
2027 /**
2028 * Update a parent forum's subforum count after a child changes count status.
2029 *
2030 * @since 2.6.17
2031 *
2032 * @param string $new_status New post status.
2033 * @param string $old_status Old post status.
2034 * @param WP_Post $forum Forum post object.
2035 * @return int|false Updated subforum count, or false when no update is needed.
2036 */
2037 function bbp_update_forum_subforum_count_on_transition_post_status( $new_status = '', $old_status = '', $forum = false ) {
2038
2039 // Bail if this is not a child forum
2040 if ( ( bbp_get_forum_post_type() !== $forum->post_type ) || empty( $forum->post_parent ) ) {
2041 return false;
2042 }
2043
2044 $statuses = bbp_get_countable_forum_statuses();
2045 $was_counted = in_array( $old_status, $statuses, true );
2046 $is_counted = in_array( $new_status, $statuses, true );
2047
2048 // Bail if subforum count membership did not change
2049 if ( $was_counted === $is_counted ) {
2050 return false;
2051 }
2052
2053 return bbp_update_forum_subforum_count( $forum->post_parent );
2054 }
2055
2056 /**
2057 * Update subforum counts after a forum changes parent or post type.
2058 *
2059 * @since 2.6.17
2060 *
2061 * @param int $forum_id Forum ID.
2062 * @param WP_Post $forum_after Forum object following the update.
2063 * @param WP_Post $forum_before Forum object before the update.
2064 */
2065 function bbp_update_forum_subforum_counts_on_post_updated( $forum_id = 0, $forum_after = false, $forum_before = false ) {
2066 $post_type = bbp_get_forum_post_type();
2067 $parent_moved = ( $forum_after->post_parent !== $forum_before->post_parent );
2068
2069 // Bail if forum hierarchy membership did not change
2070 if ( ! $parent_moved && ( $forum_after->post_type === $forum_before->post_type ) ) {
2071 return false;
2072 }
2073
2074 // Synchronize parent metadata when the updated post remains a forum
2075 if ( ( $post_type === $forum_after->post_type ) && ( $parent_moved || ( $post_type !== $forum_before->post_type ) ) ) {
2076 bbp_update_forum_id( $forum_id, $forum_after->post_parent );
2077 }
2078
2079 $statuses = bbp_get_countable_forum_statuses();
2080 $was_counted = ( $post_type === $forum_before->post_type ) && in_array( $forum_before->post_status, $statuses, true );
2081 $is_counted = ( $post_type === $forum_after->post_type ) && in_array( $forum_after->post_status, $statuses, true );
2082
2083 // Include the previous parent when it formerly contained this subforum
2084 $parent_ids = $was_counted
2085 ? array( $forum_before->post_parent )
2086 : array();
2087
2088 // Include the new parent when it now contains this subforum
2089 if ( $is_counted ) {
2090 $parent_ids[] = $forum_after->post_parent;
2091 }
2092
2093 // Recount each affected parent once
2094 foreach ( array_filter( array_unique( $parent_ids ) ) as $parent_id ) {
2095 bbp_update_forum_subforum_count( $parent_id );
2096 }
2097 }
2098
2099 /**
2100 * Adjust the total topic count of a forum.
2101 *
2102 * @since 2.0.0 bbPress (r2464)
2103 * @since 2.6.17 Optionally update ancestor forum totals.
2104 *
2105 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
2106 * is a topic or a forum. If it's a topic, its parent,
2107 * i.e. the forum is automatically retrieved.
2108 * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2109 * @return int Forum topic count.
2110 */
2111 function bbp_update_forum_topic_count( $forum_id = 0, $update_ancestors = false ) {
2112 $forum_id = bbp_get_forum_id( $forum_id );
2113 $old_total_topics = ( true === $update_ancestors )
2114 ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count', true )
2115 : 0;
2116 $children_topic_count = 0;
2117 $total_topics = 0;
2118
2119 // Loop through subforums and add together forum topic counts
2120 $children = bbp_forum_query_subforum_ids( $forum_id );
2121 if ( ! empty( $children ) ) {
2122 foreach ( $children as $child ) {
2123 $children_topic_count += bbp_update_forum_topic_count( $child ); // Recursive
2124 }
2125 }
2126
2127 // Get total topics for this forum
2128 $topics = bbp_get_public_child_count( $forum_id, bbp_get_topic_post_type() );
2129
2130 // Calculate total topics in this forum
2131 $total_topics = (int) ( $topics + $children_topic_count );
2132
2133 // Update the count
2134 update_post_meta( $forum_id, '_bbp_topic_count', $topics );
2135 update_post_meta( $forum_id, '_bbp_total_topic_count', $total_topics );
2136
2137 // Update ancestor total counts by the persisted difference
2138 if ( true === $update_ancestors ) {
2139 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count', $total_topics - $old_total_topics );
2140 }
2141
2142 // Filter & return
2143 return (int) apply_filters( 'bbp_update_forum_topic_count', $total_topics, $forum_id );
2144 }
2145
2146 /**
2147 * Adjust the total hidden topic count of a forum (hidden includes trashed,
2148 * spammed and pending topics).
2149 *
2150 * @since 2.0.0 bbPress (r2888)
2151 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
2152 * @since 2.6.17 Optionally update ancestor forum totals.
2153 *
2154 * @param int $forum_id Optional. Topic id to update.
2155 * @param int $topic_count Optional. Set the topic count manually.
2156 * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2157 *
2158 * @return int Topic hidden topic count.
2159 */
2160 function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = false, $update_ancestors = false ) {
2161
2162 // If topic_id was passed as $forum_id, then get its forum
2163 if ( bbp_is_topic( $forum_id ) ) {
2164 $topic_id = bbp_get_topic_id( $forum_id );
2165 $forum_id = bbp_get_topic_forum_id( $topic_id );
2166
2167 // $forum_id is not a topic_id, so validate and proceed
2168 } else {
2169 $forum_id = bbp_get_forum_id( $forum_id );
2170 }
2171
2172 $children_topic_count = 0;
2173 $total_topics = 0;
2174 $old_total_topics = ( true === $update_ancestors )
2175 ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count_hidden', true )
2176 : 0;
2177
2178 // Can't update what isn't there
2179 if ( ! empty( $forum_id ) ) {
2180
2181 // Loop through children and add together hidden topic counts
2182 $children = bbp_forum_query_subforum_ids( $forum_id );
2183 if ( ! empty( $children ) ) {
2184 foreach ( (array) $children as $child ) {
2185 bbp_update_forum_topic_count_hidden( $child );
2186 $children_topic_count += bbp_get_forum_topic_count_hidden( $child, true, true );
2187 }
2188 }
2189
2190 // Get topics of forum
2191 if ( ! is_int( $topic_count ) ) {
2192 $query = new WP_Query(
2193 array(
2194 'fields' => 'ids',
2195 'post_parent' => $forum_id,
2196 'post_status' => bbp_get_non_public_topic_statuses(),
2197 'post_type' => bbp_get_topic_post_type(),
2198 'posts_per_page' => -1,
2199
2200 // Performance
2201 'nopaging' => true,
2202 'suppress_filters' => true,
2203 'update_post_term_cache' => false,
2204 'update_post_meta_cache' => false,
2205 'ignore_sticky_posts' => true,
2206 'no_found_rows' => true
2207 )
2208 );
2209
2210 $topic_count = $query->post_count;
2211
2212 unset( $query );
2213 }
2214
2215 $topic_count = (int) $topic_count;
2216 $total_topics = (int) ( $topic_count + $children_topic_count );
2217
2218 // Update the counts
2219 update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count );
2220 update_post_meta( $forum_id, '_bbp_total_topic_count_hidden', $total_topics );
2221
2222 // Update ancestor total counts by the persisted difference
2223 if ( true === $update_ancestors ) {
2224 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count_hidden', $total_topics - $old_total_topics );
2225 }
2226 }
2227
2228 // Filter & return
2229 return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', $topic_count, $forum_id );
2230 }
2231
2232 /**
2233 * Adjust the total reply count of a forum.
2234 *
2235 * @since 2.0.0 bbPress (r2464)
2236 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects.
2237 * @since 2.6.17 Count replies only when their parent topics are public.
2238 * @since 2.6.17 Optionally update ancestor forum totals.
2239 *
2240 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
2241 * is a topic or a forum. If it's a topic, its parent,
2242 * i.e. the forum is automatically retrieved.
2243 * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2244 *
2245 * @return int Forum reply count.
2246 */
2247 function bbp_update_forum_reply_count( $forum_id = 0, $update_ancestors = false ) {
2248
2249 $forum_id = bbp_get_forum_id( $forum_id );
2250 $old_total_replies = ( true === $update_ancestors )
2251 ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count', true )
2252 : 0;
2253 $children_reply_count = 0;
2254
2255 // Loop through children and add together forum reply counts
2256 $children = bbp_forum_query_subforum_ids( $forum_id );
2257 if ( ! empty( $children ) ) {
2258 foreach ( (array) $children as $child ) {
2259 $children_reply_count += bbp_update_forum_reply_count( $child );
2260 }
2261 }
2262
2263 // Don't count replies if the forum is a category
2264 if ( bbp_is_forum_category( $forum_id ) ) {
2265 $reply_count = 0;
2266
2267 // Count public replies whose parent topics are also public
2268 } else {
2269 $bbp_db = bbp_db();
2270 $reply_statuses = bbp_get_public_reply_statuses();
2271 $topic_statuses = bbp_get_public_topic_statuses();
2272
2273 if ( empty( $reply_statuses ) || empty( $topic_statuses ) ) {
2274 $reply_count = 0;
2275 } else {
2276 $reply_placeholders = implode( ', ', array_fill( 0, count( $reply_statuses ), '%s' ) );
2277 $topic_placeholders = implode( ', ', array_fill( 0, count( $topic_statuses ), '%s' ) );
2278 $sql = "SELECT COUNT(*) FROM {$bbp_db->posts} AS replies
2279 INNER JOIN {$bbp_db->posts} AS topics ON replies.post_parent = topics.ID
2280 WHERE topics.post_parent = %d
2281 AND topics.post_type = %s
2282 AND topics.post_status IN ({$topic_placeholders})
2283 AND replies.post_type = %s
2284 AND replies.post_status IN ({$reply_placeholders})";
2285 $query = $bbp_db->prepare(
2286 $sql,
2287 array_merge(
2288 array( $forum_id, bbp_get_topic_post_type() ),
2289 $topic_statuses,
2290 array( bbp_get_reply_post_type() ),
2291 $reply_statuses
2292 )
2293 );
2294 $reply_count = bbp_number_not_negative( $bbp_db->get_var( $query ) );
2295 }
2296 }
2297
2298 // Calculate total replies in this forum
2299 $total_replies = (int) ( $reply_count + $children_reply_count );
2300
2301 // Update the counts
2302 update_post_meta( $forum_id, '_bbp_reply_count', $reply_count );
2303 update_post_meta( $forum_id, '_bbp_total_reply_count', $total_replies );
2304
2305 // Update ancestor total counts by the persisted difference
2306 if ( true === $update_ancestors ) {
2307 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count', $total_replies - $old_total_replies );
2308 }
2309
2310 // Filter & return
2311 return (int) apply_filters( 'bbp_update_forum_reply_count', $total_replies, $forum_id );
2312 }
2313
2314 /**
2315 * Adjust the total hidden reply count of a forum.
2316 *
2317 * @since 2.6.0 bbPress (r6922)
2318 * @since 2.6.17 Optionally update ancestor forum totals.
2319 *
2320 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
2321 * is a topic or a forum. If it's a topic, its parent,
2322 * i.e. the forum is automatically retrieved.
2323 * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2324 *
2325 * @return int Forum reply count.
2326 */
2327 function bbp_update_forum_reply_count_hidden( $forum_id = 0, $update_ancestors = false ) {
2328
2329 $forum_id = bbp_get_forum_id( $forum_id );
2330 $old_total_replies = ( true === $update_ancestors )
2331 ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count_hidden', true )
2332 : 0;
2333 $children_reply_count = 0;
2334
2335 // Loop through children and add together forum reply counts
2336 $children = bbp_forum_query_subforum_ids( $forum_id );
2337 if ( ! empty( $children ) ) {
2338 foreach ( (array) $children as $child ) {
2339 $children_reply_count += bbp_update_forum_reply_count_hidden( $child );
2340 }
2341 }
2342
2343 // Don't count replies if the forum is a category
2344 $reply_count = ! bbp_is_forum_category( $forum_id )
2345 ? bbp_get_non_public_child_count( $forum_id, bbp_get_reply_post_type() )
2346 : 0;
2347
2348 // Calculate total replies in this forum
2349 $total_replies = (int) ( $reply_count + $children_reply_count );
2350
2351 // Update the counts
2352 update_post_meta( $forum_id, '_bbp_reply_count_hidden', $reply_count );
2353 update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', $total_replies );
2354
2355 // Update ancestor total counts by the persisted difference
2356 if ( true === $update_ancestors ) {
2357 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count_hidden', $total_replies - $old_total_replies );
2358 }
2359
2360 // Filter & return
2361 return (int) apply_filters( 'bbp_update_forum_reply_count_hidden', $total_replies, $forum_id );
2362 }
2363
2364 /**
2365 * Updates the counts of a forum.
2366 *
2367 * This calls a few internal functions that all run manual queries against the
2368 * database to get their results. As such, this function can be costly to run
2369 * but is necessary to keep everything accurate.
2370 *
2371 * @since 2.0.0 bbPress (r2908)
2372 *
2373 * @param array $args Supports these arguments:
2374 * - forum_id: Forum id
2375 * - last_topic_id: Last topic id
2376 * - last_reply_id: Last reply id
2377 * - last_active_id: Last active post id
2378 * - last_active_time: last active time
2379 */
2380 function bbp_update_forum( $args = array() ) {
2381
2382 // Parse arguments against default values
2383 $r = bbp_parse_args(
2384 $args,
2385 array(
2386 'forum_id' => 0,
2387 'post_parent' => 0,
2388 'last_topic_id' => 0,
2389 'last_reply_id' => 0,
2390 'last_active_id' => 0,
2391 'last_active_time' => 0,
2392 'last_active_status' => bbp_get_public_status_id()
2393 ),
2394 'update_forum'
2395 );
2396
2397 // Update the forum parent
2398 bbp_update_forum_id( $r['forum_id'], $r['post_parent'] );
2399
2400 // Last topic and reply ID's
2401 bbp_update_forum_last_topic_id( $r['forum_id'], $r['last_topic_id'] );
2402 bbp_update_forum_last_reply_id( $r['forum_id'], $r['last_reply_id'] );
2403
2404 // Active dance
2405 $r['last_active_id'] = bbp_update_forum_last_active_id( $r['forum_id'], $r['last_active_id'] );
2406
2407 // If no active time was passed, get it from the last_active_id
2408 if ( empty( $r['last_active_time'] ) ) {
2409 $r['last_active_time'] = get_post_field( 'post_date', $r['last_active_id'] );
2410 }
2411
2412 if ( bbp_get_public_status_id() === $r['last_active_status'] ) {
2413 bbp_update_forum_last_active_time( $r['forum_id'], $r['last_active_time'] );
2414 }
2415
2416 // Subforum counts are updated on bbp_transition_post_status,
2417 // bbp_post_updated, and bbp_deleted_forum.
2418
2419 // Only update topic count if we've deleted a topic
2420 if ( in_array( current_filter(), array( 'bbp_deleted_topic', 'save_post' ), true ) ) {
2421 bbp_update_forum_reply_count( $r['forum_id'] );
2422 bbp_update_forum_topic_count( $r['forum_id'] );
2423 bbp_update_forum_topic_count_hidden( $r['forum_id'] );
2424 bbp_update_forum_reply_count_hidden( $r['forum_id'] );
2425 }
2426
2427 // Update parent forums
2428 bbp_update_forum_walker( $r );
2429
2430 // Bump the custom query cache
2431 wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
2432 }
2433
2434 /**
2435 * Walk up the forum hierarchy and update parent forums.
2436 *
2437 * @since 2.6.17
2438 *
2439 * @param array $args Parsed arguments from bbp_update_forum().
2440 * @return false|null False if there is no parent forum, otherwise null.
2441 */
2442 function bbp_update_forum_walker( $args = array() ) {
2443
2444 // Bail if this forum has no parent
2445 if ( empty( $args['post_parent'] ) ) {
2446 return false;
2447 }
2448
2449 // Update the parent and continue walking
2450 $args['forum_id'] = bbp_get_forum_id( $args['post_parent'] );
2451
2452 // Bail if the parent is not a forum
2453 if ( empty( $args['forum_id'] ) ) {
2454 return false;
2455 }
2456
2457 $args['post_parent'] = get_post_field( 'post_parent', $args['forum_id'] );
2458
2459 bbp_update_forum( $args );
2460 }
2461
2462 /** Helpers *******************************************************************/
2463
2464 /**
2465 * Return an associative array of available topic statuses
2466 *
2467 * Developers note: these statuses are actually stored as meta data, and
2468 * Visibilities are stored in post_status.
2469 *
2470 * @since 2.4.0 bbPress (r5059)
2471 *
2472 * @param int $forum_id Optional. Forum id.
2473 *
2474 * @return array
2475 */
2476 function bbp_get_forum_statuses( $forum_id = 0 ) {
2477
2478 // Filter & return
2479 return (array) apply_filters(
2480 'bbp_get_forum_statuses',
2481 array(
2482 'open' => _x( 'Open', 'Open the forum', 'bbpress' ),
2483 'closed' => _x( 'Closed', 'Close the forum', 'bbpress' )
2484 ),
2485 $forum_id
2486 );
2487 }
2488
2489 /**
2490 * Return an associative array of forum types
2491 *
2492 * @since 2.4.0 bbPress (r5059)
2493 *
2494 * @param int $forum_id Optional. Forum id.
2495 *
2496 * @return array
2497 */
2498 function bbp_get_forum_types( $forum_id = 0 ) {
2499
2500 // Filter & return
2501 return (array) apply_filters(
2502 'bbp_get_forum_types',
2503 array(
2504 'forum' => _x( 'Forum', 'Forum accepts new topics', 'bbpress' ),
2505 'category' => _x( 'Category', 'Forum is a category', 'bbpress' )
2506 ),
2507 $forum_id
2508 );
2509 }
2510
2511 /**
2512 * Return an associative array of forum visibility
2513 *
2514 * Developers note: these visibilities are actually stored in post_status, and
2515 * Statuses are stored in meta data.
2516 *
2517 * @since 2.4.0 bbPress (r5059)
2518 *
2519 * @param int $forum_id Optional. Forum id.
2520 *
2521 * @return array
2522 */
2523 function bbp_get_forum_visibilities( $forum_id = 0 ) {
2524
2525 // Filter & return
2526 return (array) apply_filters(
2527 'bbp_get_forum_visibilities',
2528 array(
2529 bbp_get_public_status_id() => _x( 'Public', 'Make forum public', 'bbpress' ),
2530 bbp_get_private_status_id() => _x( 'Private', 'Make forum private', 'bbpress' ),
2531 bbp_get_hidden_status_id() => _x( 'Hidden', 'Make forum hidden', 'bbpress' )
2532 ),
2533 $forum_id
2534 );
2535 }
2536
2537 /**
2538 * Return array of public forum statuses.
2539 *
2540 * @since 2.6.0 bbPress (r6921)
2541 *
2542 * @return array
2543 */
2544 function bbp_get_public_forum_statuses() {
2545 $statuses = array(
2546 bbp_get_public_status_id()
2547 );
2548
2549 // Filter & return
2550 return (array) apply_filters( 'bbp_get_public_forum_statuses', $statuses );
2551 }
2552
2553 /**
2554 * Return array of non-public forum statuses.
2555 *
2556 * @since 2.6.0 bbPress (r6921)
2557 *
2558 * @return array
2559 */
2560 function bbp_get_non_public_forum_statuses() {
2561 $statuses = array(
2562 bbp_get_private_status_id(),
2563 bbp_get_hidden_status_id()
2564 );
2565
2566 // Filter & return
2567 return (array) apply_filters( 'bbp_get_non_public_forum_statuses', $statuses );
2568 }
2569
2570 /**
2571 * Return forum statuses included in forum and subforum counts.
2572 *
2573 * @since 2.6.17
2574 *
2575 * @return array
2576 */
2577 function bbp_get_countable_forum_statuses() {
2578 $statuses = array_values( array_unique( array_merge( bbp_get_public_forum_statuses(), bbp_get_non_public_forum_statuses() ) ) );
2579
2580 // Filter & return
2581 return (array) apply_filters( 'bbp_get_countable_forum_statuses', $statuses );
2582 }
2583
2584 /** Queries *******************************************************************/
2585
2586 /**
2587 * Returns the hidden forum ids
2588 *
2589 * Only hidden forum ids are returned. Public and private ids are not.
2590 *
2591 * @since 2.0.0 bbPress (r3007)
2592 */
2593 function bbp_get_hidden_forum_ids() {
2594 $forum_ids = get_option( '_bbp_hidden_forums', array() );
2595 $forum_ids = ! empty( $forum_ids )
2596 ? wp_parse_id_list( $forum_ids )
2597 : array();
2598
2599 // Filter & return
2600 return (array) apply_filters( 'bbp_get_hidden_forum_ids', $forum_ids );
2601 }
2602
2603 /**
2604 * Returns the private forum ids
2605 *
2606 * Only private forum ids are returned. Public and hidden ids are not.
2607 *
2608 * @since 2.0.0 bbPress (r3007)
2609 */
2610 function bbp_get_private_forum_ids() {
2611 $forum_ids = get_option( '_bbp_private_forums', array() );
2612 $forum_ids = ! empty( $forum_ids )
2613 ? wp_parse_id_list( $forum_ids )
2614 : array();
2615
2616 // Filter & return
2617 return (array) apply_filters( 'bbp_get_private_forum_ids', $forum_ids );
2618 }
2619
2620 /**
2621 * Returns the forum IDs that should be excluded from various views & queries,
2622 * based on the current user's capabilities.
2623 *
2624 * These results are automatically filtered by bbp_allow_forums_of_user(), to
2625 * allow per-forum moderators to see forums that would otherwise be private or
2626 * hidden to them.
2627 *
2628 * If you have a need to filter these results based on your own custom
2629 * engagements API usages, please see: bbp_allow_forums_of_user()
2630 *
2631 * @since 2.6.0 bbPress (r6425)
2632 *
2633 * @return array Forum IDs to exclude, or an empty array
2634 */
2635 function bbp_get_excluded_forum_ids() {
2636
2637 // Private forums
2638 $private = ! current_user_can( 'read_private_forums' )
2639 ? bbp_get_private_forum_ids()
2640 : array();
2641
2642 // Hidden forums
2643 $hidden = ! current_user_can( 'read_hidden_forums' )
2644 ? bbp_get_hidden_forum_ids()
2645 : array();
2646
2647 // Merge private & hidden forums together, and remove any empties
2648 $forum_ids = ( ! empty( $private ) || ! empty( $hidden ) )
2649 ? array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) )
2650 : array();
2651
2652 // Include descendants of private and hidden forums
2653 $parents = $forum_ids;
2654 while ( ! empty( $parents ) ) {
2655 $parent_id = array_shift( $parents );
2656
2657 foreach ( bbp_forum_query_subforum_ids( $parent_id ) as $forum_id ) {
2658 if ( ! in_array( $forum_id, $forum_ids, true ) ) {
2659 $forum_ids[] = $forum_id;
2660 $parents[] = $forum_id;
2661 }
2662 }
2663 }
2664
2665 // Normalize forum IDs after adding descendants
2666 $forum_ids = wp_parse_id_list( $forum_ids );
2667
2668 // Filter & return
2669 return (array) apply_filters( 'bbp_get_excluded_forum_ids', $forum_ids, $private, $hidden );
2670 }
2671
2672 /**
2673 * Returns a meta_query that either includes or excludes hidden forum IDs
2674 * from a query.
2675 *
2676 * @since 2.0.0 bbPress (r3291)
2677 *
2678 * @param string Optional. The type of value to return. (string|array|meta_query)
2679 */
2680 function bbp_exclude_forum_ids( $type = 'string' ) {
2681
2682 // Setup arrays
2683 $forum_ids = array();
2684
2685 // Types
2686 $types = array(
2687 'array' => array(),
2688 'string' => '',
2689 'meta_query' => array()
2690 );
2691
2692 // Exclude for everyone but keymasters
2693 if ( ! bbp_is_user_keymaster() ) {
2694
2695 // Get forum IDs to exclude
2696 $forum_ids = bbp_get_excluded_forum_ids();
2697
2698 // Store return values in static types array
2699 if ( ! empty( $forum_ids ) ) {
2700
2701 // Setup types
2702 $types['array'] = $forum_ids;
2703 $types['string'] = implode( ',', $forum_ids );
2704 $types['meta_query'] = array(
2705 'key' => '_bbp_forum_id',
2706 'value' => $forum_ids,
2707 'type' => 'NUMERIC',
2708 'compare' => 'NOT IN'
2709 );
2710 }
2711 }
2712
2713 // There are forums that need to be excluded
2714 $retval = $types[ $type ];
2715
2716 // Filter & return
2717 return apply_filters( 'bbp_exclude_forum_ids', $retval, $forum_ids, $type );
2718 }
2719
2720 /**
2721 * Adjusts forum, topic, and reply queries to exclude items that might be
2722 * contained inside hidden or private forums that the user does not have the
2723 * capability to view.
2724 *
2725 * Doing it with an action allows us to trap all WP_Query's rather than needing
2726 * to hardcode this logic into each query. It also protects forum content for
2727 * plugins that might be doing their own queries.
2728 *
2729 * @since 2.0.0 bbPress (r3291)
2730 *
2731 * @param WP_Query $posts_query
2732 *
2733 * @return WP_Query
2734 */
2735 function bbp_pre_get_posts_normalize_forum_visibility( $posts_query = null ) {
2736
2737 // Bail if all forums are explicitly allowed
2738 if ( true === apply_filters( 'bbp_include_all_forums', false, $posts_query ) ) {
2739 return;
2740 }
2741
2742 // Bail if $posts_query is not an object or of incorrect class
2743 if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
2744 return;
2745 }
2746
2747 // Bail to prevent unintended wp-admin post_row overrides
2748 if ( is_admin() && isset( $_REQUEST['post_status'] ) ) {
2749 return;
2750 }
2751
2752 // Get the raw query post types.
2753 $post_type_query_var = $posts_query->get( 'post_type' );
2754 $post_types = bbp_get_string_array_values( $post_type_query_var );
2755
2756 // Resolve the post types included in "any" and implicit search queries.
2757 if ( ( 'any' === $post_type_query_var ) || ( empty( $post_types ) && $posts_query->is_search() ) ) {
2758 $post_types = get_post_types( array( 'exclude_from_search' => false ) );
2759 }
2760
2761 // Bail if no post types to normalize
2762 if ( empty( $post_types ) ) {
2763 return;
2764 }
2765
2766 // Compare queried post-types to supported post-types
2767 $bbp_post_types = array_intersect( $post_types, bbp_get_post_types() );
2768
2769 // Bail if no bbPress post type is being queried
2770 if ( empty( $bbp_post_types ) ) {
2771 return;
2772 }
2773
2774 // Bail if this query has already been normalized
2775 if ( $posts_query->get( '_bbp_forum_visibility_normalized' ) ) {
2776 return;
2777 }
2778
2779 // Mark this query as normalized
2780 $posts_query->set( '_bbp_forum_visibility_normalized', true );
2781
2782 // Separate non-bbPress post types from supported bbPress post types.
2783 $non_bbp_post_types = array_diff( $post_types, $bbp_post_types );
2784 $content_post_types = array_intersect(
2785 $bbp_post_types,
2786 array( bbp_get_topic_post_type(), bbp_get_reply_post_type() )
2787 );
2788
2789 /**
2790 * Clause filters do not run when a query suppresses filters. Remove bbPress
2791 * post types from mixed queries so protected content continues to fail closed
2792 * without changing the requested non-bbPress post types.
2793 */
2794 if ( ! empty( $non_bbp_post_types ) && $posts_query->get( 'suppress_filters' ) ) {
2795 $posts_query->set( 'post_type', array_values( $non_bbp_post_types ) );
2796 return;
2797 }
2798
2799 // Get forums to exclude.
2800 $forum_ids = bbp_exclude_forum_ids( 'array' );
2801
2802 // Forums
2803 if ( in_array( bbp_get_forum_post_type(), $post_types, true ) ) {
2804 $content_post_statuses = array();
2805
2806 /**
2807 * Preserve the statuses requested for topics and replies before adding
2808 * forum visibilities to a shared query. Without a post-type-aware status
2809 * clause, private and hidden content inherits the broader forum statuses.
2810 */
2811 if ( ! empty( $content_post_types ) ) {
2812 $content_post_statuses = bbp_get_string_array_values( $posts_query->get( 'post_status' ) );
2813
2814 if ( empty( $content_post_statuses ) ) {
2815 $content_post_statuses = bbp_get_public_topic_statuses();
2816 } elseif ( in_array( 'any', $content_post_statuses, true ) ) {
2817 // Match WordPress handling of an explicitly requested "any" status.
2818 $content_post_statuses = get_post_stati( array( 'exclude_from_search' => false ) );
2819 }
2820
2821 $posts_query->set( '_bbp_forum_visibility_post_types', $content_post_types );
2822 $posts_query->set( '_bbp_forum_visibility_post_statuses', $content_post_statuses );
2823 }
2824
2825 // Add all supported forum visibilities to bbPress-only queries.
2826 if ( empty( $non_bbp_post_types ) ) {
2827 $posts_query->set(
2828 'post_status',
2829 array_unique(
2830 array_merge(
2831 array_keys( bbp_get_forum_visibilities() ),
2832 $content_post_statuses
2833 )
2834 )
2835 );
2836 }
2837
2838 // Excluding some forums
2839 if ( ! empty( $forum_ids ) ) {
2840
2841 /**
2842 * WordPress ignores post__not_in when an explicit post ID is
2843 * queried. Replace an inaccessible forum ID with an impossible
2844 * inclusion so the restricted forum is not loaded into the query.
2845 */
2846 $forum_id = absint( $posts_query->get( 'p' ) );
2847 if ( ! empty( $forum_id ) && in_array( $forum_id, $forum_ids, true ) ) {
2848 $posts_query->set( 'p', 0 );
2849 $posts_query->set( 'post__in', array( 0 ) );
2850 }
2851
2852 // Get any existing not-in queries
2853 $not_in = (array) $posts_query->get( 'post__not_in', array() );
2854
2855 // Add our not-in to existing
2856 $not_in = wp_parse_id_list( array_merge( $not_in, $forum_ids ) );
2857
2858 // Set the new not-in val
2859 $posts_query->set( 'post__not_in', $not_in );
2860 }
2861 }
2862
2863 // Bail if there are no forums to exclude.
2864 if ( empty( $forum_ids ) ) {
2865 return;
2866 }
2867
2868 /**
2869 * Mixed queries need a post-type-aware SQL clause. A meta query would use an
2870 * inner join and unintentionally remove non-bbPress posts that do not have
2871 * bbPress forum metadata.
2872 */
2873 if ( ! empty( $non_bbp_post_types ) ) {
2874 $posts_query->set( '_bbp_forum_visibility_post_types', $content_post_types );
2875 $posts_query->set( '_bbp_forum_visibility_forum_ids', $forum_ids );
2876 return;
2877 }
2878
2879 // Get forum meta query.
2880 $forum_meta_query = bbp_exclude_forum_ids( 'meta_query' );
2881
2882 // Excluding some forums
2883 if ( is_array( $forum_meta_query ) && ! empty( $forum_meta_query['key'] ) && ! empty( $forum_meta_query['value'] ) ) {
2884
2885 // Get any existing meta queries
2886 $meta_query = (array) $posts_query->get( 'meta_query', array() );
2887
2888 // Add our meta query to existing
2889 $meta_query[] = $forum_meta_query;
2890
2891 // Set the new meta_query val
2892 $posts_query->set( 'meta_query', $meta_query );
2893 }
2894 }
2895
2896 /**
2897 * Excludes protected bbPress content from mixed post-type queries.
2898 *
2899 * A normal meta query cannot scope its join to bbPress post types, causing
2900 * unrelated WordPress posts and third-party post types without `_bbp_forum_id`
2901 * metadata to be removed. This clause leaves forums and non-bbPress rows
2902 * untouched while requiring topic and reply rows to have forum metadata that
2903 * does not reference an excluded forum. Forums are excluded by ID before this
2904 * clause runs.
2905 *
2906 * Queries with `suppress_filters` enabled are handled conservatively in
2907 * bbp_pre_get_posts_normalize_forum_visibility(), because this filter will not
2908 * run for those queries.
2909 *
2910 * @since 2.6.15 bbPress
2911 *
2912 * @param string $where SQL WHERE clause.
2913 * @param WP_Query $posts_query WordPress posts query.
2914 * @return string SQL WHERE clause.
2915 */
2916 function _bbp_forum_visibility_where( $where = '', $posts_query = null ) {
2917
2918 // Bail if $posts_query is not an object or of incorrect class
2919 if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
2920 return $where;
2921 }
2922
2923 // Get the query-specific visibility constraints.
2924 $post_types = bbp_get_string_array_values( $posts_query->get( '_bbp_forum_visibility_post_types' ) );
2925 $post_statuses = bbp_get_string_array_values( $posts_query->get( '_bbp_forum_visibility_post_statuses' ) );
2926 $forum_ids = wp_parse_id_list( $posts_query->get( '_bbp_forum_visibility_forum_ids' ) );
2927
2928 // Bail if this query does not need a post-type-aware visibility clause.
2929 if ( empty( $post_types ) || ( empty( $post_statuses ) && empty( $forum_ids ) ) ) {
2930 return $where;
2931 }
2932
2933 // Get the database object.
2934 $bbp_db = bbp_db();
2935
2936 // Prepare post-type placeholders.
2937 $post_type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) );
2938
2939 // Restrict topic and reply statuses in mixed forum queries.
2940 if ( ! empty( $post_statuses ) ) {
2941 $post_status_placeholders = implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) );
2942 $status_values = array_merge( $post_types, $post_statuses );
2943 $where .= $bbp_db->prepare(
2944 " AND (
2945 {$bbp_db->posts}.post_type NOT IN ({$post_type_placeholders})
2946 OR {$bbp_db->posts}.post_status IN ({$post_status_placeholders})
2947 )",
2948 $status_values
2949 );
2950 }
2951
2952 // Bail if there are no forum IDs to exclude.
2953 if ( empty( $forum_ids ) ) {
2954 return $where;
2955 }
2956
2957 // Prepare forum-ID placeholders and values.
2958 $forum_id_placeholders = implode( ', ', array_fill( 0, count( $forum_ids ), '%d' ) );
2959 $values = array_merge( $post_types, $forum_ids );
2960
2961 /**
2962 * Require topic and reply rows to have forum metadata, and exclude rows with
2963 * forum metadata pointing at a forum the current user cannot view. All other
2964 * rows bypass these checks and retain their original query behavior.
2965 */
2966 $visibility_where = $bbp_db->prepare(
2967 " AND (
2968 {$bbp_db->posts}.post_type NOT IN ({$post_type_placeholders})
2969 OR (
2970 EXISTS (
2971 SELECT 1
2972 FROM {$bbp_db->postmeta} AS bbp_forum_visibility_exists
2973 WHERE bbp_forum_visibility_exists.post_id = {$bbp_db->posts}.ID
2974 AND bbp_forum_visibility_exists.meta_key = '_bbp_forum_id'
2975 )
2976 AND NOT EXISTS (
2977 SELECT 1
2978 FROM {$bbp_db->postmeta} AS bbp_forum_visibility_excluded
2979 WHERE bbp_forum_visibility_excluded.post_id = {$bbp_db->posts}.ID
2980 AND bbp_forum_visibility_excluded.meta_key = '_bbp_forum_id'
2981 AND CAST( bbp_forum_visibility_excluded.meta_value AS UNSIGNED ) IN ({$forum_id_placeholders})
2982 )
2983 )
2984 )",
2985 $values
2986 );
2987
2988 /**
2989 * Filters the forum visibility SQL appended to mixed post-type queries.
2990 *
2991 * @since 2.6.15 bbPress
2992 *
2993 * @param string $visibility_where Forum visibility SQL clause.
2994 * @param WP_Query $posts_query WordPress posts query.
2995 * @param string[] $post_types bbPress post types protected by the clause.
2996 * @param int[] $forum_ids Forum IDs excluded from the query.
2997 */
2998 $visibility_where = apply_filters(
2999 'bbp_forum_visibility_posts_where',
3000 $visibility_where,
3001 $posts_query,
3002 $post_types,
3003 $forum_ids
3004 );
3005
3006 // Append the visibility clause.
3007 return $where . $visibility_where;
3008 }
3009
3010 /**
3011 * Returns the forum's topic ids
3012 *
3013 * Only topics with published and closed statuses are returned
3014 *
3015 * @since 2.0.0 bbPress (r2908)
3016 *
3017 * @param int $forum_id Forum id
3018 */
3019 function bbp_forum_query_topic_ids( $forum_id ) {
3020 $topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );
3021
3022 // Filter & return
3023 return (array) apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
3024 }
3025
3026 /**
3027 * Returns the forum's subforum ids.
3028 *
3029 * Only forums with countable statuses are returned.
3030 *
3031 * @since 2.0.0 bbPress (r2908)
3032 * @since 2.6.17 Restrict results to countable statuses instead of using
3033 * bbp_get_all_child_ids().
3034 *
3035 * @param int $forum_id Forum id.
3036 */
3037 function bbp_forum_query_subforum_ids( $forum_id ) {
3038 $forum_id = bbp_get_forum_id( $forum_id );
3039 $statuses = bbp_get_countable_forum_statuses();
3040 $subforum_ids = array();
3041
3042 // Query and cache countable subforums. The public child-ID helper excludes
3043 // private and hidden forums, while the all-child helper includes trash, so
3044 // neither existing helper represents the statuses counted here.
3045 if ( ! empty( $forum_id ) && ! empty( $statuses ) ) {
3046 $key = md5(
3047 serialize(
3048 array(
3049 'parent_id' => $forum_id,
3050 'post_type' => bbp_get_forum_post_type(),
3051 'post_status' => $statuses
3052 )
3053 )
3054 );
3055 $cache_key = "bbp_child_ids:{$key}:" . wp_cache_get_last_changed( 'bbpress_posts' );
3056 $subforum_ids = wp_cache_get( $cache_key, 'bbpress_posts' );
3057
3058 if ( false === $subforum_ids ) {
3059 $bbp_db = bbp_db();
3060 $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
3061 $query = $bbp_db->prepare(
3062 "SELECT ID FROM {$bbp_db->posts} WHERE post_parent = %d AND post_type = %s AND post_status IN ({$placeholders}) ORDER BY ID DESC",
3063 array_merge( array( $forum_id, bbp_get_forum_post_type() ), $statuses )
3064 );
3065 $subforum_ids = (array) $bbp_db->get_col( $query );
3066
3067 wp_cache_set( $cache_key, $subforum_ids, 'bbpress_posts' );
3068 }
3069 }
3070
3071 // Filter & return
3072 return (array) apply_filters( 'bbp_forum_query_subforum_ids', $subforum_ids, $forum_id );
3073 }
3074
3075 /**
3076 * Returns the forum's last reply id
3077 *
3078 * @since 2.0.0 bbPress (r2908)
3079 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
3080 *
3081 * @param int $forum_id Forum id.
3082 * @param int $topic_ids Optional. Topic ids.
3083 */
3084 function bbp_forum_query_last_reply_id( $forum_id = 0, $topic_ids = 0 ) {
3085
3086 // Validate forum
3087 $forum_id = bbp_get_forum_id( $forum_id );
3088
3089 // Get topic ID's if none were passed
3090 if ( empty( $topic_ids ) ) {
3091 $topic_ids = bbp_forum_query_topic_ids( $forum_id );
3092 }
3093
3094 $query = new WP_Query(
3095 array(
3096 'fields' => 'ids',
3097 'suppress_filters' => true,
3098 'post_parent__in' => $topic_ids,
3099 'post_status' => bbp_get_public_status_id(),
3100 'post_type' => bbp_get_reply_post_type(),
3101 'posts_per_page' => 1,
3102 'orderby' => array(
3103 'post_date' => 'DESC',
3104 'ID' => 'DESC'
3105 ),
3106
3107 // Performance
3108 'update_post_term_cache' => false,
3109 'update_post_meta_cache' => false,
3110 'ignore_sticky_posts' => true,
3111 'no_found_rows' => true
3112 )
3113 );
3114
3115 $reply_id = array_shift( $query->posts );
3116
3117 unset( $query );
3118
3119 // Filter & return
3120 return (int) apply_filters( 'bbp_forum_query_last_reply_id', $reply_id, $forum_id );
3121 }
3122
3123 /** Listeners *****************************************************************/
3124
3125 /**
3126 * Check if it's a hidden forum or a topic or reply of a hidden forum and if
3127 * the user can't view it, then sets a 404
3128 *
3129 * @since 2.0.0 bbPress (r2996)
3130 */
3131 function bbp_forum_enforce_hidden() {
3132
3133 // Bail if not viewing a single item or if user has caps
3134 if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_hidden_forums' ) ) {
3135 return;
3136 }
3137
3138 // Define local variables
3139 $forum_id = 0;
3140 $wp_query = bbp_get_wp_query();
3141 $post_id = ! empty( $wp_query->post->ID )
3142 ? $wp_query->post->ID
3143 : 0;
3144
3145 // Check post type
3146 switch ( $wp_query->get( 'post_type' ) ) {
3147
3148 // Forum
3149 case bbp_get_forum_post_type() :
3150 $forum_id = bbp_get_forum_id( $post_id );
3151 break;
3152
3153 // Topic
3154 case bbp_get_topic_post_type() :
3155 $forum_id = bbp_get_topic_forum_id( $post_id );
3156 break;
3157
3158 // Reply
3159 case bbp_get_reply_post_type() :
3160 $forum_id = bbp_get_reply_forum_id( $post_id );
3161 break;
3162 }
3163
3164 // If forum is explicitly hidden and user not capable, set 404
3165 if ( ! empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
3166 bbp_set_404( $wp_query );
3167 }
3168 }
3169
3170 /**
3171 * Check if it's a private forum or a topic or reply of a private forum and if
3172 * the user can't view it, then sets a 404
3173 *
3174 * @since 2.0.0 bbPress (r2996)
3175 */
3176 function bbp_forum_enforce_private() {
3177
3178 // Bail if not viewing a single item or if user has caps
3179 if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_private_forums' ) ) {
3180 return;
3181 }
3182
3183 // Define local variables
3184 $forum_id = 0;
3185 $wp_query = bbp_get_wp_query();
3186 $post_id = ! empty( $wp_query->post->ID )
3187 ? $wp_query->post->ID
3188 : 0;
3189
3190 // Check post type
3191 switch ( $wp_query->get( 'post_type' ) ) {
3192
3193 // Forum
3194 case bbp_get_forum_post_type() :
3195 $forum_id = bbp_get_forum_id( $post_id );
3196 break;
3197
3198 // Topic
3199 case bbp_get_topic_post_type() :
3200 $forum_id = bbp_get_topic_forum_id( $post_id );
3201 break;
3202
3203 // Reply
3204 case bbp_get_reply_post_type() :
3205 $forum_id = bbp_get_reply_forum_id( $post_id );
3206 break;
3207 }
3208
3209 // If forum is explicitly hidden and user not capable, set 404
3210 if ( ! empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
3211 bbp_set_404( $wp_query );
3212 }
3213 }
3214
3215 /** Permissions ***************************************************************/
3216
3217 /**
3218 * Redirect if unauthorized user is attempting to edit a forum
3219 *
3220 * @since 2.1.0 bbPress (r3607)
3221 */
3222 function bbp_check_forum_edit() {
3223
3224 // Bail if not editing a topic
3225 if ( ! bbp_is_forum_edit() ) {
3226 return;
3227 }
3228
3229 // User cannot edit topic, so redirect back to reply
3230 if ( ! current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
3231 bbp_redirect( bbp_get_forum_permalink() );
3232 }
3233 }
3234
3235 /**
3236 * Delete all topics (and their replies) for a specific forum ID
3237 *
3238 * @since 2.1.0 bbPress (r3668)
3239 *
3240 * @param int $forum_id
3241 * @return If forum is not valid
3242 */
3243 function bbp_delete_forum_topics( $forum_id = 0 ) {
3244
3245 // Validate forum ID
3246 $forum_id = bbp_get_forum_id( $forum_id );
3247 if ( empty( $forum_id ) ) {
3248 return;
3249 }
3250
3251 // Forum is being permanently deleted, so its content has go too
3252 // Note that we get all post statuses here
3253 $topics = new WP_Query(
3254 array(
3255 'fields' => 'id=>parent',
3256 'post_type' => bbp_get_topic_post_type(),
3257 'post_parent' => $forum_id,
3258 'post_status' => array_keys( get_post_stati() ),
3259 'posts_per_page' => -1,
3260
3261 // Performance
3262 'nopaging' => true,
3263 'suppress_filters' => true,
3264 'update_post_term_cache' => false,
3265 'update_post_meta_cache' => false,
3266 'ignore_sticky_posts' => true,
3267 'no_found_rows' => true
3268 )
3269 );
3270
3271 // Loop through and delete child topics. Topic replies will get deleted by
3272 // the bbp_delete_topic() action.
3273 if ( ! empty( $topics->posts ) ) {
3274 foreach ( $topics->posts as $topic ) {
3275 wp_delete_post( $topic->ID, true );
3276 }
3277
3278 // Reset the $post global
3279 wp_reset_postdata();
3280 }
3281
3282 // Cleanup
3283 unset( $topics );
3284 }
3285
3286 /**
3287 * Trash all topics inside a forum
3288 *
3289 * @since 2.1.0 bbPress (r3668)
3290 *
3291 * @param int $forum_id
3292 * @return If forum is not valid
3293 */
3294 function bbp_trash_forum_topics( $forum_id = 0 ) {
3295
3296 // Validate forum ID
3297 $forum_id = bbp_get_forum_id( $forum_id );
3298 if ( empty( $forum_id ) ) {
3299 return;
3300 }
3301
3302 // Allowed post statuses to pre-trash
3303 $post_stati = array(
3304 bbp_get_public_status_id(),
3305 bbp_get_closed_status_id(),
3306 bbp_get_pending_status_id()
3307 );
3308
3309 // Forum is being trashed, so its topics (and replies) are trashed too
3310 $topics = new WP_Query(
3311 array(
3312 'fields' => 'id=>parent',
3313 'post_type' => bbp_get_topic_post_type(),
3314 'post_parent' => $forum_id,
3315 'post_status' => $post_stati,
3316 'posts_per_page' => -1,
3317
3318 // Performance
3319 'nopaging' => true,
3320 'suppress_filters' => true,
3321 'update_post_term_cache' => false,
3322 'update_post_meta_cache' => false,
3323 'ignore_sticky_posts' => true,
3324 'no_found_rows' => true
3325 )
3326 );
3327
3328 // Loop through and trash child topics. Topic replies will get trashed by
3329 // the bbp_trash_topic() action.
3330 if ( ! empty( $topics->posts ) ) {
3331
3332 // Prevent debug notices
3333 $pre_trashed_topics = array();
3334
3335 // Loop through topics, trash them, and add them to array
3336 foreach ( $topics->posts as $topic ) {
3337 wp_trash_post( $topic->ID, true );
3338 $pre_trashed_topics[] = $topic->ID;
3339 }
3340
3341 // Set a post_meta entry of the topics that were trashed by this action.
3342 // This is so we can possibly untrash them, without untrashing topics
3343 // that were purposefully trashed before.
3344 update_post_meta( $forum_id, '_bbp_pre_trashed_topics', $pre_trashed_topics );
3345
3346 // Reset the $post global
3347 wp_reset_postdata();
3348 }
3349
3350 // Cleanup
3351 unset( $topics );
3352 }
3353
3354 /**
3355 * Untrash all topics inside a forum
3356 *
3357 * @since 2.1.0 bbPress (r3668)
3358 *
3359 * @param int $forum_id
3360 * @return If forum is not valid
3361 */
3362 function bbp_untrash_forum_topics( $forum_id = 0 ) {
3363
3364 // Validate forum ID
3365 $forum_id = bbp_get_forum_id( $forum_id );
3366
3367 if ( empty( $forum_id ) ) {
3368 return;
3369 }
3370
3371 // Get the topics that were not previously trashed
3372 $pre_trashed_topics = get_post_meta( $forum_id, '_bbp_pre_trashed_topics', true );
3373
3374 // There are topics to untrash
3375 if ( ! empty( $pre_trashed_topics ) ) {
3376
3377 // Maybe reverse the trashed topics array
3378 if ( is_array( $pre_trashed_topics ) ) {
3379 $pre_trashed_topics = array_reverse( $pre_trashed_topics );
3380 }
3381
3382 // Loop through topics
3383 foreach ( (array) $pre_trashed_topics as $topic ) {
3384 wp_untrash_post( $topic );
3385 }
3386 }
3387 }
3388
3389 /** Before Delete/Trash/Untrash ***********************************************/
3390
3391 /**
3392 * Called before deleting a forum.
3393 *
3394 * This function is supplemental to the actual forum deletion which is
3395 * handled by WordPress core API functions. It is used to clean up after
3396 * a forum that is being deleted.
3397 *
3398 * @since 2.1.0 bbPress (r3668)
3399 */
3400 function bbp_delete_forum( $forum_id = 0 ) {
3401 $forum_id = bbp_get_forum_id( $forum_id );
3402
3403 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
3404 return false;
3405 }
3406
3407 do_action( 'bbp_delete_forum', $forum_id );
3408 }
3409
3410 /**
3411 * Called before trashing a forum
3412 *
3413 * This function is supplemental to the actual forum being trashed which is
3414 * handled by WordPress core API functions. It is used to clean up after
3415 * a forum that is being trashed.
3416 *
3417 * @since 2.1.0 bbPress (r3668)
3418 */
3419 function bbp_trash_forum( $forum_id = 0 ) {
3420 $forum_id = bbp_get_forum_id( $forum_id );
3421
3422 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
3423 return false;
3424 }
3425
3426 do_action( 'bbp_trash_forum', $forum_id );
3427 }
3428
3429 /**
3430 * Called before untrashing a forum
3431 *
3432 * @since 2.1.0 bbPress (r3668)
3433 */
3434 function bbp_untrash_forum( $forum_id = 0 ) {
3435 $forum_id = bbp_get_forum_id( $forum_id );
3436
3437 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
3438 return false;
3439 }
3440
3441 do_action( 'bbp_untrash_forum', $forum_id );
3442 }
3443
3444 /** After Delete/Trash/Untrash ************************************************/
3445
3446 /**
3447 * Called after deleting a forum
3448 *
3449 * Try not to use this action. All meta & taxonomy terms have already been
3450 * deleted, making them impossible to use.
3451 *
3452 * @since 2.1.0 bbPress (r3668)
3453 * @since 2.6.0 bbPress (r6526) Not recommend for usage
3454 * @since 2.6.17 Added the `$forum` parameter and passed it to the action.
3455 *
3456 * @param int $forum_id Forum ID.
3457 * @param WP_Post|bool $forum Optional. Deleted forum post object.
3458 * @return false|null False if the post is not a forum, otherwise null.
3459 */
3460 function bbp_deleted_forum( $forum_id = 0, $forum = false ) {
3461 $forum_id = bbp_get_forum_id( $forum_id );
3462 $forum = ( $forum instanceof WP_Post )
3463 ? $forum
3464 : get_post( $forum_id );
3465
3466 if ( empty( $forum_id ) || ! $forum || ( bbp_get_forum_post_type() !== $forum->post_type ) ) {
3467 return false;
3468 }
3469
3470 do_action( 'bbp_deleted_forum', $forum_id, $forum );
3471 }
3472
3473 /**
3474 * Called after trashing a forum
3475 *
3476 * @since 2.1.0 bbPress (r3668)
3477 */
3478 function bbp_trashed_forum( $forum_id = 0 ) {
3479 $forum_id = bbp_get_forum_id( $forum_id );
3480
3481 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
3482 return false;
3483 }
3484
3485 do_action( 'bbp_trashed_forum', $forum_id );
3486 }
3487
3488 /**
3489 * Called after untrashing a forum
3490 *
3491 * @since 2.1.0 bbPress (r3668)
3492 */
3493 function bbp_untrashed_forum( $forum_id = 0 ) {
3494 $forum_id = bbp_get_forum_id( $forum_id );
3495
3496 if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
3497 return false;
3498 }
3499
3500 do_action( 'bbp_untrashed_forum', $forum_id );
3501 }
3502