PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.4.2
Forumax – AI Powered Advanced Community Forum Plugin v2.4.2
2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 2.0.0 2.1.0 All 29 releases
bbp-core / lib / bbpress / includes / topics / functions.php

functions.php in Forumax – AI Powered Advanced Community Forum Plugin 2.4.2, at lib/bbpress/includes/topics/functions.php

3,880 lines 114.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress Topic 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 topic to function properly.
18 *
19 * @since 2.0.0 bbPress (r3349)
20 *
21 * @param array $topic_data Forum post data
22 * @param array $topic_meta Forum meta data
23 */
24 function bbp_insert_topic( $topic_data = array(), $topic_meta = array() ) {
25
26 // Parse arguments against default values
27 $topic_data = bbp_parse_args( $topic_data, array(
28 'post_parent' => 0, // forum ID
29 'post_status' => bbp_get_public_status_id(),
30 'post_type' => bbp_get_topic_post_type(),
31 'post_author' => bbp_get_current_user_id(),
32 'post_password' => '',
33 'post_content' => '',
34 'post_title' => '',
35 'comment_status' => 'closed',
36 'menu_order' => 0
37 ), 'insert_topic' );
38
39 // Insert topic
40 $topic_id = wp_insert_post( $topic_data, false );
41
42 // Bail if no topic was added
43 if ( empty( $topic_id ) ) {
44 return false;
45 }
46
47 // Parse arguments against default values
48 $topic_meta = bbp_parse_args( $topic_meta, array(
49 'author_ip' => bbp_current_author_ip(),
50 'forum_id' => 0,
51 'topic_id' => $topic_id,
52 'voice_count' => 1,
53 'reply_count' => 0,
54 'reply_count_hidden' => 0,
55 'last_reply_id' => 0,
56 'last_active_id' => $topic_id,
57 'last_active_time' => get_post_field( 'post_date', $topic_id, 'db' )
58 ), 'insert_topic_meta' );
59
60 // Insert topic meta
61 foreach ( $topic_meta as $meta_key => $meta_value ) {
62
63 // Prefix if not prefixed
64 if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
65 $meta_key = '_bbp_' . $meta_key;
66 }
67
68 // Update the meta
69 update_post_meta( $topic_id, $meta_key, $meta_value );
70 }
71
72 // Update the topic and hierarchy
73 bbp_update_topic( $topic_id, $topic_meta['forum_id'], array(), $topic_data['post_author'], false );
74
75 /**
76 * Fires after topic has been inserted via `bbp_insert_topic`.
77 *
78 * @since 2.6.0 bbPress (r6036)
79 *
80 * @param int $topic_id The topic id.
81 * @param int $topic_meta['forum_id'] The topic forum meta.
82 */
83 do_action( 'bbp_insert_topic', (int) $topic_id, (int) $topic_meta['forum_id'] );
84
85 // Return topic_id
86 return $topic_id;
87 }
88
89 /** Post Form Handlers ********************************************************/
90
91 /**
92 * Handles the front end topic submission
93 *
94 * @param string $action The requested action to compare this function to
95 */
96 function bbp_new_topic_handler( $action = '' ) {
97
98 // Bail if action is not bbp-new-topic
99 if ( 'bbp-new-topic' !== $action ) {
100 return;
101 }
102
103 // Nonce check
104 if ( ! bbp_verify_nonce_request( 'bbp-new-topic' ) ) {
105 bbp_add_error( 'bbp_new_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
106 return;
107 }
108
109 // Define local variable(s)
110 $view_all = false;
111 $forum_id = $topic_author = 0;
112 $topic_title = $topic_content = '';
113 $anonymous_data = array();
114 $terms = array( bbp_get_topic_tag_tax_id() => array() );
115
116 /** Topic Author **********************************************************/
117
118 // User is anonymous
119 if ( bbp_is_anonymous() ) {
120
121 // Filter anonymous data (variable is used later)
122 $anonymous_data = bbp_filter_anonymous_post_data();
123
124 // Anonymous data checks out, so set cookies, etc...
125 bbp_set_current_anonymous_user_data( $anonymous_data );
126
127 // User is logged in
128 } else {
129
130 // User cannot create topics
131 if ( ! current_user_can( 'publish_topics' ) ) {
132 bbp_add_error( 'bbp_topic_permission', __( '<strong>Error</strong>: You do not have permission to create new topics.', 'bbpress' ) );
133 return;
134 }
135
136 // Topic author is current user
137 $topic_author = bbp_get_current_user_id();
138 }
139
140 // Remove kses filters from title and content for capable users and if the nonce is verified
141 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_topic'] ) && wp_create_nonce( 'bbp-unfiltered-html-topic_new' ) === $_POST['_bbp_unfiltered_html_topic'] ) {
142 remove_filter( 'bbp_new_topic_pre_title', 'wp_filter_kses' );
143 remove_filter( 'bbp_new_topic_pre_content', 'bbp_encode_bad', 10 );
144 remove_filter( 'bbp_new_topic_pre_content', 'bbp_filter_kses', 30 );
145 }
146
147 /** Topic Title ***********************************************************/
148
149 if ( ! empty( $_POST['bbp_topic_title'] ) ) {
150 $topic_title = sanitize_text_field( $_POST['bbp_topic_title'] );
151 }
152
153 // Filter and sanitize
154 $topic_title = apply_filters( 'bbp_new_topic_pre_title', $topic_title );
155
156 // No topic title
157 if ( empty( $topic_title ) ) {
158 bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your topic needs a title.', 'bbpress' ) );
159 }
160
161 // Title too long
162 if ( bbp_is_title_too_long( $topic_title ) ) {
163 bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
164 }
165
166 /** Topic Content *********************************************************/
167
168 if ( ! empty( $_POST['bbp_topic_content'] ) ) {
169 $topic_content = $_POST['bbp_topic_content'];
170 }
171
172 // Filter and sanitize
173 $topic_content = apply_filters( 'bbp_new_topic_pre_content', $topic_content );
174
175 // No topic content
176 if ( empty( $topic_content ) ) {
177 bbp_add_error( 'bbp_topic_content', __( '<strong>Error</strong>: Your topic cannot be empty.', 'bbpress' ) );
178 }
179
180 /** Topic Forum ***********************************************************/
181
182 // Error check the POST'ed topic id
183 if ( isset( $_POST['bbp_forum_id'] ) ) {
184
185 // Empty Forum id was passed
186 if ( empty( $_POST['bbp_forum_id'] ) ) {
187 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );
188
189 // Forum id is not a number
190 } elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) {
191 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID must be a number.', 'bbpress' ) );
192
193 // Forum id might be valid
194 } else {
195
196 // Get the forum id
197 $posted_forum_id = intval( $_POST['bbp_forum_id'] );
198
199 // Forum id is empty
200 if ( 0 === $posted_forum_id ) {
201 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );
202
203 // Forum id is a negative number
204 } elseif ( 0 > $posted_forum_id ) {
205 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID cannot be a negative number.', 'bbpress' ) );
206
207 // Forum does not exist
208 } elseif ( ! bbp_get_forum( $posted_forum_id ) ) {
209 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum does not exist.', 'bbpress' ) );
210
211 // Use the POST'ed forum id
212 } else {
213 $forum_id = $posted_forum_id;
214 }
215 }
216 }
217
218 // Forum exists
219 if ( ! empty( $forum_id ) ) {
220
221 // Forum is a category
222 if ( bbp_is_forum_category( $forum_id ) ) {
223 bbp_add_error( 'bbp_new_topic_forum_category', __( '<strong>Error</strong>: This forum is a category. No topics can be created in this forum.', 'bbpress' ) );
224
225 // Forum is not a category
226 } else {
227
228 // Forum is closed and user cannot access
229 if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
230 bbp_add_error( 'bbp_new_topic_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new topics.', 'bbpress' ) );
231 }
232
233 // Forum is private and user cannot access
234 if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
235 bbp_add_error( 'bbp_new_topic_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
236
237 // Forum is hidden and user cannot access
238 } elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
239 bbp_add_error( 'bbp_new_topic_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
240 }
241 }
242 }
243
244 /** Topic Flooding ********************************************************/
245
246 if ( ! bbp_check_for_flood( $anonymous_data, $topic_author ) ) {
247 bbp_add_error( 'bbp_topic_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
248 }
249
250 /** Topic Duplicate *******************************************************/
251
252 $dupe_args = array(
253 'post_type' => bbp_get_topic_post_type(),
254 'post_author' => $topic_author,
255 'post_content' => $topic_content,
256 'post_parent' => $forum_id,
257 'anonymous_data' => $anonymous_data
258 );
259
260 if ( ! bbp_check_for_duplicate( $dupe_args ) ) {
261 bbp_add_error( 'bbp_topic_duplicate', __( '<strong>Error</strong>: Duplicate topic detected; it looks as though you&#8217;ve already said that.', 'bbpress' ) );
262 }
263
264 /** Topic Bad Words *******************************************************/
265
266 if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content, true ) ) {
267 bbp_add_error( 'bbp_topic_moderation', __( '<strong>Error</strong>: Your topic cannot be created at this time.', 'bbpress' ) );
268 }
269
270 /** Topic Status **********************************************************/
271
272 // Get available topic statuses
273 $topic_statuses = bbp_get_topic_statuses();
274
275 // Default to published
276 $topic_status = bbp_get_public_status_id();
277
278 // Maybe force into pending
279 if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {
280 $topic_status = bbp_get_pending_status_id();
281
282 // Check for possible posted topic status
283 } elseif ( ! empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( $topic_statuses ), true ) ) {
284
285 // Allow capable users to explicitly override the status
286 if ( current_user_can( 'moderate', $forum_id ) ) {
287 $topic_status = sanitize_key( $_POST['bbp_topic_status'] );
288
289 // Not capable
290 } else {
291 bbp_add_error( 'bbp_new_topic_status', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) );
292 }
293 }
294
295 /** Topic Tags ************************************************************/
296
297 if ( bbp_allow_topic_tags() && ! empty( $_POST['bbp_topic_tags'] ) ) {
298
299 // Escape tag input
300 $terms = sanitize_text_field( $_POST['bbp_topic_tags'] );
301
302 // Explode by comma
303 if ( strstr( $terms, ',' ) ) {
304 $terms = explode( ',', $terms );
305 }
306
307 // Add topic tag ID as main key
308 $terms = array( bbp_get_topic_tag_tax_id() => $terms );
309 }
310
311 /** Additional Actions (Before Save) **************************************/
312
313 do_action( 'bbp_new_topic_pre_extras', $forum_id );
314
315 // Bail if errors
316 if ( bbp_has_errors() ) {
317 return;
318 }
319
320 /** No Errors *************************************************************/
321
322 // Add the content of the form to $topic_data as an array.
323 // Just in time manipulation of topic data before being created
324 $topic_data = apply_filters( 'bbp_new_topic_pre_insert', array(
325 'post_author' => $topic_author,
326 'post_title' => $topic_title,
327 'post_content' => $topic_content,
328 'post_status' => $topic_status,
329 'post_parent' => $forum_id,
330 'post_type' => bbp_get_topic_post_type(),
331 'tax_input' => $terms,
332 'comment_status' => 'closed'
333 ) );
334
335 // Insert topic
336 $topic_id = wp_insert_post( $topic_data, true );
337
338 /** No Errors *************************************************************/
339
340 if ( ! empty( $topic_id ) && ! is_wp_error( $topic_id ) ) {
341
342 /** Close Check *******************************************************/
343
344 // If the topic is closed, close it properly
345 if ( ( get_post_field( 'post_status', $topic_id ) === bbp_get_closed_status_id() ) || ( $topic_data['post_status'] === bbp_get_closed_status_id() ) ) {
346
347 // Close the topic
348 bbp_close_topic( $topic_id );
349 }
350
351 /** Trash Check *******************************************************/
352
353 // If the forum is trash, or the topic_status is switched to
354 // trash, trash the topic properly
355 if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $topic_data['post_status'] === bbp_get_trash_status_id() ) ) {
356
357 // Trash the topic
358 wp_trash_post( $topic_id );
359
360 // Force view=all
361 $view_all = true;
362 }
363
364 /** Spam Check ********************************************************/
365
366 // If the topic is spam, officially spam this topic
367 if ( $topic_data['post_status'] === bbp_get_spam_status_id() ) {
368 add_post_meta( $topic_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
369
370 // Force view=all
371 $view_all = true;
372 }
373
374 /** Update counts, etc... *********************************************/
375
376 do_action( 'bbp_new_topic', $topic_id, $forum_id, $anonymous_data, $topic_data['post_author'] );
377
378 /** Additional Actions (After Save) ***********************************/
379
380 do_action( 'bbp_new_topic_post_extras', $topic_id );
381
382 /** Redirect **********************************************************/
383
384 // Redirect to
385 $redirect_to = bbp_get_redirect_to();
386
387 // Get the topic URL
388 $redirect_url = bbp_get_topic_permalink( $topic_id, $redirect_to );
389
390 // Add view all?
391 if ( bbp_get_view_all() || ! empty( $view_all ) ) {
392
393 // User can moderate, so redirect to topic with view all set
394 if ( current_user_can( 'moderate', $topic_id ) ) {
395 $redirect_url = bbp_add_view_all( $redirect_url );
396
397 // User cannot moderate, so redirect to forum
398 } else {
399 $redirect_url = bbp_get_forum_permalink( $forum_id );
400 }
401 }
402
403 // Allow to be filtered
404 $redirect_url = apply_filters( 'bbp_new_topic_redirect_to', $redirect_url, $redirect_to, $topic_id );
405
406 /** Successful Save ***************************************************/
407
408 // Redirect back to new topic
409 bbp_redirect( $redirect_url );
410
411 /** Errors ****************************************************************/
412
413 // WP_Error
414 } elseif ( is_wp_error( $topic_id ) ) {
415 bbp_add_error( 'bbp_topic_error', sprintf( __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ), $topic_id->get_error_message() ) );
416
417 // Generic error
418 } else {
419 bbp_add_error( 'bbp_topic_error', __( '<strong>Error</strong>: The topic was not created.', 'bbpress' ) );
420 }
421 }
422
423 /**
424 * Handles the front end edit topic submission
425 *
426 * @param string $action The requested action to compare this function to
427 */
428 function bbp_edit_topic_handler( $action = '' ) {
429
430 // Bail if action is not bbp-edit-topic
431 if ( 'bbp-edit-topic' !== $action ) {
432 return;
433 }
434
435 // Define local variable(s)
436 $revisions_removed = false;
437 $topic = $topic_id = $topic_author = $forum_id = 0;
438 $topic_title = $topic_content = $topic_edit_reason = '';
439 $anonymous_data = array();
440
441 /** Topic *****************************************************************/
442
443 // Topic id was not passed
444 if ( empty( $_POST['bbp_topic_id'] ) ) {
445 bbp_add_error( 'bbp_edit_topic_id', __( '<strong>Error</strong>: Topic ID not found.', 'bbpress' ) );
446 return;
447
448 // Topic id was passed
449 } elseif ( is_numeric( $_POST['bbp_topic_id'] ) ) {
450 $topic_id = (int) $_POST['bbp_topic_id'];
451 $topic = bbp_get_topic( $topic_id );
452 }
453
454 // Topic does not exist
455 if ( empty( $topic ) ) {
456 bbp_add_error( 'bbp_edit_topic_not_found', __( '<strong>Error</strong>: The topic you want to edit was not found.', 'bbpress' ) );
457 return;
458
459 // Topic exists
460 } else {
461
462 // Check users ability to create new topic
463 if ( ! bbp_is_topic_anonymous( $topic_id ) ) {
464
465 // User cannot edit this topic
466 if ( ! current_user_can( 'edit_topic', $topic_id ) ) {
467 bbp_add_error( 'bbp_edit_topic_permission', __( '<strong>Error</strong>: You do not have permission to edit that topic.', 'bbpress' ) );
468 }
469
470 // Set topic author
471 $topic_author = bbp_get_topic_author_id( $topic_id );
472
473 // It is an anonymous post
474 } else {
475
476 // Filter anonymous data
477 $anonymous_data = bbp_filter_anonymous_post_data();
478 }
479 }
480
481 // Nonce check
482 if ( ! bbp_verify_nonce_request( 'bbp-edit-topic_' . $topic_id ) ) {
483 bbp_add_error( 'bbp_edit_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
484 return;
485 }
486
487 // Remove kses filters from title and content for capable users and if the nonce is verified
488 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_topic'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-topic_' . $topic_id ) === $_POST['_bbp_unfiltered_html_topic'] ) ) {
489 remove_filter( 'bbp_edit_topic_pre_title', 'wp_filter_kses' );
490 remove_filter( 'bbp_edit_topic_pre_content', 'bbp_encode_bad', 10 );
491 remove_filter( 'bbp_edit_topic_pre_content', 'bbp_filter_kses', 30 );
492 }
493
494 /** Topic Forum ***********************************************************/
495
496 // Forum id was not passed
497 if ( empty( $_POST['bbp_forum_id'] ) ) {
498 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );
499
500 // Forum id was passed
501 } elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
502 $forum_id = (int) $_POST['bbp_forum_id'];
503 }
504
505 // Current forum this topic is in
506 $current_forum_id = bbp_get_topic_forum_id( $topic_id );
507
508 // Forum exists
509 if ( ! empty( $forum_id ) && ( $forum_id !== $current_forum_id ) ) {
510
511 // Forum is a category
512 if ( bbp_is_forum_category( $forum_id ) ) {
513 bbp_add_error( 'bbp_edit_topic_forum_category', __( '<strong>Error</strong>: This forum is a category. No topics can be created in it.', 'bbpress' ) );
514
515 // Forum is not a category
516 } else {
517
518 // Forum is closed and user cannot access
519 if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
520 bbp_add_error( 'bbp_edit_topic_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new topics.', 'bbpress' ) );
521 }
522
523 // Forum is private and user cannot access
524 if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
525 bbp_add_error( 'bbp_edit_topic_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
526
527 // Forum is hidden and user cannot access
528 } elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
529 bbp_add_error( 'bbp_edit_topic_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
530 }
531 }
532 }
533
534 /** Topic Title ***********************************************************/
535
536 if ( ! empty( $_POST['bbp_topic_title'] ) ) {
537 $topic_title = sanitize_text_field( $_POST['bbp_topic_title'] );
538 }
539
540 // Filter and sanitize
541 $topic_title = apply_filters( 'bbp_edit_topic_pre_title', $topic_title, $topic_id );
542
543 // No topic title
544 if ( empty( $topic_title ) ) {
545 bbp_add_error( 'bbp_edit_topic_title', __( '<strong>Error</strong>: Your topic needs a title.', 'bbpress' ) );
546 }
547
548 // Title too long
549 if ( bbp_is_title_too_long( $topic_title ) ) {
550 bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
551 }
552
553 /** Topic Content *********************************************************/
554
555 if ( ! empty( $_POST['bbp_topic_content'] ) ) {
556 $topic_content = $_POST['bbp_topic_content'];
557 }
558
559 // Filter and sanitize
560 $topic_content = apply_filters( 'bbp_edit_topic_pre_content', $topic_content, $topic_id );
561
562 // No topic content
563 if ( empty( $topic_content ) ) {
564 bbp_add_error( 'bbp_edit_topic_content', __( '<strong>Error</strong>: Your topic cannot be empty.', 'bbpress' ) );
565 }
566
567 /** Topic Bad Words *******************************************************/
568
569 if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content, true ) ) {
570 bbp_add_error( 'bbp_topic_moderation', __( '<strong>Error</strong>: Your topic cannot be edited at this time.', 'bbpress' ) );
571 }
572
573 /** Topic Status **********************************************************/
574
575 // Get available topic statuses
576 $topic_statuses = bbp_get_topic_statuses( $topic_id );
577
578 // Use existing post_status
579 $topic_status = $topic->post_status;
580
581 // Maybe force into pending
582 if ( bbp_is_topic_public( $topic_id ) && ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {
583 $topic_status = bbp_get_pending_status_id();
584
585 // Check for possible posted topic status
586 } elseif ( ! empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( $topic_statuses ), true ) ) {
587
588 // Allow capable users to explicitly override the status
589 if ( current_user_can( 'moderate', $topic_id ) ) {
590 $topic_status = sanitize_key( $_POST['bbp_topic_status'] );
591
592 // Not capable
593 } else {
594 bbp_add_error( 'bbp_edit_topic_status', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) );
595 }
596 }
597
598 /** Topic Tags ************************************************************/
599
600 // Either replace terms
601 if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
602
603 // Escape tag input
604 $terms = sanitize_text_field( $_POST['bbp_topic_tags'] );
605
606 // Explode by comma
607 if ( strstr( $terms, ',' ) ) {
608 $terms = explode( ',', $terms );
609 }
610
611 // Add topic tag ID as main key
612 $terms = array( bbp_get_topic_tag_tax_id() => $terms );
613
614 // ...or remove them.
615 } elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
616 $terms = array( bbp_get_topic_tag_tax_id() => array() );
617
618 // Existing terms
619 } else {
620 $terms = array( bbp_get_topic_tag_tax_id() => explode( ',', bbp_get_topic_tag_names( $topic_id, ',' ) ) );
621 }
622
623 /** Additional Actions (Before Save) **************************************/
624
625 do_action( 'bbp_edit_topic_pre_extras', $topic_id );
626
627 // Bail if errors
628 if ( bbp_has_errors() ) {
629 return;
630 }
631
632 /** No Errors *************************************************************/
633
634 // Add the content of the form to $topic_data as an array
635 // Just in time manipulation of topic data before being edited
636 $topic_data = apply_filters( 'bbp_edit_topic_pre_insert', array(
637 'ID' => $topic_id,
638 'post_title' => $topic_title,
639 'post_content' => $topic_content,
640 'post_status' => $topic_status,
641 'post_parent' => $forum_id,
642 'post_author' => $topic_author,
643 'post_type' => bbp_get_topic_post_type(),
644 'tax_input' => $terms,
645 ) );
646
647 // Toggle revisions to avoid duplicates
648 if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
649 $revisions_removed = true;
650 remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
651 }
652
653 // Insert topic
654 $topic_id = wp_update_post( $topic_data );
655
656 // Toggle revisions back on
657 if ( true === $revisions_removed ) {
658 $revisions_removed = false;
659 add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
660 }
661
662 /** No Errors *************************************************************/
663
664 if ( ! empty( $topic_id ) && ! is_wp_error( $topic_id ) ) {
665
666 // Update counts, etc...
667 do_action( 'bbp_edit_topic', $topic_id, $forum_id, $anonymous_data, $topic_data['post_author'], true /* Is edit */ );
668
669 /** Revisions *********************************************************/
670
671 // Update locks
672 update_post_meta( $topic_id, '_edit_last', bbp_get_current_user_id() );
673 delete_post_meta( $topic_id, '_edit_lock' );
674
675 // Revision Reason
676 if ( ! empty( $_POST['bbp_topic_edit_reason'] ) ) {
677 $topic_edit_reason = sanitize_text_field( $_POST['bbp_topic_edit_reason'] );
678 }
679
680 // Update revision log
681 if ( ! empty( $_POST['bbp_log_topic_edit'] ) && ( "1" === $_POST['bbp_log_topic_edit'] ) ) {
682 $revision_id = wp_save_post_revision( $topic_id );
683 if ( ! empty( $revision_id ) ) {
684 bbp_update_topic_revision_log( array(
685 'topic_id' => $topic_id,
686 'revision_id' => $revision_id,
687 'author_id' => bbp_get_current_user_id(),
688 'reason' => $topic_edit_reason
689 ) );
690 }
691 }
692
693 /** Move Topic ********************************************************/
694
695 // If the new forum id is not equal to the old forum id, run the
696 // bbp_move_topic action and pass the topic's forum id as the
697 // first arg and topic id as the second to update counts.
698 if ( $forum_id !== $topic->post_parent ) {
699 bbp_move_topic_handler( $topic_id, $topic->post_parent, $forum_id );
700 }
701
702 /** Additional Actions (After Save) ***********************************/
703
704 do_action( 'bbp_edit_topic_post_extras', $topic_id );
705
706 /** Redirect **********************************************************/
707
708 // Redirect to
709 $redirect_to = bbp_get_redirect_to();
710
711 // View all?
712 $view_all = bbp_get_view_all( 'edit_others_replies' );
713
714 // Get the topic URL
715 $topic_url = bbp_get_topic_permalink( $topic_id, $redirect_to );
716
717 // Add view all?
718 if ( ! empty( $view_all ) ) {
719 $topic_url = bbp_add_view_all( $topic_url );
720 }
721
722 // Allow to be filtered
723 $topic_url = apply_filters( 'bbp_edit_topic_redirect_to', $topic_url, $view_all, $redirect_to );
724
725 /** Successful Edit ***************************************************/
726
727 // Redirect back to new topic
728 bbp_redirect( $topic_url );
729
730 /** Errors ****************************************************************/
731
732 } else {
733 $append_error = ( is_wp_error( $topic_id ) && $topic_id->get_error_message() ) ? $topic_id->get_error_message() . ' ' : '';
734 bbp_add_error( 'bbp_topic_error', __( '<strong>Error</strong>: The following problem(s) have been found with your topic:' . $append_error . 'Please try again.', 'bbpress' ) );
735 }
736 }
737
738 /**
739 * Handle all the extra meta stuff from posting a new topic
740 *
741 * @param int $topic_id Optional. Topic id
742 * @param int $forum_id Optional. Forum id
743 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
744 * supply if supplying $author_id. Should be
745 * sanitized (see {@link bbp_filter_anonymous_post_data()}
746 * @param int $author_id Author id
747 * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
748 */
749 function bbp_update_topic( $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $author_id = 0, $is_edit = false ) {
750
751 // Validate the ID's passed from 'bbp_new_topic' action
752 $topic_id = bbp_get_topic_id( $topic_id );
753 $forum_id = bbp_get_forum_id( $forum_id );
754
755 // Bail if there is no topic
756 if ( empty( $topic_id ) ) {
757 return;
758 }
759
760 // Check author_id
761 if ( empty( $author_id ) ) {
762 $author_id = bbp_get_current_user_id();
763 }
764
765 // Forum/Topic meta (early, for use in downstream functions)
766 bbp_update_topic_forum_id( $topic_id, $forum_id );
767 bbp_update_topic_topic_id( $topic_id, $topic_id );
768
769 // Get the topic types
770 $topic_types = bbp_get_topic_types( $topic_id );
771
772 // Sticky check after 'bbp_new_topic' action so forum ID meta is set
773 if ( ! empty( $_POST['bbp_stick_topic'] ) && in_array( $_POST['bbp_stick_topic'], array_keys( $topic_types ), true ) ) {
774
775 // What's the caps?
776 if ( current_user_can( 'moderate', $topic_id ) ) {
777
778 // What's the haps?
779 switch ( $_POST['bbp_stick_topic'] ) {
780
781 // Sticky in this forum
782 case 'stick' :
783 bbp_stick_topic( $topic_id );
784 break;
785
786 // Super sticky in all forums
787 case 'super' :
788 bbp_stick_topic( $topic_id, true );
789 break;
790
791 // Unsticky from everywhere
792 case 'unstick' :
793 default :
794 bbp_unstick_topic( $topic_id );
795 break;
796 }
797 }
798 }
799
800 // If anonymous post, store name, email, website and ip in post_meta.
801 if ( ! empty( $anonymous_data ) ) {
802
803 // Update anonymous meta data (not cookies)
804 bbp_update_anonymous_post_author( $topic_id, $anonymous_data, bbp_get_topic_post_type() );
805
806 // Set transient for throttle check (only on new, not edit)
807 if ( empty( $is_edit ) ) {
808 set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time(), HOUR_IN_SECONDS );
809 }
810 }
811
812 // Handle Subscription Checkbox
813 if ( bbp_is_subscriptions_active() && ! empty( $author_id ) ) {
814
815 // Check if subscribed
816 $subscribed = bbp_is_user_subscribed( $author_id, $topic_id );
817
818 // Check for action
819 $subscheck = ( ! empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) )
820 ? true
821 : false;
822
823 // Subscribed and unsubscribing
824 if ( ( true === $subscribed ) && ( false === $subscheck ) ) {
825 bbp_remove_user_subscription( $author_id, $topic_id );
826
827 // Not subscribed and subscribing
828 } elseif ( ( false === $subscribed ) && ( true === $subscheck ) ) {
829 bbp_add_user_subscription( $author_id, $topic_id );
830 }
831 }
832
833 // Update associated topic values if this is a new topic
834 if ( empty( $is_edit ) ) {
835
836 // Update poster activity time
837 bbp_update_user_last_posted( $author_id );
838
839 // Update poster IP
840 update_post_meta( $topic_id, '_bbp_author_ip', bbp_current_author_ip(), false );
841
842 // Last active time
843 $last_active = get_post_field( 'post_date', $topic_id );
844
845 // Reply topic meta
846 bbp_update_topic_last_reply_id ( $topic_id, 0 );
847 bbp_update_topic_last_active_id ( $topic_id, $topic_id );
848 bbp_update_topic_last_active_time ( $topic_id, $last_active );
849 bbp_update_topic_reply_count ( $topic_id, 0 );
850 bbp_update_topic_reply_count_hidden ( $topic_id, 0 );
851 bbp_update_topic_voice_count ( $topic_id );
852
853 // Walk up ancestors and do the dirty work
854 bbp_update_topic_walker( $topic_id, $last_active, $forum_id, 0, false );
855 }
856
857 // Bump the custom query cache
858 wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
859 }
860
861 /**
862 * Walks up the post_parent tree from the current topic_id, and updates the
863 * meta data of forums above it. This calls several functions that all run
864 * manual queries against the database to get their results. As such, this
865 * function can be costly to run but is necessary to keep everything accurate.
866 *
867 * @since 2.0.0 bbPress (r2800)
868 *
869 * @param int $topic_id Topic id
870 * @param string $last_active_time Optional. Last active time
871 * @param int $forum_id Optional. Forum id
872 * @param int $reply_id Optional. Reply id
873 * @param bool $refresh Reset all the previous parameters? Defaults to true.
874 */
875 function bbp_update_topic_walker( $topic_id, $last_active_time = '', $forum_id = 0, $reply_id = 0, $refresh = true ) {
876
877 // Validate topic_id
878 $topic_id = bbp_get_topic_id( $topic_id );
879
880 // Define local variable(s)
881 $active_id = 0;
882
883 // Topic was passed
884 if ( ! empty( $topic_id ) ) {
885
886 // Get the forum ID if none was passed
887 if ( empty( $forum_id ) ) {
888 $forum_id = bbp_get_topic_forum_id( $topic_id );
889 }
890
891 // Set the active_id based on topic_id/reply_id
892 $active_id = empty( $reply_id ) ? $topic_id : $reply_id;
893 }
894
895 // Get topic ancestors
896 $ancestors = array_values( array_unique( array_merge( array( $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) );
897
898 // Topic status
899 $topic_status = get_post_status( $topic_id );
900
901 // If we want a full refresh, unset any of the possibly passed variables
902 if ( true === $refresh ) {
903 $forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0;
904 $topic_status = bbp_get_public_status_id();
905 }
906
907 // Loop through ancestors
908 if ( ! empty( $ancestors ) ) {
909 foreach ( $ancestors as $ancestor ) {
910
911 // If ancestor is a forum, update counts
912 if ( bbp_is_forum( $ancestor ) ) {
913
914 // Get the forum
915 $forum = bbp_get_forum( $ancestor );
916
917 // Update the forum
918 bbp_update_forum( array(
919 'forum_id' => $forum->ID,
920 'post_parent' => $forum->post_parent,
921 'last_topic_id' => $topic_id,
922 'last_reply_id' => $reply_id,
923 'last_active_id' => $active_id,
924 'last_active_time' => $last_active_time,
925 'last_active_status' => $topic_status
926 ) );
927 }
928 }
929 }
930 }
931
932 /**
933 * Handle the moving of a topic from one forum to another. This includes walking
934 * up the old and new branches and updating the counts.
935 *
936 * @since 2.0.0 bbPress (r2907)
937 *
938 * @param int $topic_id The topic id.
939 * @param int $old_forum_id Old forum id.
940 * @param int $new_forum_id New forum id.
941 */
942 function bbp_move_topic_handler( $topic_id, $old_forum_id, $new_forum_id ) {
943
944 // Validate parameters
945 $topic_id = bbp_get_topic_id( $topic_id );
946 $old_forum_id = bbp_get_forum_id( $old_forum_id );
947 $new_forum_id = bbp_get_forum_id( $new_forum_id );
948
949 // Clean old and new forum caches before proceeding, to ensure subsequent
950 // calls to forum objects are using updated data.
951 clean_post_cache( $old_forum_id );
952 clean_post_cache( $new_forum_id );
953
954 // Update topic forum's ID
955 bbp_update_topic_forum_id( $topic_id, $new_forum_id );
956
957 // Update topic post parent with the new forum ID
958 wp_update_post( array(
959 'ID' => $topic_id,
960 'post_parent' => $new_forum_id,
961 ) );
962
963 /** Stickies **************************************************************/
964
965 // Get forum stickies
966 $old_stickies = bbp_get_stickies( $old_forum_id );
967
968 // Only proceed if stickies are found
969 if ( ! empty( $old_stickies ) ) {
970
971 // Define local variables
972 $updated_stickies = array();
973
974 // Loop through stickies of forum and add misses to the updated array
975 foreach ( (array) $old_stickies as $sticky_topic_id ) {
976 if ( $topic_id !== $sticky_topic_id ) {
977 $updated_stickies[] = $sticky_topic_id;
978 }
979 }
980
981 // If stickies are different, update or delete them
982 if ( $updated_stickies !== $old_stickies ) {
983
984 // No more stickies so delete the meta
985 if ( empty( $updated_stickies ) ) {
986 delete_post_meta( $old_forum_id, '_bbp_sticky_topics' );
987
988 // Still stickies so update the meta
989 } else {
990 update_post_meta( $old_forum_id, '_bbp_sticky_topics', $updated_stickies );
991 }
992
993 // Topic was sticky, so restick in new forum
994 bbp_stick_topic( $topic_id );
995 }
996 }
997
998 /** Topic Replies *********************************************************/
999
1000 // Get the topics replies
1001 $replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() );
1002
1003 // Update the forum_id of all replies in the topic
1004 foreach ( $replies as $reply_id ) {
1005 bbp_update_reply_forum_id( $reply_id, $new_forum_id );
1006 }
1007
1008 /** Old forum_id **********************************************************/
1009
1010 // Get topic ancestors
1011 $old_forum_ancestors = array_values( array_unique( array_merge( array( $old_forum_id ), (array) get_post_ancestors( $old_forum_id ) ) ) );
1012
1013 // Public counts
1014 if ( bbp_is_topic_public( $topic_id ) ) {
1015
1016 // Update old forum counts.
1017 bbp_decrease_forum_topic_count( $old_forum_id );
1018
1019 // Update new forum counts.
1020 bbp_increase_forum_topic_count( $new_forum_id );
1021
1022 // Non-public counts
1023 } else {
1024
1025 // Update old forum counts.
1026 bbp_decrease_forum_topic_count_hidden( $old_forum_id );
1027
1028 // Update new forum counts.
1029 bbp_increase_forum_topic_count_hidden( $new_forum_id );
1030 }
1031
1032 // Get reply counts.
1033 $public_reply_count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
1034 $hidden_reply_count = bbp_get_non_public_child_count( $topic_id, bbp_get_reply_post_type() );
1035
1036 // Bump reply counts.
1037 bbp_bump_forum_reply_count( $old_forum_id, -$public_reply_count );
1038 bbp_bump_forum_reply_count( $new_forum_id, $public_reply_count );
1039 bbp_bump_forum_reply_count_hidden( $old_forum_id, -$hidden_reply_count );
1040 bbp_bump_forum_reply_count_hidden( $new_forum_id, $hidden_reply_count );
1041
1042 // Loop through ancestors and update them
1043 if ( ! empty( $old_forum_ancestors ) ) {
1044 foreach ( $old_forum_ancestors as $ancestor ) {
1045 if ( bbp_is_forum( $ancestor ) ) {
1046 bbp_update_forum( array(
1047 'forum_id' => $ancestor,
1048 ) );
1049 }
1050 }
1051 }
1052
1053 /** New forum_id **********************************************************/
1054
1055 // Make sure we're not walking twice
1056 if ( ! in_array( $new_forum_id, $old_forum_ancestors, true ) ) {
1057
1058 // Get topic ancestors
1059 $new_forum_ancestors = array_values( array_unique( array_merge( array( $new_forum_id ), (array) get_post_ancestors( $new_forum_id ) ) ) );
1060
1061 // Make sure we're not walking twice
1062 $new_forum_ancestors = array_diff( $new_forum_ancestors, $old_forum_ancestors );
1063
1064 // Loop through ancestors and update them
1065 if ( ! empty( $new_forum_ancestors ) ) {
1066 foreach ( $new_forum_ancestors as $ancestor ) {
1067 if ( bbp_is_forum( $ancestor ) ) {
1068 bbp_update_forum( array(
1069 'forum_id' => $ancestor,
1070 ) );
1071 }
1072 }
1073 }
1074 }
1075 }
1076
1077 /**
1078 * Merge topic handler
1079 *
1080 * Handles the front end merge topic submission
1081 *
1082 * @since 2.0.0 bbPress (r2756)
1083 *
1084 * @param string $action The requested action to compare this function to
1085 */
1086 function bbp_merge_topic_handler( $action = '' ) {
1087
1088 // Bail if action is not bbp-merge-topic
1089 if ( 'bbp-merge-topic' !== $action ) {
1090 return;
1091 }
1092
1093 // Define local variable(s)
1094 $source_topic_id = $destination_topic_id = 0;
1095 $source_topic = $destination_topic = 0;
1096 $subscribers = $favoriters = $replies = array();
1097
1098 /** Source Topic **********************************************************/
1099
1100 // Topic id
1101 if ( empty( $_POST['bbp_topic_id'] ) ) {
1102 bbp_add_error( 'bbp_merge_topic_source_id', __( '<strong>Error</strong>: Topic ID not found.', 'bbpress' ) );
1103 } else {
1104 $source_topic_id = (int) $_POST['bbp_topic_id'];
1105 }
1106
1107 // Nonce check
1108 if ( ! bbp_verify_nonce_request( 'bbp-merge-topic_' . $source_topic_id ) ) {
1109 bbp_add_error( 'bbp_merge_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
1110 return;
1111
1112 // Source topic not found
1113 } elseif ( ! $source_topic = bbp_get_topic( $source_topic_id ) ) {
1114 bbp_add_error( 'bbp_merge_topic_source_not_found', __( '<strong>Error</strong>: The topic you want to merge was not found.', 'bbpress' ) );
1115 return;
1116 }
1117
1118 // Cannot edit source topic
1119 if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) {
1120 bbp_add_error( 'bbp_merge_topic_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) );
1121 return;
1122 }
1123
1124 /** Destination Topic *****************************************************/
1125
1126 // Topic id
1127 if ( empty( $_POST['bbp_destination_topic'] ) ) {
1128 bbp_add_error( 'bbp_merge_topic_destination_id', __( '<strong>Error</strong>: Destination topic ID not found.', 'bbpress' ) );
1129 } else {
1130 $destination_topic_id = (int) $_POST['bbp_destination_topic'];
1131 }
1132
1133 // Destination topic not found
1134 if ( ! $destination_topic = bbp_get_topic( $destination_topic_id ) ) {
1135 bbp_add_error( 'bbp_merge_topic_destination_not_found', __( '<strong>Error</strong>: The topic you want to merge to was not found.', 'bbpress' ) );
1136 }
1137
1138 // Cannot edit destination topic
1139 if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) {
1140 bbp_add_error( 'bbp_merge_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) );
1141 }
1142
1143 // Bail if errors
1144 if ( bbp_has_errors() ) {
1145 return;
1146 }
1147
1148 /** No Errors *************************************************************/
1149
1150 // Update counts, etc...
1151 do_action( 'bbp_merge_topic', $destination_topic->ID, $source_topic->ID );
1152
1153 /** Date Check ************************************************************/
1154
1155 // Check if the destination topic is older than the source topic
1156 if ( strtotime( $source_topic->post_date ) < strtotime( $destination_topic->post_date ) ) {
1157
1158 // Set destination topic post_date to 1 second before source topic
1159 $destination_post_date = date( 'Y-m-d H:i:s', strtotime( $source_topic->post_date ) - 1 );
1160
1161 // Update destination topic
1162 wp_update_post( array(
1163 'ID' => $destination_topic_id,
1164 'post_date' => $destination_post_date,
1165 'post_date_gmt' => get_gmt_from_date( $destination_post_date )
1166 ) );
1167 }
1168
1169 /** Engagements ***********************************************************/
1170
1171 // Get engagements from source topic
1172 $engagements = bbp_get_topic_engagements( $source_topic->ID );
1173
1174 // Maybe migrate engagements
1175 if ( ! empty( $engagements ) ) {
1176 foreach ( $engagements as $engager ) {
1177 bbp_add_user_engagement( $engager, $destination_topic->ID );
1178 }
1179 }
1180
1181 /** Subscriptions *********************************************************/
1182
1183 // Get subscribers from source topic
1184 $subscribers = bbp_get_subscribers( $source_topic->ID );
1185
1186 // Maybe migrate subscriptions
1187 if ( ! empty( $subscribers ) && ! empty( $_POST['bbp_topic_subscribers'] ) && ( '1' === $_POST['bbp_topic_subscribers'] ) ) {
1188 foreach ( $subscribers as $subscriber ) {
1189 bbp_add_user_subscription( $subscriber, $destination_topic->ID );
1190 }
1191 }
1192
1193 /** Favorites *************************************************************/
1194
1195 // Get favoriters from source topic
1196 $favoriters = bbp_get_topic_favoriters( $source_topic->ID );
1197
1198 // Maybe migrate favorites
1199 if ( ! empty( $favoriters ) && ! empty( $_POST['bbp_topic_favoriters'] ) && ( '1' === $_POST['bbp_topic_favoriters'] ) ) {
1200 foreach ( $favoriters as $favoriter ) {
1201 bbp_add_user_favorite( $favoriter, $destination_topic->ID );
1202 }
1203 }
1204
1205 /** Tags ******************************************************************/
1206
1207 // Get the source topic tags
1208 $source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
1209
1210 // Tags to possibly merge
1211 if ( ! empty( $source_topic_tags ) && ! is_wp_error( $source_topic_tags ) ) {
1212
1213 // Shift the tags if told to
1214 if ( ! empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) ) {
1215 wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
1216 }
1217
1218 // Delete the tags from the source topic
1219 wp_delete_object_term_relationships( $source_topic->ID, bbp_get_topic_tag_tax_id() );
1220 }
1221
1222 /** Source Topic **********************************************************/
1223
1224 // Status
1225 bbp_open_topic( $source_topic->ID );
1226
1227 // Sticky
1228 bbp_unstick_topic( $source_topic->ID );
1229
1230 // Delete source topic's last & count meta data
1231 delete_post_meta( $source_topic->ID, '_bbp_last_reply_id' );
1232 delete_post_meta( $source_topic->ID, '_bbp_last_active_id' );
1233 delete_post_meta( $source_topic->ID, '_bbp_last_active_time' );
1234 delete_post_meta( $source_topic->ID, '_bbp_voice_count' );
1235 delete_post_meta( $source_topic->ID, '_bbp_reply_count' );
1236 delete_post_meta( $source_topic->ID, '_bbp_reply_count_hidden' );
1237
1238 // Delete source topics user relationships
1239 delete_post_meta( $source_topic->ID, '_bbp_favorite' );
1240 delete_post_meta( $source_topic->ID, '_bbp_subscription' );
1241 delete_post_meta( $source_topic->ID, '_bbp_engagement' );
1242
1243 // Get the replies of the source topic
1244 $replies = (array) get_posts( array(
1245 'post_parent' => $source_topic->ID,
1246 'post_type' => bbp_get_reply_post_type(),
1247 'posts_per_page' => -1,
1248 'order' => 'ASC'
1249 ) );
1250
1251 // Prepend the source topic to its replies array for processing
1252 array_unshift( $replies, $source_topic );
1253
1254 if ( ! empty( $replies ) ) {
1255
1256 /** Merge Replies *****************************************************/
1257
1258 // Change the post_parent of each reply to the destination topic id
1259 foreach ( $replies as $reply ) {
1260
1261 // Update the reply
1262 wp_update_post( array(
1263 'ID' => $reply->ID,
1264 'post_title' => '',
1265 'post_name' => false,
1266 'post_type' => bbp_get_reply_post_type(),
1267 'post_parent' => $destination_topic->ID,
1268 'guid' => ''
1269 ) );
1270
1271 // Adjust reply meta values
1272 bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID );
1273 bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
1274
1275 // Update the reply position
1276 bbp_update_reply_position( $reply->ID );
1277
1278 // Do additional actions per merged reply
1279 do_action( 'bbp_merged_topic_reply', $reply->ID, $destination_topic->ID );
1280 }
1281 }
1282
1283 /** Successful Merge ******************************************************/
1284
1285 // Update topic's last meta data
1286 bbp_update_topic_last_reply_id ( $destination_topic->ID );
1287 bbp_update_topic_last_active_id ( $destination_topic->ID );
1288 bbp_update_topic_last_active_time( $destination_topic->ID );
1289
1290 // Send the post parent of the source topic as it has been shifted
1291 // (possibly to a new forum) so we need to update the counts of the
1292 // old forum as well as the new one
1293 do_action( 'bbp_merged_topic', $destination_topic->ID, $source_topic->ID, $source_topic->post_parent );
1294
1295 // Redirect back to new topic
1296 bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
1297 }
1298
1299 /**
1300 * Fix counts on topic merge
1301 *
1302 * When a topic is merged, update the counts of source and destination topic
1303 * and their forums.
1304 *
1305 * @since 2.0.0 bbPress (r2756)
1306 *
1307 * @param int $destination_topic_id Destination topic id
1308 * @param int $source_topic_id Source topic id
1309 * @param int $source_topic_forum_id Source topic's forum id
1310 */
1311 function bbp_merge_topic_count( $destination_topic_id, $source_topic_id, $source_topic_forum_id ) {
1312
1313 /** Source Topic **********************************************************/
1314
1315 // Forum Topic Counts
1316 bbp_update_forum_topic_count( $source_topic_forum_id );
1317
1318 // Forum Reply Counts
1319 bbp_update_forum_reply_count( $source_topic_forum_id );
1320
1321 /** Destination Topic *****************************************************/
1322
1323 // Topic Reply Counts
1324 bbp_update_topic_reply_count( $destination_topic_id );
1325
1326 // Topic Hidden Reply Counts
1327 bbp_update_topic_reply_count_hidden( $destination_topic_id );
1328
1329 // Topic Voice Counts
1330 bbp_update_topic_voice_count( $destination_topic_id );
1331
1332 do_action( 'bbp_merge_topic_count', $destination_topic_id, $source_topic_id, $source_topic_forum_id );
1333 }
1334
1335 /**
1336 * Split topic handler
1337 *
1338 * Handles the front end split topic submission
1339 *
1340 * @since 2.0.0 bbPress (r2756)
1341 *
1342 * @param string $action The requested action to compare this function to
1343 */
1344 function bbp_split_topic_handler( $action = '' ) {
1345
1346 // Bail if action is not 'bbp-split-topic'
1347 if ( 'bbp-split-topic' !== $action ) {
1348 return;
1349 }
1350
1351 // Prevent debug notices
1352 $from_reply_id = $destination_topic_id = 0;
1353 $destination_topic_title = '';
1354 $destination_topic = $from_reply = $source_topic = '';
1355 $split_option = false;
1356
1357 /** Split Reply ***********************************************************/
1358
1359 if ( empty( $_POST['bbp_reply_id'] ) ) {
1360 bbp_add_error( 'bbp_split_topic_reply_id', __( '<strong>Error</strong>: A reply ID is required.', 'bbpress' ) );
1361 } else {
1362 $from_reply_id = (int) $_POST['bbp_reply_id'];
1363 }
1364
1365 $from_reply = bbp_get_reply( $from_reply_id );
1366
1367 // Reply exists
1368 if ( empty( $from_reply ) ) {
1369 bbp_add_error( 'bbp_split_topic_r_not_found', __( '<strong>Error</strong>: The reply you want to split from was not found.', 'bbpress' ) );
1370 }
1371
1372 /** Topic to Split ********************************************************/
1373
1374 // Get the topic being split
1375 $source_topic = bbp_get_topic( $from_reply->post_parent );
1376
1377 // No topic
1378 if ( empty( $source_topic ) ) {
1379 bbp_add_error( 'bbp_split_topic_source_not_found', __( '<strong>Error</strong>: The topic you want to split was not found.', 'bbpress' ) );
1380 }
1381
1382 // Nonce check failed
1383 if ( ! bbp_verify_nonce_request( 'bbp-split-topic_' . $source_topic->ID ) ) {
1384 bbp_add_error( 'bbp_split_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
1385 return;
1386 }
1387
1388 // Use cannot edit topic
1389 if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) {
1390 bbp_add_error( 'bbp_split_topic_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) );
1391 }
1392
1393 // How to Split
1394 if ( ! empty( $_POST['bbp_topic_split_option'] ) ) {
1395 $split_option = sanitize_key( $_POST['bbp_topic_split_option'] );
1396 }
1397
1398 // Invalid split option
1399 if ( empty( $split_option ) || ! in_array( $split_option, array( 'existing', 'reply' ), true ) ) {
1400 bbp_add_error( 'bbp_split_topic_option', __( '<strong>Error</strong>: You need to choose a valid split option.', 'bbpress' ) );
1401
1402 // Valid Split Option
1403 } else {
1404
1405 // What kind of split
1406 switch ( $split_option ) {
1407
1408 // Into an existing topic
1409 case 'existing' :
1410
1411 // Get destination topic id
1412 if ( empty( $_POST['bbp_destination_topic'] ) ) {
1413 bbp_add_error( 'bbp_split_topic_destination_id', __( '<strong>Error</strong>: A topic ID is required.', 'bbpress' ) );
1414 } else {
1415 $destination_topic_id = (int) $_POST['bbp_destination_topic'];
1416 }
1417
1418 // Get the destination topic
1419 $destination_topic = bbp_get_topic( $destination_topic_id );
1420
1421 // No destination topic
1422 if ( empty( $destination_topic ) ) {
1423 bbp_add_error( 'bbp_split_topic_destination_not_found', __( '<strong>Error</strong>: The topic you want to split to was not found.', 'bbpress' ) );
1424 }
1425
1426 // User cannot edit the destination topic
1427 if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) {
1428 bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) );
1429 }
1430
1431 break;
1432
1433 // Split at reply into a new topic
1434 case 'reply' :
1435 default :
1436
1437 // User needs to be able to publish topics
1438 if ( current_user_can( 'publish_topics' ) ) {
1439
1440 // Use the new title that was passed
1441 if ( ! empty( $_POST['bbp_topic_split_destination_title'] ) ) {
1442 $destination_topic_title = sanitize_text_field( $_POST['bbp_topic_split_destination_title'] );
1443
1444 // Use the source topic title
1445 } else {
1446 $destination_topic_title = $source_topic->post_title;
1447 }
1448
1449 // Update the topic
1450 $destination_topic_id = wp_update_post( array(
1451 'ID' => $from_reply->ID,
1452 'post_title' => $destination_topic_title,
1453 'post_name' => false,
1454 'post_type' => bbp_get_topic_post_type(),
1455 'post_parent' => $source_topic->post_parent,
1456 'menu_order' => 0,
1457 'guid' => ''
1458 ) );
1459 $destination_topic = bbp_get_topic( $destination_topic_id );
1460
1461 // Make sure the new topic knows its a topic
1462 bbp_update_topic_topic_id( $from_reply->ID );
1463
1464 // Shouldn't happen
1465 if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) {
1466 bbp_add_error( 'bbp_split_topic_destination_reply', __( '<strong>Error</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) );
1467 }
1468
1469 // User cannot publish posts
1470 } else {
1471 bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to create new topics. The reply could not be converted into a topic.', 'bbpress' ) );
1472 }
1473
1474 break;
1475 }
1476 }
1477
1478 // Bail if there are errors
1479 if ( bbp_has_errors() ) {
1480 return;
1481 }
1482
1483 /** No Errors - Do the Spit ***********************************************/
1484
1485 // Update counts, etc...
1486 do_action( 'bbp_pre_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );
1487
1488 /** Date Check ************************************************************/
1489
1490 // Check if the destination topic is older than the from reply
1491 if ( strtotime( $from_reply->post_date ) < strtotime( $destination_topic->post_date ) ) {
1492
1493 // Set destination topic post_date to 1 second before from reply
1494 $destination_post_date = date( 'Y-m-d H:i:s', strtotime( $from_reply->post_date ) - 1 );
1495
1496 // Update destination topic
1497 wp_update_post( array(
1498 'ID' => $destination_topic_id,
1499 'post_date' => $destination_post_date,
1500 'post_date_gmt' => get_gmt_from_date( $destination_post_date )
1501 ) );
1502 }
1503
1504 /** Subscriptions *********************************************************/
1505
1506 // Copy the subscribers
1507 if ( ! empty( $_POST['bbp_topic_subscribers'] ) && "1" === $_POST['bbp_topic_subscribers'] && bbp_is_subscriptions_active() ) {
1508
1509 // Get the subscribers
1510 $subscribers = bbp_get_subscribers( $source_topic->ID );
1511
1512 if ( ! empty( $subscribers ) ) {
1513
1514 // Add subscribers to new topic
1515 foreach ( (array) $subscribers as $subscriber ) {
1516 bbp_add_user_subscription( $subscriber, $destination_topic->ID );
1517 }
1518 }
1519 }
1520
1521 /** Favorites *************************************************************/
1522
1523 // Copy the favoriters if told to
1524 if ( ! empty( $_POST['bbp_topic_favoriters'] ) && ( "1" === $_POST['bbp_topic_favoriters'] ) ) {
1525
1526 // Get the favoriters
1527 $favoriters = bbp_get_topic_favoriters( $source_topic->ID );
1528
1529 if ( ! empty( $favoriters ) ) {
1530
1531 // Add the favoriters to new topic
1532 foreach ( (array) $favoriters as $favoriter ) {
1533 bbp_add_user_favorite( $favoriter, $destination_topic->ID );
1534 }
1535 }
1536 }
1537
1538 /** Tags ******************************************************************/
1539
1540 // Copy the tags if told to
1541 if ( ! empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) ) {
1542
1543 // Get the source topic tags
1544 $source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );
1545
1546 if ( ! empty( $source_topic_tags ) ) {
1547 wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
1548 }
1549 }
1550
1551 /** Split Replies *********************************************************/
1552
1553 // get_posts() is not used because it doesn't allow us to use '>='
1554 // comparision without a filter.
1555 $bbp_db = bbp_db();
1556 $query = $bbp_db->prepare( "SELECT * FROM {$bbp_db->posts} WHERE {$bbp_db->posts}.post_date >= %s AND {$bbp_db->posts}.post_parent = %d AND {$bbp_db->posts}.post_type = %s ORDER BY {$bbp_db->posts}.post_date ASC", $from_reply->post_date, $source_topic->ID, bbp_get_reply_post_type() );
1557 $replies = (array) $bbp_db->get_results( $query );
1558
1559 // Make sure there are replies to loop through
1560 if ( ! empty( $replies ) && ! is_wp_error( $replies ) ) {
1561
1562 // Save reply ids
1563 $reply_ids = array();
1564
1565 // Change the post_parent of each reply to the destination topic id
1566 foreach ( $replies as $reply ) {
1567
1568 // Update the reply
1569 wp_update_post( array(
1570 'ID' => $reply->ID,
1571 'post_title' => '',
1572 'post_name' => false, // will be automatically generated
1573 'post_parent' => $destination_topic->ID,
1574 'guid' => ''
1575 ) );
1576
1577 // Gather reply ids
1578 $reply_ids[] = $reply->ID;
1579
1580 // Adjust reply meta values
1581 bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID );
1582 bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );
1583
1584 // Adjust reply position
1585 bbp_update_reply_position( $reply->ID );
1586
1587 // Adjust reply to values
1588 $reply_to = bbp_get_reply_to( $reply->ID );
1589
1590 // Not a reply to a reply that moved over
1591 if ( ! in_array( $reply_to, $reply_ids, true ) ) {
1592 bbp_update_reply_to( $reply->ID, 0 );
1593 }
1594
1595 // New topic from reply can't be a reply to
1596 if ( ( $from_reply->ID === $destination_topic->ID ) && ( $from_reply->ID === $reply_to ) ) {
1597 bbp_update_reply_to( $reply->ID, 0 );
1598 }
1599
1600 // Do additional actions per split reply
1601 do_action( 'bbp_split_topic_reply', $reply->ID, $destination_topic->ID );
1602 }
1603
1604 // Remove reply to from new topic
1605 if ( $from_reply->ID === $destination_topic->ID ) {
1606 delete_post_meta( $from_reply->ID, '_bbp_reply_to' );
1607 }
1608
1609 // Set the last reply ID and freshness
1610 $last_reply_id = $reply->ID;
1611 $freshness = $reply->post_date;
1612
1613 // Set the last reply ID and freshness to the from_reply
1614 } else {
1615 $last_reply_id = $from_reply->ID;
1616 $freshness = $from_reply->post_date;
1617 }
1618
1619 // It is a new topic and we need to set some default metas to make
1620 // the topic display in bbp_has_topics() list
1621 if ( 'reply' === $split_option ) {
1622 bbp_update_topic_last_reply_id ( $destination_topic->ID, $last_reply_id );
1623 bbp_update_topic_last_active_id ( $destination_topic->ID, $last_reply_id );
1624 bbp_update_topic_last_active_time( $destination_topic->ID, $freshness );
1625 }
1626
1627 // Update source topic ID last active
1628 bbp_update_topic_last_reply_id ( $source_topic->ID );
1629 bbp_update_topic_last_active_id ( $source_topic->ID );
1630 bbp_update_topic_last_active_time( $source_topic->ID );
1631
1632 /** Successful Split ******************************************************/
1633
1634 // Update counts, etc...
1635 do_action( 'bbp_post_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );
1636
1637 // Redirect back to the topic
1638 bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
1639 }
1640
1641 /**
1642 * Fix counts on topic split
1643 *
1644 * When a topic is split, update the counts of source and destination topic
1645 * and their forums.
1646 *
1647 * @since 2.0.0 bbPress (r2756)
1648 *
1649 * @param int $from_reply_id From reply id
1650 * @param int $source_topic_id Source topic id
1651 * @param int $destination_topic_id Destination topic id
1652 */
1653 function bbp_split_topic_count( $from_reply_id, $source_topic_id, $destination_topic_id ) {
1654
1655 // Forum Topic Counts
1656 bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) );
1657
1658 // Forum Reply Counts
1659 bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) );
1660
1661 // Topic Reply Counts
1662 bbp_update_topic_reply_count( $source_topic_id );
1663 bbp_update_topic_reply_count( $destination_topic_id );
1664
1665 // Topic Hidden Reply Counts
1666 bbp_update_topic_reply_count_hidden( $source_topic_id );
1667 bbp_update_topic_reply_count_hidden( $destination_topic_id );
1668
1669 // Topic Voice Counts
1670 bbp_update_topic_voice_count( $source_topic_id );
1671 bbp_update_topic_voice_count( $destination_topic_id );
1672
1673 do_action( 'bbp_split_topic_count', $from_reply_id, $source_topic_id, $destination_topic_id );
1674 }
1675
1676 /**
1677 * Handles the front end tag management (renaming, merging, destroying)
1678 *
1679 * @since 2.0.0 bbPress (r2768)
1680 *
1681 * @param string $action The requested action to compare this function to
1682 */
1683 function bbp_edit_topic_tag_handler( $action = '' ) {
1684
1685 // Bail if required POST actions aren't passed
1686 if ( empty( $_POST['tag-id'] ) ) {
1687 return;
1688 }
1689
1690 // Setup possible get actions
1691 $possible_actions = array(
1692 'bbp-update-topic-tag',
1693 'bbp-merge-topic-tag',
1694 'bbp-delete-topic-tag'
1695 );
1696
1697 // Bail if actions aren't meant for this function
1698 if ( ! in_array( $action, $possible_actions, true ) ) {
1699 return;
1700 }
1701
1702 // Setup vars
1703 $tag_id = (int) $_POST['tag-id'];
1704 $tag = get_term( $tag_id, bbp_get_topic_tag_tax_id() );
1705
1706 // Tag does not exist
1707 if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
1708 bbp_add_error( 'bbp_manage_topic_invalid_tag', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while getting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
1709 return;
1710 }
1711
1712 // What action are we trying to perform?
1713 switch ( $action ) {
1714
1715 // Update tag
1716 case 'bbp-update-topic-tag' :
1717
1718 // Nonce check
1719 if ( ! bbp_verify_nonce_request( 'update-tag_' . $tag_id ) ) {
1720 bbp_add_error( 'bbp_manage_topic_tag_update_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
1721 return;
1722 }
1723
1724 // Can user edit topic tags?
1725 if ( ! current_user_can( 'edit_topic_tag', $tag_id ) ) {
1726 bbp_add_error( 'bbp_manage_topic_tag_update_permission', __( '<strong>Error</strong>: You do not have permission to edit the topic tags.', 'bbpress' ) );
1727 return;
1728 }
1729
1730 // No tag name was provided
1731 if ( empty( $_POST['tag-name'] ) || ! $name = $_POST['tag-name'] ) {
1732 bbp_add_error( 'bbp_manage_topic_tag_update_name', __( '<strong>Error</strong>: You need to enter a tag name.', 'bbpress' ) );
1733 return;
1734 }
1735
1736 // Attempt to update the tag
1737 $slug = ! empty( $_POST['tag-slug'] ) ? $_POST['tag-slug'] : '';
1738 $description = ! empty( $_POST['tag-description'] ) ? $_POST['tag-description'] : '';
1739 $tag = wp_update_term( $tag_id, bbp_get_topic_tag_tax_id(), array(
1740 'name' => $name,
1741 'slug' => $slug,
1742 'description' => $description
1743 ) );
1744
1745 // Cannot update tag
1746 if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
1747 bbp_add_error( 'bbp_manage_topic_tag_update_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while updating the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
1748 return;
1749 }
1750
1751 // Redirect
1752 $redirect = get_term_link( $tag_id, bbp_get_topic_tag_tax_id() );
1753
1754 // Update counts, etc...
1755 do_action( 'bbp_update_topic_tag', $tag_id, $tag, $name, $slug, $description );
1756
1757 break;
1758
1759 // Merge two tags
1760 case 'bbp-merge-topic-tag' :
1761
1762 // Nonce check
1763 if ( ! bbp_verify_nonce_request( 'merge-tag_' . $tag_id ) ) {
1764 bbp_add_error( 'bbp_manage_topic_tag_merge_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
1765 return;
1766 }
1767
1768 // Can user edit topic tags?
1769 if ( ! current_user_can( 'edit_topic_tags' ) ) {
1770 bbp_add_error( 'bbp_manage_topic_tag_merge_permission', __( '<strong>Error</strong>: You do not have permission to edit the topic tags.', 'bbpress' ) );
1771 return;
1772 }
1773
1774 // No tag name was provided
1775 if ( empty( $_POST['tag-existing-name'] ) || ! $name = $_POST['tag-existing-name'] ) {
1776 bbp_add_error( 'bbp_manage_topic_tag_merge_name', __( '<strong>Error</strong>: You need to enter a tag name.', 'bbpress' ) );
1777 return;
1778 }
1779
1780 // If term does not exist, create it
1781 if ( ! $tag = term_exists( $name, bbp_get_topic_tag_tax_id() ) ) {
1782 $tag = wp_insert_term( $name, bbp_get_topic_tag_tax_id() );
1783 }
1784
1785 // Problem inserting the new term
1786 if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
1787 bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
1788 return;
1789 }
1790
1791 // Merging in to...
1792 $to_tag = $tag['term_id'];
1793
1794 // Attempting to merge a tag into itself
1795 if ( $tag_id === $to_tag ) {
1796 bbp_add_error( 'bbp_manage_topic_tag_merge_same', __( '<strong>Error</strong>: The tags which are being merged can not be the same.', 'bbpress' ) );
1797 return;
1798 }
1799
1800 // Delete the old term
1801 $tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id(), array(
1802 'default' => $to_tag,
1803 'force_default' => true
1804 ) );
1805
1806 // Error merging the terms
1807 if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
1808 bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
1809 return;
1810 }
1811
1812 // Redirect
1813 $redirect = get_term_link( (int) $to_tag, bbp_get_topic_tag_tax_id() );
1814
1815 // Update counts, etc...
1816 do_action( 'bbp_merge_topic_tag', $tag_id, $to_tag, $tag );
1817
1818 break;
1819
1820 // Delete tag
1821 case 'bbp-delete-topic-tag' :
1822
1823 // Nonce check
1824 if ( ! bbp_verify_nonce_request( 'delete-tag_' . $tag_id ) ) {
1825 bbp_add_error( 'bbp_manage_topic_tag_delete_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
1826 return;
1827 }
1828
1829 // Can user delete topic tags?
1830 if ( ! current_user_can( 'delete_topic_tag', $tag_id ) ) {
1831 bbp_add_error( 'bbp_manage_topic_tag_delete_permission', __( '<strong>Error</strong>: You do not have permission to delete the topic tags.', 'bbpress' ) );
1832 return;
1833 }
1834
1835 // Attempt to delete term
1836 $tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id() );
1837
1838 // Error deleting term
1839 if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
1840 bbp_add_error( 'bbp_manage_topic_tag_delete_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while deleting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
1841 return;
1842 }
1843
1844 // We don't have any other place to go other than home! Or we may die because of the 404 disease
1845 $redirect = bbp_get_forums_url();
1846
1847 // Update counts, etc...
1848 do_action( 'bbp_delete_topic_tag', $tag_id, $tag );
1849
1850 break;
1851 }
1852
1853 /** Successful Moderation *************************************************/
1854
1855 // Redirect back
1856 $redirect = ( ! empty( $redirect ) && ! is_wp_error( $redirect ) ) ? $redirect : home_url();
1857 bbp_redirect( $redirect );
1858 }
1859
1860 /** Helpers *******************************************************************/
1861
1862 /**
1863 * Return an associative array of available topic statuses
1864 *
1865 * @since 2.4.0 bbPress (r5059)
1866 *
1867 * @param int $topic_id Optional. Topic id.
1868 *
1869 * @return array
1870 */
1871 function bbp_get_topic_statuses( $topic_id = 0 ) {
1872
1873 // Filter & return
1874 return (array) apply_filters( 'bbp_get_topic_statuses', array(
1875 bbp_get_public_status_id() => _x( 'Open', 'Open the topic', 'bbpress' ),
1876 bbp_get_closed_status_id() => _x( 'Closed', 'Close the topic', 'bbpress' ),
1877 bbp_get_spam_status_id() => _x( 'Spam', 'Spam the topic', 'bbpress' ),
1878 bbp_get_trash_status_id() => _x( 'Trash', 'Trash the topic', 'bbpress' ),
1879 bbp_get_pending_status_id() => _x( 'Pending', 'Unapprove the topic', 'bbpress' )
1880 ), $topic_id );
1881 }
1882
1883 /**
1884 * Return an associative array of topic sticky types
1885 *
1886 * @since 2.4.0 bbPress (r5059)
1887 *
1888 * @param int $topic_id Optional. Topic id.
1889 *
1890 * @return array
1891 */
1892 function bbp_get_topic_types( $topic_id = 0 ) {
1893
1894 // Filter & return
1895 return (array) apply_filters( 'bbp_get_topic_types', array(
1896 'unstick' => _x( 'Normal', 'Unstick a topic', 'bbpress' ),
1897 'stick' => _x( 'Sticky', 'Make topic sticky', 'bbpress' ),
1898 'super' => _x( 'Super Sticky', 'Make topic super sticky', 'bbpress' )
1899 ), $topic_id );
1900 }
1901
1902 /**
1903 * Return array of available topic toggle actions
1904 *
1905 * @since 2.6.0 bbPress (r6133)
1906 *
1907 * @param int $topic_id Optional. Topic id.
1908 *
1909 * @return array
1910 */
1911 function bbp_get_topic_toggles( $topic_id = 0 ) {
1912
1913 // Filter & return
1914 return (array) apply_filters( 'bbp_get_toggle_topic_actions', array(
1915 'bbp_toggle_topic_close',
1916 'bbp_toggle_topic_stick',
1917 'bbp_toggle_topic_spam',
1918 'bbp_toggle_topic_trash',
1919 'bbp_toggle_topic_approve'
1920 ), $topic_id );
1921 }
1922
1923 /**
1924 * Return array of public topic statuses.
1925 *
1926 * @since 2.6.0 bbPress (r6383)
1927 *
1928 * @return array
1929 */
1930 function bbp_get_public_topic_statuses() {
1931 $statuses = array(
1932 bbp_get_public_status_id(),
1933 bbp_get_closed_status_id()
1934 );
1935
1936 // Filter & return
1937 return (array) apply_filters( 'bbp_get_public_topic_statuses', $statuses );
1938 }
1939
1940 /**
1941 * Return array of non-public topic statuses.
1942 *
1943 * @since 2.6.0 bbPress (r6642)
1944 *
1945 * @return array
1946 */
1947 function bbp_get_non_public_topic_statuses() {
1948 $statuses = array(
1949 bbp_get_trash_status_id(),
1950 bbp_get_spam_status_id(),
1951 bbp_get_pending_status_id()
1952 );
1953
1954 // Filter & return
1955 return (array) apply_filters( 'bbp_get_non_public_topic_statuses', $statuses );
1956 }
1957
1958 /** Stickies ******************************************************************/
1959
1960 /**
1961 * Return sticky topics of a forum
1962 *
1963 * @since 2.0.0 bbPress (r2592)
1964 *
1965 * @param int $forum_id Optional. If not passed, super stickies are returned.
1966 * @return array IDs of sticky topics of a forum or super stickies
1967 */
1968 function bbp_get_stickies( $forum_id = 0 ) {
1969
1970 // Get stickies (maybe super if empty)
1971 $stickies = empty( $forum_id )
1972 ? bbp_get_super_stickies()
1973 : get_post_meta( $forum_id, '_bbp_sticky_topics', true );
1974
1975 // Cast as array
1976 $stickies = ( empty( $stickies ) || ! is_array( $stickies ) )
1977 ? array()
1978 : wp_parse_id_list( $stickies );
1979
1980 // Filter & return
1981 return (array) apply_filters( 'bbp_get_stickies', $stickies, $forum_id );
1982 }
1983
1984 /**
1985 * Return topics stuck to front page of the forums
1986 *
1987 * @since 2.0.0 bbPress (r2592)
1988 *
1989 * @return array IDs of super sticky topics
1990 */
1991 function bbp_get_super_stickies() {
1992
1993 // Get super stickies
1994 $stickies = get_option( '_bbp_super_sticky_topics', array() );
1995
1996 // Cast as array
1997 $stickies = ( empty( $stickies ) || ! is_array( $stickies ) )
1998 ? array()
1999 : wp_parse_id_list( $stickies );
2000
2001 // Filter & return
2002 return (array) apply_filters( 'bbp_get_super_stickies', $stickies );
2003 }
2004
2005 /** Topics Actions ************************************************************/
2006
2007 /**
2008 * Handles the front end opening/closing, spamming/unspamming,
2009 * sticking/unsticking and trashing/untrashing/deleting of topics
2010 *
2011 * @since 2.0.0 bbPress (r2727)
2012 *
2013 * @param string $action The requested action to compare this function to
2014 */
2015 function bbp_toggle_topic_handler( $action = '' ) {
2016
2017 // Bail if required GET actions aren't passed
2018 if ( empty( $_GET['topic_id'] ) ) {
2019 return;
2020 }
2021
2022 // What's the topic id?
2023 $topic_id = bbp_get_topic_id( (int) $_GET['topic_id'] );
2024
2025 // Get possible topic-handler toggles
2026 $toggles = bbp_get_topic_toggles( $topic_id );
2027
2028 // Bail if actions aren't meant for this function
2029 if ( ! in_array( $action, $toggles, true ) ) {
2030 return;
2031 }
2032
2033 // Make sure topic exists
2034 $topic = bbp_get_topic( $topic_id );
2035 if ( empty( $topic ) ) {
2036 bbp_add_error( 'bbp_toggle_topic_missing', __( '<strong>Error</strong>: This topic could not be found or no longer exists.', 'bbpress' ) );
2037 return;
2038 }
2039
2040 // What is the user doing here?
2041 if ( ! current_user_can( 'edit_topic', $topic_id ) || ( 'bbp_toggle_topic_trash' === $action && ! current_user_can( 'delete_topic', $topic_id ) ) ) {
2042 bbp_add_error( 'bbp_toggle_topic_permission', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) );
2043 return;
2044 }
2045
2046 // Sub-action?
2047 $sub_action = ! empty( $_GET['sub_action'] )
2048 ? sanitize_key( $_GET['sub_action'] )
2049 : false;
2050
2051 // Preliminary array
2052 $post_data = array( 'ID' => $topic_id );
2053
2054 // Do the topic toggling
2055 $retval = bbp_toggle_topic( array(
2056 'id' => $topic_id,
2057 'action' => $action,
2058 'sub_action' => $sub_action,
2059 'data' => $post_data
2060 ) );
2061
2062 // Do additional topic toggle actions
2063 do_action( 'bbp_toggle_topic_handler', $retval['status'], $post_data, $action );
2064
2065 // No errors
2066 if ( ( false !== $retval['status'] ) && ! is_wp_error( $retval['status'] ) ) {
2067 bbp_redirect( $retval['redirect_to'] );
2068
2069 // Handle errors
2070 } else {
2071 bbp_add_error( 'bbp_toggle_topic', $retval['message'] );
2072 }
2073 }
2074
2075 /**
2076 * Do the actual topic toggling
2077 *
2078 * This function is used by `bbp_toggle_topic_handler()` to do the actual heavy
2079 * lifting when it comes to toggling topic. It only really makes sense to call
2080 * within that context, so if you need to call this function directly, make sure
2081 * you're also doing what the handler does too.
2082 *
2083 * @since 2.6.0 bbPress (r6133)
2084 * @access private
2085 *
2086 * @param array $args
2087 */
2088 function bbp_toggle_topic( $args = array() ) {
2089
2090 // Parse the arguments
2091 $r = bbp_parse_args( $args, array(
2092 'id' => 0,
2093 'action' => '',
2094 'sub_action' => '',
2095 'data' => array()
2096 ) );
2097
2098 // Build the nonce suffix
2099 $nonce_suffix = bbp_get_topic_post_type() . '_' . (int) $r['id'];
2100
2101 // Default return values
2102 $retval = array(
2103 'status' => 0,
2104 'message' => '',
2105 'redirect_to' => bbp_get_topic_permalink( $r['id'], bbp_get_redirect_to() ),
2106 'view_all' => false
2107 );
2108
2109 // What action are we trying to perform?
2110 switch ( $r['action'] ) {
2111
2112 // Toggle approve/unapprove
2113 case 'bbp_toggle_topic_approve' :
2114 check_ajax_referer( "approve-{$nonce_suffix}" );
2115
2116 $is_pending = bbp_is_topic_pending( $r['id'] );
2117 $retval['view_all'] = ! $is_pending;
2118
2119 // Toggle
2120 $retval['status'] = ( true === $is_pending )
2121 ? bbp_approve_topic( $r['id'] )
2122 : bbp_unapprove_topic( $r['id'] );
2123
2124 // Feedback
2125 $retval['message'] = ( true === $is_pending )
2126 ? __( '<strong>Error</strong>: There was a problem approving the topic.', 'bbpress' )
2127 : __( '<strong>Error</strong>: There was a problem unapproving the topic.', 'bbpress' );
2128
2129 break;
2130
2131 // Toggle open/close
2132 case 'bbp_toggle_topic_close' :
2133 check_ajax_referer( "close-{$nonce_suffix}" );
2134
2135 $is_open = bbp_is_topic_open( $r['id'] );
2136
2137 // Toggle
2138 $retval['status'] = ( true === $is_open )
2139 ? bbp_close_topic( $r['id'] )
2140 : bbp_open_topic( $r['id'] );
2141
2142 // Feedback
2143 $retval['message'] = ( true === $is_open )
2144 ? __( '<strong>Error</strong>: There was a problem closing the topic.', 'bbpress' )
2145 : __( '<strong>Error</strong>: There was a problem opening the topic.', 'bbpress' );
2146
2147 break;
2148
2149 // Toggle sticky/super-sticky/unstick
2150 case 'bbp_toggle_topic_stick' :
2151 check_ajax_referer( "stick-{$nonce_suffix}" );
2152
2153 $is_sticky = bbp_is_topic_sticky( $r['id'] );
2154 $is_super = false === $is_sticky && ! empty( $_GET['super'] ) && ( "1" === $_GET['super'] ) ? true : false;
2155
2156 // Toggle
2157 $retval['status'] = ( true === $is_sticky )
2158 ? bbp_unstick_topic( $r['id'] )
2159 : bbp_stick_topic( $r['id'], $is_super );
2160
2161 // Feedback
2162 $retval['message'] = ( true === $is_sticky )
2163 ? __( '<strong>Error</strong>: There was a problem unsticking the topic.', 'bbpress' )
2164 : __( '<strong>Error</strong>: There was a problem sticking the topic.', 'bbpress' );
2165
2166 break;
2167
2168 // Toggle spam
2169 case 'bbp_toggle_topic_spam' :
2170 check_ajax_referer( "spam-{$nonce_suffix}" );
2171
2172 $is_spam = bbp_is_topic_spam( $r['id'] );
2173 $retval['view_all'] = ! $is_spam;
2174
2175 // Toggle
2176 $retval['status'] = ( true === $is_spam )
2177 ? bbp_unspam_topic( $r['id'] )
2178 : bbp_spam_topic( $r['id'] );
2179
2180 // Feedback
2181 $retval['message'] = ( true === $is_spam )
2182 ? __( '<strong>Error</strong>: There was a problem unmarking the topic as spam.', 'bbpress' )
2183 : __( '<strong>Error</strong>: There was a problem marking the topic as spam.', 'bbpress' );
2184
2185 break;
2186
2187 // Toggle trash
2188 case 'bbp_toggle_topic_trash' :
2189
2190 switch ( $r['sub_action'] ) {
2191 case 'trash':
2192 check_ajax_referer( "trash-{$nonce_suffix}" );
2193
2194 $retval['view_all'] = true;
2195 $retval['status'] = wp_trash_post( $r['id'] );
2196 $retval['message'] = __( '<strong>Error</strong>: There was a problem trashing the topic.', 'bbpress' );
2197 $retval['redirect_to'] = current_user_can( 'view_trash' )
2198 ? bbp_get_topic_permalink( $r['id'] )
2199 : bbp_get_forum_permalink( bbp_get_topic_forum_id( $r['id'] ) );
2200
2201 break;
2202
2203 case 'untrash':
2204 check_ajax_referer( "untrash-{$nonce_suffix}" );
2205
2206 $retval['status'] = wp_untrash_post( $r['id'] );
2207 $retval['message'] = __( '<strong>Error</strong>: There was a problem untrashing the topic.', 'bbpress' );
2208 $retval['redirect_to'] = bbp_get_topic_permalink( $r['id'] );
2209
2210 break;
2211
2212 case 'delete':
2213 check_ajax_referer( "delete-{$nonce_suffix}" );
2214
2215 $retval['status'] = wp_delete_post( $r['id'] );
2216 $retval['message'] = __( '<strong>Error</strong>: There was a problem deleting the topic.', 'bbpress' );
2217 $retval['redirect_to'] = bbp_get_forum_permalink( $retval['status']->post_parent );
2218
2219 break;
2220 }
2221
2222 break;
2223 }
2224
2225 // Add view all if needed
2226 if ( ! empty( $retval['view_all'] ) ) {
2227 $retval['redirect_to'] = bbp_add_view_all( $retval['redirect_to'], true );
2228 }
2229
2230 // Filter & return
2231 return apply_filters( 'bbp_toggle_topic', $retval, $r, $args );
2232 }
2233
2234 /** Favorites & Subscriptions *************************************************/
2235
2236 /**
2237 * Remove a deleted topic from all user favorites
2238 *
2239 * @since 2.0.0 bbPress (r2652)
2240 *
2241 * @param int $topic_id Get the topic id to remove
2242 */
2243 function bbp_remove_topic_from_all_favorites( $topic_id = 0 ) {
2244 $topic_id = bbp_get_topic_id( $topic_id );
2245
2246 // Bail if no topic
2247 if ( empty( $topic_id ) ) {
2248 return;
2249 }
2250
2251 // Get users
2252 $users = (array) bbp_get_topic_favoriters( $topic_id );
2253
2254 // Users exist
2255 if ( ! empty( $users ) ) {
2256
2257 // Loop through users
2258 foreach ( $users as $user ) {
2259
2260 // Remove each user
2261 bbp_remove_user_favorite( $user, $topic_id );
2262 }
2263 }
2264 }
2265
2266 /**
2267 * Remove a deleted topic from all user subscriptions
2268 *
2269 * @since 2.0.0 bbPress (r2652)
2270 *
2271 * @param int $topic_id Get the topic id to remove
2272 */
2273 function bbp_remove_topic_from_all_subscriptions( $topic_id = 0 ) {
2274
2275 // Subscriptions are not active
2276 if ( ! bbp_is_subscriptions_active() ) {
2277 return;
2278 }
2279
2280 // Bail if no topic
2281 $topic_id = bbp_get_topic_id( $topic_id );
2282 if ( empty( $topic_id ) ) {
2283 return;
2284 }
2285
2286 // Remove all users
2287 return bbp_remove_object_from_all_users( $topic_id, '_bbp_subscription', 'post' );
2288 }
2289
2290 /** Count Bumpers *************************************************************/
2291
2292 /**
2293 * Bump the total reply count of a topic
2294 *
2295 * @since 2.1.0 bbPress (r3825)
2296 *
2297 * @param int $topic_id Optional. Topic id.
2298 * @param int $difference Optional. Default 1
2299 * @return int Topic reply count
2300 */
2301 function bbp_bump_topic_reply_count( $topic_id = 0, $difference = 1 ) {
2302
2303 // Bail if no bump
2304 if ( empty( $difference ) ) {
2305 return false;
2306 }
2307
2308 // Get counts
2309 $topic_id = bbp_get_topic_id( $topic_id );
2310 $reply_count = bbp_get_topic_reply_count( $topic_id, true );
2311 $difference = (int) $difference;
2312 $new_count = (int) ( $reply_count + $difference );
2313
2314 // Update this topic id's reply count
2315 update_post_meta( $topic_id, '_bbp_reply_count', $new_count );
2316
2317 // Filter & return
2318 return (int) apply_filters( 'bbp_bump_topic_reply_count', $new_count, $topic_id, $difference );
2319 }
2320
2321 /**
2322 * Increase the total reply count of a topic by one.
2323 *
2324 * @since 2.6.0 bbPress (r6036)
2325 *
2326 * @param int $topic_id The topic id.
2327 *
2328 * @return void
2329 */
2330 function bbp_increase_topic_reply_count( $topic_id = 0 ) {
2331
2332 // Bail early if no id is passed.
2333 if ( empty( $topic_id ) ) {
2334 return;
2335 }
2336
2337 // If it's a reply, get the topic id.
2338 if ( bbp_is_reply( $topic_id ) ) {
2339 $reply_id = $topic_id;
2340 $topic_id = bbp_get_reply_topic_id( $reply_id );
2341
2342 // Update inverse based on item status
2343 if ( ! bbp_is_reply_public( $reply_id ) ) {
2344 bbp_increase_topic_reply_count_hidden( $topic_id );
2345 return;
2346 }
2347 }
2348
2349 // Bump up
2350 bbp_bump_topic_reply_count( $topic_id );
2351 }
2352
2353 /**
2354 * Decrease the total reply count of a topic by one.
2355 *
2356 * @since 2.6.0 bbPress (r6036)
2357 *
2358 * @param int $topic_id The topic id.
2359 *
2360 * @return void
2361 */
2362 function bbp_decrease_topic_reply_count( $topic_id = 0 ) {
2363
2364 // Bail early if no id is passed.
2365 if ( empty( $topic_id ) ) {
2366 return;
2367 }
2368
2369 // If it's a reply, get the topic id.
2370 if ( bbp_is_reply( $topic_id ) ) {
2371 $reply_id = $topic_id;
2372 $topic_id = bbp_get_reply_topic_id( $reply_id );
2373
2374 // Update inverse based on item status
2375 if ( ! bbp_is_reply_public( $reply_id ) ) {
2376 bbp_decrease_topic_reply_count_hidden( $topic_id );
2377 return;
2378 }
2379 }
2380
2381 // Bump down
2382 bbp_bump_topic_reply_count( $topic_id, -1 );
2383 }
2384
2385 /**
2386 * Bump the total hidden reply count of a topic
2387 *
2388 * @since 2.1.0 bbPress (r3825)
2389 *
2390 * @param int $topic_id Optional. Topic id.
2391 * @param int $difference Optional. Default 1
2392 * @return int Topic hidden reply count
2393 */
2394 function bbp_bump_topic_reply_count_hidden( $topic_id = 0, $difference = 1 ) {
2395
2396 // Bail if no bump
2397 if ( empty( $difference ) ) {
2398 return false;
2399 }
2400
2401 // Get counts
2402 $topic_id = bbp_get_topic_id( $topic_id );
2403 $reply_count = bbp_get_topic_reply_count_hidden( $topic_id, true );
2404 $difference = (int) $difference;
2405 $new_count = (int) ( $reply_count + $difference );
2406
2407 // Update this topic id's hidden reply count
2408 update_post_meta( $topic_id, '_bbp_reply_count_hidden', $new_count );
2409
2410 // Filter & return
2411 return (int) apply_filters( 'bbp_bump_topic_reply_count_hidden', $new_count, $topic_id, $difference );
2412 }
2413
2414 /**
2415 * Increase the total hidden reply count of a topic by one.
2416 *
2417 * @since 2.6.0 bbPress (r6036)
2418 *
2419 * @param int $topic_id The topic id.
2420 *
2421 * @return void
2422 */
2423 function bbp_increase_topic_reply_count_hidden( $topic_id = 0 ) {
2424
2425 // Bail early if no id is passed.
2426 if ( empty( $topic_id ) ) {
2427 return;
2428 }
2429
2430 // If it's a reply, get the topic id.
2431 if ( bbp_is_reply( $topic_id ) ) {
2432 $reply_id = $topic_id;
2433 $topic_id = bbp_get_reply_topic_id( $reply_id );
2434
2435 // Update inverse based on item status
2436 if ( bbp_is_reply_public( $reply_id ) ) {
2437 bbp_increase_topic_reply_count( $topic_id );
2438 return;
2439 }
2440 }
2441
2442 // Bump up
2443 bbp_bump_topic_reply_count_hidden( $topic_id );
2444 }
2445
2446 /**
2447 * Decrease the total hidden reply count of a topic by one.
2448 *
2449 * @since 2.6.0 bbPress (r6036)
2450 *
2451 * @param int $topic_id The topic id.
2452 *
2453 * @return void
2454 */
2455 function bbp_decrease_topic_reply_count_hidden( $topic_id = 0 ) {
2456
2457 // Bail early if no id is passed.
2458 if ( empty( $topic_id ) ) {
2459 return;
2460 }
2461
2462 // If it's a reply, get the topic id.
2463 if ( bbp_is_reply( $topic_id ) ) {
2464 $reply_id = $topic_id;
2465 $topic_id = bbp_get_reply_topic_id( $reply_id );
2466
2467 // Update inverse based on item status
2468 if ( bbp_is_reply_public( $reply_id ) ) {
2469 bbp_decrease_topic_reply_count( $topic_id );
2470 return;
2471 }
2472 }
2473
2474 // Bump down
2475 bbp_bump_topic_reply_count_hidden( $topic_id, -1 );
2476 }
2477
2478 /**
2479 * Update counts after a topic is inserted via `bbp_insert_topic`.
2480 *
2481 * @since 2.6.0 bbPress (r6036)
2482 *
2483 * @param int $topic_id The topic id.
2484 * @param int $forum_id The forum id.
2485 *
2486 * @return void
2487 */
2488 function bbp_insert_topic_update_counts( $topic_id = 0, $forum_id = 0 ) {
2489
2490 // If the topic is public, update the forum topic counts.
2491 if ( bbp_is_topic_public( $topic_id ) ) {
2492 bbp_increase_forum_topic_count( $forum_id );
2493
2494 // If the topic isn't public only update the forum topic hidden count.
2495 } else {
2496 bbp_increase_forum_topic_count_hidden( $forum_id );
2497 }
2498 }
2499
2500 /** Topic Updaters ************************************************************/
2501
2502 /**
2503 * Update the topic's forum id
2504 *
2505 * @since 2.0.0 bbPress (r2855)
2506 *
2507 * @param int $topic_id Optional. Topic id to update
2508 * @param int $forum_id Optional. Forum id
2509 * @return int Forum id
2510 */
2511 function bbp_update_topic_forum_id( $topic_id = 0, $forum_id = 0 ) {
2512
2513 // If it's a reply, then get the parent (topic id)
2514 $topic_id = bbp_is_reply( $topic_id )
2515 ? bbp_get_reply_topic_id( $topic_id )
2516 : bbp_get_topic_id( $topic_id );
2517
2518 // Forum ID fallback
2519 if ( empty( $forum_id ) ) {
2520 $forum_id = get_post_field( 'post_parent', $topic_id );
2521 }
2522
2523 // Update the forum ID
2524 $forum_id = bbp_update_forum_id( $topic_id, $forum_id );
2525
2526 // Filter & return
2527 return (int) apply_filters( 'bbp_update_topic_forum_id', $forum_id, $topic_id );
2528 }
2529
2530 /**
2531 * Update the topic's topic id
2532 *
2533 * @since 2.0.0 bbPress (r2954)
2534 *
2535 * @param int $topic_id Optional. Topic id to update
2536 * @return int Topic id
2537 */
2538 function bbp_update_topic_topic_id( $topic_id = 0 ) {
2539 $topic_id = bbp_get_topic_id( $topic_id );
2540 $topic_id = bbp_update_topic_id( $topic_id, $topic_id );
2541
2542 // Filter & return
2543 return (int) apply_filters( 'bbp_update_topic_topic_id', $topic_id );
2544 }
2545
2546 /**
2547 * Adjust the total reply count of a topic
2548 *
2549 * @since 2.0.0 bbPress (r2467)
2550 *
2551 * @param int $topic_id Optional. Topic id to update
2552 * @param int $reply_count Optional. Set the reply count manually.
2553 * @return int Topic reply count
2554 */
2555 function bbp_update_topic_reply_count( $topic_id = 0, $reply_count = false ) {
2556
2557 // If it's a reply, then get the parent (topic id)
2558 $topic_id = bbp_is_reply( $topic_id )
2559 ? bbp_get_reply_topic_id( $topic_id )
2560 : bbp_get_topic_id( $topic_id );
2561
2562 // Get replies of topic if not passed
2563 $reply_count = ! is_int( $reply_count )
2564 ? bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() )
2565 : (int) $reply_count;
2566
2567 update_post_meta( $topic_id, '_bbp_reply_count', $reply_count );
2568
2569 // Filter & return
2570 return (int) apply_filters( 'bbp_update_topic_reply_count', $reply_count, $topic_id );
2571 }
2572
2573 /**
2574 * Adjust the total hidden reply count of a topic (hidden includes trashed,
2575 * spammed and pending replies)
2576 *
2577 * @since 2.0.0 bbPress (r2740)
2578 *
2579 * @param int $topic_id Optional. Topic id to update
2580 * @param int $reply_count Optional. Set the reply count manually
2581 * @return int Topic hidden reply count
2582 */
2583 function bbp_update_topic_reply_count_hidden( $topic_id = 0, $reply_count = false ) {
2584
2585 // If it's a reply, then get the parent (topic id)
2586 $topic_id = bbp_is_reply( $topic_id )
2587 ? bbp_get_reply_topic_id( $topic_id )
2588 : bbp_get_topic_id( $topic_id );
2589
2590 // Get replies of topic
2591 $reply_count = ! is_int( $reply_count )
2592 ? bbp_get_non_public_child_count( $topic_id, bbp_get_reply_post_type() )
2593 : (int) $reply_count;
2594
2595 update_post_meta( $topic_id, '_bbp_reply_count_hidden', $reply_count );
2596
2597 // Filter & return
2598 return (int) apply_filters( 'bbp_update_topic_reply_count_hidden', $reply_count, $topic_id );
2599 }
2600
2601 /**
2602 * Update the topic with the last active post ID
2603 *
2604 * @since 2.0.0 bbPress (r2888)
2605 *
2606 * @param int $topic_id Optional. Topic id to update
2607 * @param int $active_id Optional. active id
2608 * @return int Active id
2609 */
2610 function bbp_update_topic_last_active_id( $topic_id = 0, $active_id = 0 ) {
2611
2612 // If it's a reply, then get the parent (topic id)
2613 $topic_id = bbp_is_reply( $topic_id )
2614 ? bbp_get_reply_topic_id( $topic_id )
2615 : bbp_get_topic_id( $topic_id );
2616
2617 // Get last public active id if not passed
2618 if ( empty( $active_id ) ) {
2619 $active_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
2620 }
2621
2622 // Adjust last_id's based on last_reply post_type
2623 if ( empty( $active_id ) || ! bbp_is_reply( $active_id ) ) {
2624 $active_id = $topic_id;
2625 }
2626
2627 $active_id = (int) $active_id;
2628
2629 // Update only if published
2630 update_post_meta( $topic_id, '_bbp_last_active_id', $active_id );
2631
2632 // Filter & return
2633 return (int) apply_filters( 'bbp_update_topic_last_active_id', $active_id, $topic_id );
2634 }
2635
2636 /**
2637 * Update the topics last active date/time (aka freshness)
2638 *
2639 * @since 2.0.0 bbPress (r2680)
2640 *
2641 * @param int $topic_id Optional. Topic id.
2642 * @param string $new_time Optional. New time in mysql format.
2643 * @return string MySQL timestamp of last active reply
2644 */
2645 function bbp_update_topic_last_active_time( $topic_id = 0, $new_time = '' ) {
2646
2647 // If it's a reply, then get the parent (topic id)
2648 $topic_id = bbp_is_reply( $topic_id )
2649 ? bbp_get_reply_topic_id( $topic_id )
2650 : bbp_get_topic_id( $topic_id );
2651
2652 // Check time and use current if empty
2653 if ( empty( $new_time ) ) {
2654 $new_time = get_post_field( 'post_date', bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() ) );
2655 }
2656
2657 // Update only if published
2658 if ( ! empty( $new_time ) ) {
2659 update_post_meta( $topic_id, '_bbp_last_active_time', $new_time );
2660 }
2661
2662 // Filter & return
2663 return apply_filters( 'bbp_update_topic_last_active_time', $new_time, $topic_id );
2664 }
2665
2666 /**
2667 * Update the topic with the most recent reply ID
2668 *
2669 * @since 2.0.0 bbPress (r2625)
2670 *
2671 * @param int $topic_id Optional. Topic id to update
2672 * @param int $reply_id Optional. Reply id
2673 * @return int Reply id
2674 */
2675 function bbp_update_topic_last_reply_id( $topic_id = 0, $reply_id = 0 ) {
2676
2677 // If it's a reply, then get the parent (topic id)
2678 if ( empty( $reply_id ) && bbp_is_reply( $topic_id ) ) {
2679 $reply_id = bbp_get_reply_id( $topic_id );
2680 $topic_id = bbp_get_reply_topic_id( $reply_id );
2681 } else {
2682 $reply_id = bbp_get_reply_id( $reply_id );
2683 $topic_id = bbp_get_topic_id( $topic_id );
2684 }
2685
2686 if ( empty( $reply_id ) ) {
2687 $reply_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
2688 }
2689
2690 // Adjust last_id's based on last_reply post_type
2691 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
2692 $reply_id = 0;
2693 }
2694
2695 $reply_id = (int) $reply_id;
2696
2697 // Update if reply is published
2698 update_post_meta( $topic_id, '_bbp_last_reply_id', $reply_id );
2699
2700 // Filter & return
2701 return (int) apply_filters( 'bbp_update_topic_last_reply_id', $reply_id, $topic_id );
2702 }
2703
2704 /**
2705 * Adjust the total voice count of a topic
2706 *
2707 * @since 2.0.0 bbPress (r2567)
2708 * @since 2.6.0 bbPress (r6515) This must be called after any engagement changes
2709 *
2710 * @param int $topic_id Optional. Topic id to update
2711 * @return int Voice count
2712 */
2713 function bbp_update_topic_voice_count( $topic_id = 0 ) {
2714
2715 // If it's a reply, then get the parent (topic id)
2716 $topic_id = bbp_is_reply( $topic_id )
2717 ? bbp_get_reply_topic_id( $topic_id )
2718 : bbp_get_topic_id( $topic_id );
2719
2720 // Bail if no topic ID
2721 if ( empty( $topic_id ) ) {
2722 return;
2723 }
2724
2725 // Count the engagements
2726 $count = count( bbp_get_topic_engagements( $topic_id ) );
2727
2728 // Update the voice count for this topic id
2729 update_post_meta( $topic_id, '_bbp_voice_count', $count );
2730
2731 // Filter & return
2732 return (int) apply_filters( 'bbp_update_topic_voice_count', $count, $topic_id );
2733 }
2734
2735 /**
2736 * Adjust the total anonymous reply count of a topic
2737 *
2738 * @since 2.0.0 bbPress (r2567)
2739 *
2740 * @param int $topic_id Optional. Topic id to update
2741 * @return int Anonymous reply count
2742 */
2743 function bbp_update_topic_anonymous_reply_count( $topic_id = 0 ) {
2744
2745 // If it's a reply, then get the parent (topic id)
2746 $topic_id = bbp_is_reply( $topic_id )
2747 ? bbp_get_reply_topic_id( $topic_id )
2748 : bbp_get_topic_id( $topic_id );
2749
2750 // Query the DB to get anonymous replies in this topic
2751 $bbp_db = bbp_db();
2752 $query = $bbp_db->prepare( "SELECT COUNT( ID ) FROM {$bbp_db->posts} WHERE ( post_parent = %d AND post_status = %s AND post_type = %s AND post_author = 0 ) OR ( ID = %d AND post_type = %s AND post_author = 0 )", $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type(), $topic_id, bbp_get_topic_post_type() );
2753 $replies = (int) $bbp_db->get_var( $query );
2754
2755 update_post_meta( $topic_id, '_bbp_anonymous_reply_count', $replies );
2756
2757 // Filter & return
2758 return (int) apply_filters( 'bbp_update_topic_anonymous_reply_count', $replies, $topic_id );
2759 }
2760
2761 /**
2762 * Update the revision log of the topic
2763 *
2764 * @since 2.0.0 bbPress (r2782)
2765 *
2766 * @param array $args Supports these args:
2767 * - topic_id: Topic id
2768 * - author_id: Author id
2769 * - reason: Reason for editing
2770 * - revision_id: Revision id
2771 * @return mixed False on failure, true on success
2772 */
2773 function bbp_update_topic_revision_log( $args = array() ) {
2774
2775 // Parse arguments against default values
2776 $r = bbp_parse_args( $args, array(
2777 'reason' => '',
2778 'topic_id' => 0,
2779 'author_id' => 0,
2780 'revision_id' => 0
2781 ), 'update_topic_revision_log' );
2782
2783 // Populate the variables
2784 $r['reason'] = bbp_format_revision_reason( $r['reason'] );
2785 $r['topic_id'] = bbp_get_topic_id( $r['topic_id'] );
2786 $r['author_id'] = bbp_get_user_id ( $r['author_id'], false, true );
2787 $r['revision_id'] = (int) $r['revision_id'];
2788
2789 // Get the logs and append the new one to those
2790 $revision_log = bbp_get_topic_raw_revision_log( $r['topic_id'] );
2791 $revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] );
2792
2793 // Finally, update
2794 return update_post_meta( $r['topic_id'], '_bbp_revision_log', $revision_log );
2795 }
2796
2797 /** Topic Actions *************************************************************/
2798
2799 /**
2800 * Closes a topic
2801 *
2802 * @since 2.0.0 bbPress (r2740)
2803 *
2804 * @param int $topic_id Topic id
2805 * @return mixed False or {@link WP_Error} on failure, topic id on success
2806 */
2807 function bbp_close_topic( $topic_id = 0 ) {
2808
2809 // Get topic
2810 $topic = bbp_get_topic( $topic_id );
2811 if ( empty( $topic ) ) {
2812 return $topic;
2813 }
2814
2815 // Get previous topic status meta
2816 $status = bbp_get_closed_status_id();
2817 $topic_status = get_post_meta( $topic_id, '_bbp_status', true );
2818
2819 // Bail if already closed and topic status meta exists
2820 if ( $status === $topic->post_status && ! empty( $topic_status ) ) {
2821 return false;
2822 }
2823
2824 // Set status meta public
2825 $topic_status = $topic->post_status;
2826
2827 // Execute pre close code
2828 do_action( 'bbp_close_topic', $topic_id );
2829
2830 // Add pre close status
2831 add_post_meta( $topic_id, '_bbp_status', $topic_status );
2832
2833 // Set closed status
2834 $topic->post_status = $status;
2835
2836 // Toggle revisions off as we are not altering content
2837 if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
2838 $revisions_removed = true;
2839 remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
2840 }
2841
2842 // Update topic
2843 $topic_id = wp_update_post( $topic );
2844
2845 // Toggle revisions back on
2846 if ( true === $revisions_removed ) {
2847 $revisions_removed = false;
2848 add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
2849 }
2850
2851 // Execute post close code
2852 do_action( 'bbp_closed_topic', $topic_id );
2853
2854 // Return topic_id
2855 return $topic_id;
2856 }
2857
2858 /**
2859 * Opens a topic
2860 *
2861 * @since 2.0.0 bbPress (r2740)
2862 *
2863 * @param int $topic_id Topic id
2864 * @return mixed False or {@link WP_Error} on failure, topic id on success
2865 */
2866 function bbp_open_topic( $topic_id = 0 ) {
2867
2868 // Get topic
2869 $topic = bbp_get_topic( $topic_id );
2870 if ( empty( $topic ) ) {
2871 return $topic;
2872 }
2873
2874 // Bail if not closed
2875 if ( bbp_get_closed_status_id() !== $topic->post_status ) {
2876 return false;
2877 }
2878
2879 // Execute pre open code
2880 do_action( 'bbp_open_topic', $topic_id );
2881
2882 // Get previous status
2883 $topic_status = get_post_meta( $topic_id, '_bbp_status', true );
2884
2885 // If no previous status, default to publish
2886 if ( empty( $topic_status ) ) {
2887 $topic_status = bbp_get_public_status_id();
2888 }
2889
2890 // Set previous status
2891 $topic->post_status = $topic_status;
2892
2893 // Remove old status meta
2894 delete_post_meta( $topic_id, '_bbp_status' );
2895
2896 // Toggle revisions off as we are not altering content
2897 if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
2898 $revisions_removed = true;
2899 remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
2900 }
2901
2902 // Update topic
2903 $topic_id = wp_update_post( $topic );
2904
2905 // Toggle revisions back on
2906 if ( true === $revisions_removed ) {
2907 $revisions_removed = false;
2908 add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
2909 }
2910
2911 // Execute post open code
2912 do_action( 'bbp_opened_topic', $topic_id );
2913
2914 // Return topic_id
2915 return $topic_id;
2916 }
2917
2918 /**
2919 * Marks a topic as spam
2920 *
2921 * @since 2.0.0 bbPress (r2740)
2922 *
2923 * @param int $topic_id Topic id
2924 * @return mixed False or {@link WP_Error} on failure, topic id on success
2925 */
2926 function bbp_spam_topic( $topic_id = 0 ) {
2927
2928 // Get the topic
2929 $topic = bbp_get_topic( $topic_id );
2930 if ( empty( $topic ) ) {
2931 return $topic;
2932 }
2933
2934 // Get new status
2935 $status = bbp_get_spam_status_id();
2936
2937 // Bail if topic is spam
2938 if ( $status === $topic->post_status ) {
2939 return false;
2940 }
2941
2942 // Add the original post status as post meta for future restoration
2943 add_post_meta( $topic_id, '_bbp_spam_meta_status', $topic->post_status );
2944
2945 // Execute pre spam code
2946 do_action( 'bbp_spam_topic', $topic_id );
2947
2948 // Set post status to spam
2949 $topic->post_status = $status;
2950
2951 // Empty the topic of its tags
2952 $topic->tax_input = bbp_spam_topic_tags( $topic_id );
2953
2954 // No revisions
2955 remove_action( 'pre_post_update', 'wp_save_post_revision' );
2956
2957 // Update the topic
2958 $topic_id = wp_update_post( $topic );
2959
2960 // Execute post spam code
2961 do_action( 'bbp_spammed_topic', $topic_id );
2962
2963 // Return topic_id
2964 return $topic_id;
2965 }
2966
2967 /**
2968 * Trash replies to a topic when it's marked as spam
2969 *
2970 * Usually you'll want to do this before the topic itself is marked as spam.
2971 *
2972 * @since 2.6.0 bbPress (r5405)
2973 *
2974 * @param int $topic_id
2975 */
2976 function bbp_spam_topic_replies( $topic_id = 0 ) {
2977
2978 // Validation
2979 $topic_id = bbp_get_topic_id( $topic_id );
2980
2981 // Topic is being spammed, so its replies are trashed
2982 $replies = new WP_Query( array(
2983 'fields' => 'id=>parent',
2984 'post_type' => bbp_get_reply_post_type(),
2985 'post_status' => bbp_get_public_status_id(),
2986 'post_parent' => $topic_id,
2987 'posts_per_page' => -1,
2988
2989 // Performance
2990 'nopaging' => true,
2991 'suppress_filters' => true,
2992 'update_post_term_cache' => false,
2993 'update_post_meta_cache' => false,
2994 'ignore_sticky_posts' => true,
2995 'no_found_rows' => true
2996 ) );
2997
2998 if ( ! empty( $replies->posts ) ) {
2999
3000 // Prevent debug notices
3001 $pre_spammed_replies = array();
3002
3003 // Loop through replies, trash them, and add them to array
3004 foreach ( $replies->posts as $reply ) {
3005 wp_trash_post( $reply->ID );
3006 $pre_spammed_replies[] = $reply->ID;
3007 }
3008
3009 // Set a post_meta entry of the replies that were trashed by this action.
3010 // This is so we can possibly untrash them, without untrashing replies
3011 // that were purposefully trashed before.
3012 update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies );
3013
3014 // Reset the global post data after looping through the above WP_Query
3015 wp_reset_postdata();
3016 }
3017 }
3018
3019 /**
3020 * Store the tags to a topic in post meta before it's marked as spam so they
3021 * can be retrieved and unspammed later.
3022 *
3023 * Usually you'll want to do this before the topic itself is marked as spam.
3024 *
3025 * @since 2.6.0 bbPress (r5405)
3026 *
3027 * @param int $topic_id
3028 */
3029 function bbp_spam_topic_tags( $topic_id = 0 ) {
3030
3031 // Validation
3032 $topic_id = bbp_get_topic_id( $topic_id );
3033
3034 // Get topic tags
3035 $terms = get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() );
3036
3037 // Define local variable(s)
3038 $term_names = array();
3039
3040 // Topic has tags
3041 if ( ! empty( $terms ) ) {
3042
3043 // Loop through and collect term names
3044 foreach ( $terms as $term ) {
3045 $term_names[] = $term->name;
3046 }
3047
3048 // Topic terms have slugs
3049 if ( ! empty( $term_names ) ) {
3050
3051 // Add the original post status as post meta for future restoration
3052 add_post_meta( $topic_id, '_bbp_spam_topic_tags', $term_names );
3053 }
3054 }
3055
3056 return array( bbp_get_topic_tag_tax_id() => '' );
3057 }
3058
3059 /**
3060 * Unspams a topic
3061 *
3062 * @since 2.0.0 bbPress (r2740)
3063 *
3064 * @param int $topic_id Topic id
3065 * @return mixed False or {@link WP_Error} on failure, topic id on success
3066 */
3067 function bbp_unspam_topic( $topic_id = 0 ) {
3068
3069 // Get the topic
3070 $topic = bbp_get_topic( $topic_id );
3071 if ( empty( $topic ) ) {
3072 return $topic;
3073 }
3074
3075 // Bail if already not spam
3076 if ( bbp_get_spam_status_id() !== $topic->post_status ) {
3077 return false;
3078 }
3079
3080 // Execute pre unspam code
3081 do_action( 'bbp_unspam_topic', $topic_id );
3082
3083 // Get pre spam status
3084 $topic_status = get_post_meta( $topic_id, '_bbp_spam_meta_status', true );
3085
3086 // If no previous status, default to publish
3087 if ( empty( $topic_status ) ) {
3088 $topic_status = bbp_get_public_status_id();
3089 }
3090
3091 // Set post status to pre spam
3092 $topic->post_status = $topic_status;
3093 $topic->tax_input = bbp_unspam_topic_tags( $topic_id );
3094
3095 // Delete pre spam meta
3096 delete_post_meta( $topic_id, '_bbp_spam_meta_status' );
3097
3098 // No revisions
3099 remove_action( 'pre_post_update', 'wp_save_post_revision' );
3100
3101 // Update the topic
3102 $topic_id = wp_update_post( $topic );
3103
3104 // Execute post unspam code
3105 do_action( 'bbp_unspammed_topic', $topic_id );
3106
3107 // Return topic_id
3108 return $topic_id;
3109 }
3110
3111 /**
3112 * Untrash replies to a topic previously marked as spam.
3113 *
3114 * Usually you'll want to do this after the topic is unspammed.
3115 *
3116 * @since 2.6.0 bbPress (r5405)
3117 *
3118 * @param int $topic_id
3119 */
3120 function bbp_unspam_topic_replies( $topic_id = 0 ) {
3121
3122 // Validation
3123 $topic_id = bbp_get_topic_id( $topic_id );
3124
3125 // Get the replies that were not previously trashed
3126 $pre_spammed_replies = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true );
3127
3128 // There are replies to untrash
3129 if ( ! empty( $pre_spammed_replies ) ) {
3130
3131 // Maybe reverse the trashed replies array
3132 if ( is_array( $pre_spammed_replies ) ) {
3133 $pre_spammed_replies = array_reverse( $pre_spammed_replies );
3134 }
3135
3136 // Loop through replies
3137 foreach ( (array) $pre_spammed_replies as $reply ) {
3138 wp_untrash_post( $reply );
3139 }
3140 }
3141
3142 // Clear the trasheed reply meta for the topic
3143 delete_post_meta( $topic_id, '_bbp_pre_spammed_replies' );
3144 }
3145
3146 /**
3147 * Retrieve tags to a topic from post meta before it's unmarked as spam so they.
3148 *
3149 * Usually you'll want to do this before the topic itself is unmarked as spam.
3150 *
3151 * @since 2.6.0 bbPress (r5405)
3152 *
3153 * @param int $topic_id
3154 */
3155 function bbp_unspam_topic_tags( $topic_id = 0 ) {
3156
3157 // Validation
3158 $topic_id = bbp_get_topic_id( $topic_id );
3159
3160 // Get pre-spam topic tags
3161 $terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );
3162
3163 // Delete pre-spam topic tag meta
3164 if ( ! empty( $terms ) ) {
3165 delete_post_meta( $topic_id, '_bbp_spam_topic_tags' );
3166 }
3167
3168 return array( bbp_get_topic_tag_tax_id() => $terms );
3169 }
3170
3171 /**
3172 * Sticks a topic to a forum or front
3173 *
3174 * @since 2.0.0 bbPress (r2754)
3175 *
3176 * @param int $topic_id Optional. Topic id
3177 * @param int $super Should we make the topic a super sticky?
3178 * @return bool True on success, false on failure
3179 */
3180 function bbp_stick_topic( $topic_id = 0, $super = false ) {
3181
3182 // Validation
3183 $topic_id = bbp_get_topic_id( $topic_id );
3184
3185 // Bail if a topic is not a topic (prevents revisions as stickies)
3186 if ( ! bbp_is_topic( $topic_id ) ) {
3187 return false;
3188 }
3189
3190 do_action( 'bbp_stick_topic', $topic_id, $super );
3191
3192 // Maybe get the forum ID if not getting supers
3193 $forum_id = empty( $super )
3194 ? bbp_get_topic_forum_id( $topic_id )
3195 : 0;
3196
3197 // Get the stickies, maybe from the forum ID
3198 $stickies = bbp_get_stickies( $forum_id );
3199
3200 // Add the topic to the stickies
3201 $stickies[] = $topic_id;
3202
3203 // Pull out duplicates and empties
3204 $stickies = array_unique( array_filter( $stickies ) );
3205
3206 // Unset incorrectly stuck revisions
3207 foreach ( (array) $stickies as $key => $id ) {
3208 if ( ! bbp_is_topic( $id ) ) {
3209 unset( $stickies[ $key ] );
3210 }
3211 }
3212
3213 // Reset keys
3214 $stickies = array_values( $stickies );
3215
3216 // Update
3217 $success = ! empty( $super )
3218 ? update_option( '_bbp_super_sticky_topics', $stickies )
3219 : update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );
3220
3221 do_action( 'bbp_stuck_topic', $topic_id, $super, $success );
3222
3223 return (bool) $success;
3224 }
3225
3226 /**
3227 * Approves a pending topic
3228 *
3229 * @since 2.6.0 bbPress (r5503)
3230 *
3231 * @param int $topic_id Topic id
3232 * @return mixed False or {@link WP_Error} on failure, topic id on success
3233 */
3234 function bbp_approve_topic( $topic_id = 0 ) {
3235
3236 // Get topic
3237 $topic = bbp_get_topic( $topic_id );
3238 if ( empty( $topic ) ) {
3239 return $topic;
3240 }
3241
3242 // Get new status
3243 $status = bbp_get_public_status_id();
3244
3245 // Bail if already approved
3246 if ( $status === $topic->post_status ) {
3247 return false;
3248 }
3249
3250 // Execute pre pending code
3251 do_action( 'bbp_approve_topic', $topic_id );
3252
3253 // Set publish status
3254 $topic->post_status = $status;
3255
3256 // Set post date GMT - prevents post_date override in wp_update_post()
3257 $topic->post_date_gmt = get_gmt_from_date( $topic->post_date );
3258
3259 // No revisions
3260 remove_action( 'pre_post_update', 'wp_save_post_revision' );
3261
3262 // Update topic
3263 $topic_id = wp_update_post( $topic );
3264
3265 // Execute post pending code
3266 do_action( 'bbp_approved_topic', $topic_id );
3267
3268 // Return topic_id
3269 return $topic_id;
3270 }
3271
3272 /**
3273 * Unapproves a topic
3274 *
3275 * @since 2.6.0 bbPress (r5503)
3276 *
3277 * @param int $topic_id Topic id
3278 * @return mixed False or {@link WP_Error} on failure, topic id on success
3279 */
3280 function bbp_unapprove_topic( $topic_id = 0 ) {
3281
3282 // Get topic
3283 $topic = bbp_get_topic( $topic_id );
3284 if ( empty( $topic ) ) {
3285 return $topic;
3286 }
3287
3288 // Get new status
3289 $status = bbp_get_pending_status_id();
3290
3291 // Bail if already unapproved
3292 if ( ! bbp_is_topic_public( $topic_id ) ) {
3293 return false;
3294 }
3295
3296 // Execute pre open code
3297 do_action( 'bbp_unapprove_topic', $topic_id );
3298
3299 // Set pending status
3300 $topic->post_status = $status;
3301
3302 // No revisions
3303 remove_action( 'pre_post_update', 'wp_save_post_revision' );
3304
3305 // Update topic
3306 $topic_id = wp_update_post( $topic );
3307
3308 // Execute post open code
3309 do_action( 'bbp_unapproved_topic', $topic_id );
3310
3311 // Return topic_id
3312 return $topic_id;
3313 }
3314
3315 /**
3316 * Unsticks a topic both from front and it's forum
3317 *
3318 * @since 2.0.0 bbPress (r2754)
3319 *
3320 * @param int $topic_id Optional. Topic id
3321 * @return bool Always true.
3322 */
3323 function bbp_unstick_topic( $topic_id = 0 ) {
3324
3325 // Get topic sticky status
3326 $topic_id = bbp_get_topic_id( $topic_id );
3327 $super = bbp_is_topic_super_sticky( $topic_id );
3328 $forum_id = empty( $super ) ? bbp_get_topic_forum_id( $topic_id ) : 0;
3329 $stickies = bbp_get_stickies( $forum_id );
3330 $offset = array_search( $topic_id, $stickies );
3331
3332 do_action( 'bbp_unstick_topic', $topic_id );
3333
3334 // Nothing to unstick
3335 if ( empty( $stickies ) ) {
3336 $success = true;
3337
3338 // Topic not in stickies
3339 } elseif ( ! in_array( $topic_id, $stickies, true ) ) {
3340 $success = true;
3341
3342 // Topic not in stickies
3343 } elseif ( false === $offset ) {
3344 $success = true;
3345
3346 // Splice out the offset
3347 } else {
3348 array_splice( $stickies, $offset, 1 );
3349
3350 if ( empty( $stickies ) ) {
3351 $success = ! empty( $super )
3352 ? delete_option( '_bbp_super_sticky_topics' )
3353 : delete_post_meta( $forum_id, '_bbp_sticky_topics' );
3354 } else {
3355 $success = ! empty( $super )
3356 ? update_option( '_bbp_super_sticky_topics', $stickies )
3357 : update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );
3358 }
3359 }
3360
3361 do_action( 'bbp_unstuck_topic', $topic_id, $success );
3362
3363 return (bool) $success;
3364 }
3365
3366 /** Before Delete/Trash/Untrash ***********************************************/
3367
3368 /**
3369 * Called before deleting a topic.
3370 *
3371 * This function is supplemental to the actual topic deletion which is
3372 * handled by WordPress core API functions. It is used to clean up after
3373 * a topic that is being deleted.
3374 */
3375 function bbp_delete_topic( $topic_id = 0 ) {
3376
3377 // Validate topic ID
3378 $topic_id = bbp_get_topic_id( $topic_id );
3379
3380 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3381 return false;
3382 }
3383
3384 do_action( 'bbp_delete_topic', $topic_id );
3385 }
3386
3387 /**
3388 * Delete replies to a topic when it's deleted
3389 *
3390 * Usually you'll want to do this before the topic itself is deleted.
3391 *
3392 * @since 2.6.0 bbPress (r5405)
3393 *
3394 * @param int $topic_id
3395 */
3396 function bbp_delete_topic_replies( $topic_id = 0 ) {
3397
3398 // Validate topic ID
3399 $topic_id = bbp_get_topic_id( $topic_id );
3400
3401 // Topic is being permanently deleted, so its replies gotta go too
3402 // Note that we get all post statuses here
3403 $replies = new WP_Query( array(
3404 'fields' => 'id=>parent',
3405 'post_type' => bbp_get_reply_post_type(),
3406 'post_status' => array_keys( get_post_stati() ),
3407 'post_parent' => $topic_id,
3408 'posts_per_page' => -1,
3409
3410 // Performance
3411 'nopaging' => true,
3412 'suppress_filters' => true,
3413 'update_post_term_cache' => false,
3414 'update_post_meta_cache' => false,
3415 'ignore_sticky_posts' => true,
3416 'no_found_rows' => true
3417 ) );
3418
3419 // Loop through and delete child replies
3420 if ( ! empty( $replies->posts ) ) {
3421 foreach ( $replies->posts as $reply ) {
3422 wp_delete_post( $reply->ID, true );
3423 }
3424
3425 // Reset the $post global
3426 wp_reset_postdata();
3427 }
3428 }
3429
3430 /**
3431 * Called before trashing a topic
3432 *
3433 * This function is supplemental to the actual topic being trashed which is
3434 * handled by WordPress core API functions. It is used to clean up after
3435 * a topic that is being trashed.
3436 */
3437 function bbp_trash_topic( $topic_id = 0 ) {
3438
3439 // Validate topic ID
3440 $topic_id = bbp_get_topic_id( $topic_id );
3441
3442 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3443 return false;
3444 }
3445
3446 do_action( 'bbp_trash_topic', $topic_id );
3447 }
3448
3449 /**
3450 * Trash replies to a topic when it's trashed.
3451 *
3452 * Usually you'll want to do this before the topic itself is marked as spam.
3453 *
3454 * @since 2.6.0 bbPress (r5405)
3455 *
3456 * @param int $topic_id
3457 */
3458 function bbp_trash_topic_replies( $topic_id = 0 ) {
3459
3460 // Validate topic ID
3461 $topic_id = bbp_get_topic_id( $topic_id );
3462
3463 // Topic is being trashed, so its replies are trashed too
3464 $replies = new WP_Query( array(
3465 'fields' => 'id=>parent',
3466 'post_type' => bbp_get_reply_post_type(),
3467 'post_status' => bbp_get_public_status_id(),
3468 'post_parent' => $topic_id,
3469 'posts_per_page' => -1,
3470
3471 // Performance
3472 'nopaging' => true,
3473 'suppress_filters' => true,
3474 'update_post_term_cache' => false,
3475 'update_post_meta_cache' => false,
3476 'ignore_sticky_posts' => true,
3477 'no_found_rows' => true
3478 ) );
3479
3480 if ( ! empty( $replies->posts ) ) {
3481
3482 // Prevent debug notices
3483 $pre_trashed_replies = array();
3484
3485 // Loop through replies, trash them, and add them to array
3486 foreach ( $replies->posts as $reply ) {
3487 wp_trash_post( $reply->ID );
3488 $pre_trashed_replies[] = $reply->ID;
3489 }
3490
3491 // Set a post_meta entry of the replies that were trashed by this action.
3492 // This is so we can possibly untrash them, without untrashing replies
3493 // that were purposefully trashed before.
3494 update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies );
3495
3496 // Reset the $post global
3497 wp_reset_postdata();
3498 }
3499 }
3500
3501 /**
3502 * Called before untrashing a topic
3503 */
3504 function bbp_untrash_topic( $topic_id = 0 ) {
3505 $topic_id = bbp_get_topic_id( $topic_id );
3506
3507 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3508 return false;
3509 }
3510
3511 do_action( 'bbp_untrash_topic', $topic_id );
3512 }
3513
3514 /**
3515 * Untrash replies to a topic previously trashed.
3516 *
3517 * Usually you'll want to do this after the topic is unspammed.
3518 *
3519 * @since 2.6.0 bbPress (r5405)
3520 *
3521 * @param int $topic_id
3522 */
3523 function bbp_untrash_topic_replies( $topic_id = 0 ) {
3524
3525 // Validation
3526 $topic_id = bbp_get_topic_id( $topic_id );
3527
3528 // Get the replies that were not previously trashed
3529 $pre_trashed_replies = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true );
3530
3531 // There are replies to untrash
3532 if ( ! empty( $pre_trashed_replies ) ) {
3533
3534 // Maybe reverse the trashed replies array
3535 if ( is_array( $pre_trashed_replies ) ) {
3536 $pre_trashed_replies = array_reverse( $pre_trashed_replies );
3537 }
3538
3539 // Loop through replies
3540 foreach ( (array) $pre_trashed_replies as $reply ) {
3541 wp_untrash_post( $reply );
3542 }
3543 }
3544
3545 // Clear the trashed reply meta for the topic
3546 delete_post_meta( $topic_id, '_bbp_pre_trashed_replies' );
3547 }
3548
3549 /** After Delete/Trash/Untrash ************************************************/
3550
3551 /**
3552 * Called after deleting a topic
3553 *
3554 * @since 2.0.0 bbPress (r2993)
3555 */
3556 function bbp_deleted_topic( $topic_id = 0 ) {
3557 $topic_id = bbp_get_topic_id( $topic_id );
3558
3559 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3560 return false;
3561 }
3562
3563 do_action( 'bbp_deleted_topic', $topic_id );
3564 }
3565
3566 /**
3567 * Called after trashing a topic
3568 *
3569 * @since 2.0.0 bbPress (r2993)
3570 */
3571 function bbp_trashed_topic( $topic_id = 0 ) {
3572 $topic_id = bbp_get_topic_id( $topic_id );
3573
3574 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3575 return false;
3576 }
3577
3578 do_action( 'bbp_trashed_topic', $topic_id );
3579 }
3580
3581 /**
3582 * Called after untrashing a topic
3583 *
3584 * @since 2.0.0 bbPress (r2993)
3585 */
3586 function bbp_untrashed_topic( $topic_id = 0 ) {
3587 $topic_id = bbp_get_topic_id( $topic_id );
3588
3589 if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
3590 return false;
3591 }
3592
3593 do_action( 'bbp_untrashed_topic', $topic_id );
3594 }
3595
3596 /** Settings ******************************************************************/
3597
3598 /**
3599 * Return the topics per page setting
3600 *
3601 * @since 2.0.0 bbPress (r3540)
3602 * @return int
3603 */
3604 function bbp_get_topics_per_page( $default = 15 ) {
3605
3606 // Get database option and cast as integer
3607 $retval = get_option( '_bbp_topics_per_page', $default );
3608
3609 // If return val is empty, set it to default
3610 if ( empty( $retval ) ) {
3611 $retval = $default;
3612 }
3613
3614 // Filter & return
3615 return (int) apply_filters( 'bbp_get_topics_per_page', $retval, $default );
3616 }
3617
3618 /**
3619 * Return the topics per RSS page setting
3620 *
3621 * @since 2.0.0 bbPress (r3540)
3622 *
3623 * @param int $default Default replies per page (25)
3624 * @return int
3625 */
3626 function bbp_get_topics_per_rss_page( $default = 25 ) {
3627
3628 // Get database option and cast as integer
3629 $retval = get_option( '_bbp_topics_per_rss_page', $default );
3630
3631 // If return val is empty, set it to default
3632 if ( empty( $retval ) ) {
3633 $retval = $default;
3634 }
3635
3636 // Filter & return
3637 return (int) apply_filters( 'bbp_get_topics_per_rss_page', $retval, $default );
3638 }
3639
3640 /** Topic Tags ****************************************************************/
3641
3642 /**
3643 * Get topic tags for a specific topic ID
3644 *
3645 * @since 2.6.0 bbPress (r5836)
3646 *
3647 * @param int $topic_id
3648 *
3649 * @return string
3650 */
3651 function bbp_get_topic_tags( $topic_id = 0 ) {
3652 $topic_id = bbp_get_topic_id( $topic_id );
3653 $terms = (array) get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() );
3654 $topic_tags = array_filter( $terms );
3655
3656 // Filter & return
3657 return apply_filters( 'bbp_get_topic_tags', $topic_tags, $topic_id );
3658 }
3659
3660 /**
3661 * Get topic tags for a specific topic ID
3662 *
3663 * @since 2.2.0 bbPress (r4165)
3664 *
3665 * @param int $topic_id
3666 * @param string $sep
3667 *
3668 * @return string
3669 */
3670 function bbp_get_topic_tag_names( $topic_id = 0, $sep = ', ' ) {
3671 $topic_tags = bbp_get_topic_tags( $topic_id );
3672 $pluck = wp_list_pluck( $topic_tags, 'name' );
3673 $terms = ! empty( $pluck )
3674 ? implode( $sep, $pluck )
3675 : '';
3676
3677 // Filter & return
3678 return apply_filters( 'bbp_get_topic_tag_names', $terms, $topic_id, $sep );
3679 }
3680
3681 /**
3682 * Will update topic-tag count based on object type.
3683 *
3684 * Function for the default callback for topic-tag taxonomies.
3685 *
3686 * @see https://bbpress.trac.wordpress.org/ticket/3043
3687 * @access private
3688 *
3689 * @since 2.6.0 bbPress (r6253)
3690 *
3691 * @param array $terms List of Term taxonomy IDs.
3692 * @param object $taxonomy Current taxonomy object of terms.
3693 */
3694 function bbp_update_topic_tag_count( $terms, $taxonomy ) {
3695
3696 // Bail if no object types are available
3697 if ( empty( $terms ) || empty( $taxonomy->object_type ) ) {
3698 return;
3699 }
3700
3701 // Get object types
3702 $object_types = (array) $taxonomy->object_type;
3703
3704 foreach ( $object_types as &$object_type ) {
3705 list( $object_type ) = explode( ':', $object_type );
3706 }
3707
3708 $object_types = array_unique( $object_types );
3709
3710 if ( ! empty( $object_types ) ) {
3711 $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
3712 }
3713
3714 // Statuses to count
3715 $object_statuses = bbp_get_public_topic_statuses();
3716
3717 // Get database
3718 $bbp_db = bbp_db();
3719
3720 // Loop through terms, maybe update counts
3721 foreach ( (array) $terms as $term ) {
3722 $count = 0;
3723
3724 // Get count, and bump it
3725 if ( ! empty( $object_types ) ) {
3726 $query = "SELECT COUNT(*) FROM {$bbp_db->term_relationships}, {$bbp_db->posts} WHERE {$bbp_db->posts}.ID = {$bbp_db->term_relationships}.object_id AND post_status IN ('" . implode("', '", $object_statuses ) . "') AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d";
3727 $prepare = $bbp_db->prepare( $query, $term );
3728 $count += (int) $bbp_db->get_var( $prepare );
3729 }
3730
3731 /** This action is documented in wp-includes/taxonomy.php */
3732 do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
3733 $bbp_db->update( $bbp_db->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
3734
3735 /** This action is documented in wp-includes/taxonomy.php */
3736 do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
3737 }
3738 }
3739
3740 /** Autoembed *****************************************************************/
3741
3742 /**
3743 * Check if autoembeds are enabled and hook them in if so
3744 *
3745 * @since 2.1.0 bbPress (r3752)
3746 *
3747 * @global WP_Embed $wp_embed
3748 */
3749 function bbp_topic_content_autoembed() {
3750 global $wp_embed;
3751
3752 if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) {
3753 add_filter( 'bbp_get_topic_content', array( $wp_embed, 'autoembed' ), 2 );
3754 }
3755 }
3756
3757 /** Feeds *********************************************************************/
3758
3759 /**
3760 * Output an RSS2 feed of topics, based on the query passed.
3761 *
3762 * @since 2.0.0 bbPress (r3171)
3763 *
3764 * @param array $topics_query
3765 */
3766 function bbp_display_topics_feed_rss2( $topics_query = array() ) {
3767
3768 // User cannot access this forum
3769 if ( bbp_is_single_forum() && ! bbp_user_can_view_forum( array( 'forum_id' => bbp_get_forum_id() ) ) ) {
3770 return;
3771 }
3772
3773 // Feed title
3774 $title = get_bloginfo_rss( 'name' ) . ' &#187; ' . esc_html__( 'All Topics', 'bbpress' );
3775 $title = apply_filters( 'wp_title_rss', $title );
3776
3777 // Display the feed
3778 header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true );
3779 header( 'Status: 200 OK' );
3780 echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>
3781
3782 <rss version="2.0"
3783 xmlns:content="http://purl.org/rss/1.0/modules/content/"
3784 xmlns:wfw="http://wellformedweb.org/CommentAPI/"
3785 xmlns:dc="http://purl.org/dc/elements/1.1/"
3786 xmlns:atom="http://www.w3.org/2005/Atom"
3787
3788 <?php do_action( 'bbp_feed' ); ?>
3789 >
3790
3791 <channel>
3792
3793 <title><?php echo $title; // Already escaped ?></title>
3794 <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
3795 <link><?php self_link(); ?></link>
3796 <description><?php //?></description>
3797 <lastBuildDate><?php echo date( 'r' ); ?></lastBuildDate>
3798 <generator><?php echo esc_url_raw( 'https://bbpress.org/?v=' . convert_chars( bbp_get_version() ) ); ?></generator>
3799 <language><?php bloginfo_rss( 'language' ); ?></language>
3800
3801 <?php do_action( 'bbp_feed_head' ); ?>
3802
3803 <?php if ( bbp_has_topics( $topics_query ) ) : ?>
3804
3805 <?php while ( bbp_topics() ) : bbp_the_topic(); ?>
3806
3807 <item>
3808 <guid><?php bbp_topic_permalink(); ?></guid>
3809 <title><![CDATA[<?php bbp_topic_title(); ?>]]></title>
3810 <link><?php bbp_topic_permalink(); ?></link>
3811 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_meta( bbp_get_topic_id(), '_bbp_last_active_time', true ), false ); ?></pubDate>
3812 <dc:creator><?php the_author() ?></dc:creator>
3813
3814 <?php if ( !post_password_required() ) : ?>
3815
3816 <description>
3817 <![CDATA[
3818 <p><?php printf( esc_html__( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p>
3819 <?php bbp_topic_content(); ?>
3820 ]]>
3821 </description>
3822
3823 <?php rss_enclosure(); ?>
3824
3825 <?php endif; ?>
3826
3827 <?php do_action( 'bbp_feed_item' ); ?>
3828
3829 </item>
3830
3831 <?php endwhile; ?>
3832 <?php endif; ?>
3833
3834 <?php do_action( 'bbp_feed_footer' ); ?>
3835
3836 </channel>
3837 </rss>
3838
3839 <?php
3840 exit();
3841 }
3842
3843 /** Permissions ***************************************************************/
3844
3845 /**
3846 * Redirect if unauthorized user is attempting to edit a topic
3847 *
3848 * @since 2.1.0 bbPress (r3605)
3849 */
3850 function bbp_check_topic_edit() {
3851
3852 // Bail if not editing a topic
3853 if ( ! bbp_is_topic_edit() ) {
3854 return;
3855 }
3856
3857 // User cannot edit topic, so redirect back to topic
3858 if ( ! current_user_can( 'edit_topic', bbp_get_topic_id() ) ) {
3859 bbp_redirect( bbp_get_topic_permalink() );
3860 }
3861 }
3862
3863 /**
3864 * Redirect if unauthorized user is attempting to edit a topic tag
3865 *
3866 * @since 2.1.0 bbPress (r3605)
3867 */
3868 function bbp_check_topic_tag_edit() {
3869
3870 // Bail if not editing a topic tag
3871 if ( ! bbp_is_topic_tag_edit() ) {
3872 return;
3873 }
3874
3875 // Bail if current user cannot edit topic tags
3876 if ( ! current_user_can( 'edit_topic_tag', bbp_get_topic_tag_id() ) ) {
3877 bbp_redirect( bbp_get_topic_tag_link() );
3878 }
3879 }
3880