PluginProbe
bbPress / 2.6.17
bbPress v2.6.17
2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 2.2 2.2.1 All 72 releases
bbpress / includes / topics / functions.php

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

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