[ Index ] |
PHP Cross Reference of BBPress |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * bbPress Reply 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 reply to function properly. 18 * 19 * @since 2.0.0 bbPress (r3349) 20 * 21 * @param array $reply_data Forum post data 22 * @param array $reply_meta Forum meta data 23 */ 24 function bbp_insert_reply( $reply_data = array(), $reply_meta = array() ) { 25 26 // Parse arguments against default values 27 $reply_data = bbp_parse_args( $reply_data, array( 28 'post_parent' => 0, // topic ID 29 'post_type' => bbp_get_reply_post_type(), 30 'post_author' => bbp_get_current_user_id(), 31 'post_password' => '', 32 'post_content' => '', 33 'post_title' => '', 34 'menu_order' => bbp_get_topic_reply_count( $reply_data['post_parent'], true ) + 1, 35 'comment_status' => 'closed' 36 ), 'insert_reply' ); 37 38 // Possibly override status based on parent topic 39 if ( ! empty( $reply_data['post_parent'] ) && empty( $reply_data['post_status'] ) ) { 40 $reply_data['post_status'] = bbp_get_topic_status( $reply_data['post_parent'] ); 41 } 42 43 // Insert reply 44 $reply_id = wp_insert_post( $reply_data, false ); 45 46 // Bail if no reply was added 47 if ( empty( $reply_id ) ) { 48 return false; 49 } 50 51 // Parse arguments against default values 52 $reply_meta = bbp_parse_args( $reply_meta, array( 53 'author_ip' => bbp_current_author_ip(), 54 'forum_id' => 0, 55 'topic_id' => 0, 56 'reply_to' => 0 57 ), 'insert_reply_meta' ); 58 59 // Insert reply meta 60 foreach ( $reply_meta as $meta_key => $meta_value ) { 61 62 // Prefix if not prefixed 63 if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) { 64 $meta_key = '_bbp_' . $meta_key; 65 } 66 67 // Update the meta 68 update_post_meta( $reply_id, $meta_key, $meta_value ); 69 } 70 71 // Update the reply and hierarchy 72 bbp_update_reply( $reply_id, $reply_meta['topic_id'], $reply_meta['forum_id'], array(), $reply_data['post_author'], false, $reply_meta['reply_to'] ); 73 74 /** 75 * Fires after reply has been inserted via `bbp_insert_reply`. 76 * 77 * @since 2.6.0 bbPress (r6036) 78 * 79 * @param int $reply_id The reply id. 80 * @param int $reply_meta['topic_id'] The reply topic meta. 81 * @param int $reply_meta['forum_id'] The reply forum meta. 82 */ 83 do_action( 'bbp_insert_reply', (int) $reply_id, (int) $reply_meta['topic_id'], (int) $reply_meta['forum_id'] ); 84 85 // Return reply_id 86 return $reply_id; 87 } 88 89 /** 90 * Update counts after a reply is inserted via `bbp_insert_reply`. 91 * 92 * @since 2.6.0 bbPress (r6036) 93 * 94 * @param int $reply_id The reply id. 95 * @param int $topic_id The topic id. 96 * @param int $forum_id The forum id. 97 * 98 * @return void 99 */ 100 function bbp_insert_reply_update_counts( $reply_id = 0, $topic_id = 0, $forum_id = 0 ) { 101 102 // If the reply is public, update the reply counts. 103 if ( bbp_is_reply_published( $reply_id ) ) { 104 bbp_increase_topic_reply_count( $topic_id ); 105 bbp_increase_forum_reply_count( $forum_id ); 106 107 // If the reply isn't public only update the reply hidden counts. 108 } else { 109 bbp_increase_topic_reply_count_hidden( $topic_id ); 110 bbp_increase_forum_reply_count_hidden( $forum_id ); 111 } 112 } 113 114 /** Post Form Handlers ********************************************************/ 115 116 /** 117 * Handles the front end reply submission 118 * 119 * @since 2.0.0 bbPress (r2574) 120 * 121 * @param string $action The requested action to compare this function to 122 * id, anonymous data, reply author, edit (false), and 123 * the reply to id 124 */ 125 function bbp_new_reply_handler( $action = '' ) { 126 127 // Bail if action is not bbp-new-reply 128 if ( 'bbp-new-reply' !== $action ) { 129 return; 130 } 131 132 // Nonce check 133 if ( ! bbp_verify_nonce_request( 'bbp-new-reply' ) ) { 134 bbp_add_error( 'bbp_new_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) ); 135 return; 136 } 137 138 // Define local variable(s) 139 $topic_id = $forum_id = $reply_author = $reply_to = 0; 140 $reply_title = $reply_content = $terms = ''; 141 $anonymous_data = array(); 142 143 /** Reply Author **********************************************************/ 144 145 // User is anonymous 146 if ( bbp_is_anonymous() ) { 147 148 // Filter anonymous data (variable is used later) 149 $anonymous_data = bbp_filter_anonymous_post_data(); 150 151 // Anonymous data checks out, so set cookies, etc... 152 bbp_set_current_anonymous_user_data( $anonymous_data ); 153 154 // User is logged in 155 } else { 156 157 // User cannot create replies 158 if ( ! current_user_can( 'publish_replies' ) ) { 159 bbp_add_error( 'bbp_reply_permission', __( '<strong>Error</strong>: You do not have permission to reply.', 'bbpress' ) ); 160 } 161 162 // Reply author is current user 163 $reply_author = bbp_get_current_user_id(); 164 } 165 166 /** Topic ID **************************************************************/ 167 168 // Topic id was not passed 169 if ( empty( $_POST['bbp_topic_id'] ) ) { 170 bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID is missing.', 'bbpress' ) ); 171 172 // Topic id is not a number 173 } elseif ( ! is_numeric( $_POST['bbp_topic_id'] ) ) { 174 bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID must be a number.', 'bbpress' ) ); 175 176 // Topic id might be valid 177 } else { 178 179 // Get the topic id 180 $posted_topic_id = intval( $_POST['bbp_topic_id'] ); 181 182 // Topic id is a negative number 183 if ( 0 > $posted_topic_id ) { 184 bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID cannot be a negative number.', 'bbpress' ) ); 185 186 // Topic does not exist 187 } elseif ( ! bbp_get_topic( $posted_topic_id ) ) { 188 bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic does not exist.', 'bbpress' ) ); 189 190 // Use the POST'ed topic id 191 } else { 192 $topic_id = $posted_topic_id; 193 } 194 } 195 196 /** Forum ID **************************************************************/ 197 198 // Try to use the forum id of the topic 199 if ( ! isset( $_POST['bbp_forum_id'] ) && ! empty( $topic_id ) ) { 200 $forum_id = bbp_get_topic_forum_id( $topic_id ); 201 202 // Error check the POST'ed forum id 203 } elseif ( isset( $_POST['bbp_forum_id'] ) ) { 204 205 // Empty Forum id was passed 206 if ( empty( $_POST['bbp_forum_id'] ) ) { 207 bbp_add_error( 'bbp_reply_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) ); 208 209 // Forum id is not a number 210 } elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) { 211 bbp_add_error( 'bbp_reply_forum_id', __( '<strong>Error</strong>: Forum ID must be a number.', 'bbpress' ) ); 212 213 // Forum id might be valid 214 } else { 215 216 // Get the forum id 217 $posted_forum_id = intval( $_POST['bbp_forum_id'] ); 218 219 // Forum id is empty 220 if ( 0 === $posted_forum_id ) { 221 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) ); 222 223 // Forum id is a negative number 224 } elseif ( 0 > $posted_forum_id ) { 225 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID cannot be a negative number.', 'bbpress' ) ); 226 227 // Forum does not exist 228 } elseif ( ! bbp_get_forum( $posted_forum_id ) ) { 229 bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum does not exist.', 'bbpress' ) ); 230 231 // Use the POST'ed forum id 232 } else { 233 $forum_id = $posted_forum_id; 234 } 235 } 236 } 237 238 // Forum exists 239 if ( ! empty( $forum_id ) ) { 240 241 // Forum is a category 242 if ( bbp_is_forum_category( $forum_id ) ) { 243 bbp_add_error( 'bbp_new_reply_forum_category', __( '<strong>Error</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) ); 244 245 // Forum is not a category 246 } else { 247 248 // Forum is closed and user cannot access 249 if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) { 250 bbp_add_error( 'bbp_new_reply_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new replies.', 'bbpress' ) ); 251 } 252 253 // Forum is private and user cannot access 254 if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) { 255 bbp_add_error( 'bbp_new_reply_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) ); 256 257 // Forum is hidden and user cannot access 258 } elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) { 259 bbp_add_error( 'bbp_new_reply_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) ); 260 } 261 } 262 } 263 264 /** Unfiltered HTML *******************************************************/ 265 266 // Remove kses filters from title and content for capable users and if the nonce is verified 267 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $topic_id ) === $_POST['_bbp_unfiltered_html_reply'] ) { 268 remove_filter( 'bbp_new_reply_pre_title', 'wp_filter_kses' ); 269 remove_filter( 'bbp_new_reply_pre_content', 'bbp_encode_bad', 10 ); 270 remove_filter( 'bbp_new_reply_pre_content', 'bbp_filter_kses', 30 ); 271 } 272 273 /** Reply Title ***********************************************************/ 274 275 if ( ! empty( $_POST['bbp_reply_title'] ) ) { 276 $reply_title = sanitize_text_field( $_POST['bbp_reply_title'] ); 277 } 278 279 // Filter and sanitize 280 $reply_title = apply_filters( 'bbp_new_reply_pre_title', $reply_title ); 281 282 // Title too long 283 if ( bbp_is_title_too_long( $reply_title ) ) { 284 bbp_add_error( 'bbp_reply_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) ); 285 } 286 287 /** Reply Content *********************************************************/ 288 289 if ( ! empty( $_POST['bbp_reply_content'] ) ) { 290 $reply_content = $_POST['bbp_reply_content']; 291 } 292 293 // Filter and sanitize 294 $reply_content = apply_filters( 'bbp_new_reply_pre_content', $reply_content ); 295 296 // No reply content 297 if ( empty( $reply_content ) ) { 298 bbp_add_error( 'bbp_reply_content', __( '<strong>Error</strong>: Your reply cannot be empty.', 'bbpress' ) ); 299 } 300 301 /** Reply Flooding ********************************************************/ 302 303 if ( ! bbp_check_for_flood( $anonymous_data, $reply_author ) ) { 304 bbp_add_error( 'bbp_reply_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) ); 305 } 306 307 /** Reply Duplicate *******************************************************/ 308 309 if ( ! bbp_check_for_duplicate( array( 'post_type' => bbp_get_reply_post_type(), 'post_author' => $reply_author, 'post_content' => $reply_content, 'post_parent' => $topic_id, 'anonymous_data' => $anonymous_data ) ) ) { 310 bbp_add_error( 'bbp_reply_duplicate', __( '<strong>Error</strong>: Duplicate reply detected; it looks as though you’ve already said that.', 'bbpress' ) ); 311 } 312 313 /** Reply Bad Words *******************************************************/ 314 315 if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content, true ) ) { 316 bbp_add_error( 'bbp_reply_moderation', __( '<strong>Error</strong>: Your reply cannot be created at this time.', 'bbpress' ) ); 317 } 318 319 /** Reply Status **********************************************************/ 320 321 // Maybe put into moderation 322 if ( bbp_is_topic_pending( $topic_id ) || ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) { 323 $reply_status = bbp_get_pending_status_id(); 324 325 // Default 326 } else { 327 $reply_status = bbp_get_public_status_id(); 328 } 329 330 /** Reply To **************************************************************/ 331 332 // Handle Reply To of the reply; $_REQUEST for non-JS submissions 333 if ( isset( $_REQUEST['bbp_reply_to'] ) ) { 334 $reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] ); 335 } 336 337 /** Topic Closed **********************************************************/ 338 339 // If topic is closed, moderators can still reply 340 if ( bbp_is_topic_closed( $topic_id ) && ! current_user_can( 'moderate', $topic_id ) ) { 341 bbp_add_error( 'bbp_reply_topic_closed', __( '<strong>Error</strong>: Topic is closed.', 'bbpress' ) ); 342 } 343 344 /** Topic Tags ************************************************************/ 345 346 // Either replace terms 347 if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) { 348 $terms = sanitize_text_field( $_POST['bbp_topic_tags'] ); 349 350 // ...or remove them. 351 } elseif ( isset( $_POST['bbp_topic_tags'] ) ) { 352 $terms = ''; 353 354 // Existing terms 355 } else { 356 $terms = bbp_get_topic_tag_names( $topic_id ); 357 } 358 359 /** Additional Actions (Before Save) **************************************/ 360 361 do_action( 'bbp_new_reply_pre_extras', $topic_id, $forum_id ); 362 363 // Bail if errors 364 if ( bbp_has_errors() ) { 365 return; 366 } 367 368 /** No Errors *************************************************************/ 369 370 // Add the content of the form to $reply_data as an array 371 // Just in time manipulation of reply data before being created 372 $reply_data = apply_filters( 'bbp_new_reply_pre_insert', array( 373 'post_author' => $reply_author, 374 'post_title' => $reply_title, 375 'post_content' => $reply_content, 376 'post_status' => $reply_status, 377 'post_parent' => $topic_id, 378 'post_type' => bbp_get_reply_post_type(), 379 'comment_status' => 'closed', 380 'menu_order' => bbp_get_topic_reply_count( $topic_id, true ) + 1 381 ) ); 382 383 // Insert reply 384 $reply_id = wp_insert_post( $reply_data, true ); 385 386 /** No Errors *************************************************************/ 387 388 // Check for missing reply_id or error 389 if ( ! empty( $reply_id ) && ! is_wp_error( $reply_id ) ) { 390 391 /** Topic Tags ********************************************************/ 392 393 // Just in time manipulation of reply terms before being edited 394 $terms = apply_filters( 'bbp_new_reply_pre_set_terms', $terms, $topic_id, $reply_id ); 395 396 // Insert terms 397 $terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false ); 398 399 // Term error 400 if ( is_wp_error( $terms ) ) { 401 bbp_add_error( 'bbp_reply_tags', __( '<strong>Error</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) ); 402 } 403 404 /** Trash Check *******************************************************/ 405 406 // If this reply starts as trash, add it to pre_trashed_replies 407 // for the topic, so it is properly restored. 408 if ( bbp_is_topic_trash( $topic_id ) || ( $reply_data['post_status'] === bbp_get_trash_status_id() ) ) { 409 410 // Trash the reply 411 wp_trash_post( $reply_id ); 412 413 // Only add to pre-trashed array if topic is trashed 414 if ( bbp_is_topic_trash( $topic_id ) ) { 415 416 // Get pre_trashed_replies for topic 417 $pre_trashed_meta = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true ); 418 419 // Format the meta value 420 $pre_trashed_replies = is_array( $pre_trashed_meta ) 421 ? array_filter( $pre_trashed_meta ) 422 : array(); 423 424 // Add this reply to the end of the existing replies 425 $pre_trashed_replies[] = $reply_id; 426 427 // Update the pre_trashed_reply post meta 428 update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies ); 429 } 430 431 /** Spam Check ********************************************************/ 432 433 // If reply or topic are spam, officially spam this reply 434 } elseif ( bbp_is_topic_spam( $topic_id ) || ( $reply_data['post_status'] === bbp_get_spam_status_id() ) ) { 435 add_post_meta( $reply_id, '_bbp_spam_meta_status', bbp_get_public_status_id() ); 436 437 // Only add to pre-spammed array if topic is spam 438 if ( bbp_is_topic_spam( $topic_id ) ) { 439 440 // Get pre_spammed_replies for topic 441 $pre_trashed_meta = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true ); 442 443 // Format the meta value 444 $pre_spammed_replies = is_array( $pre_trashed_meta ) 445 ? array_filter( $pre_trashed_meta ) 446 : array(); 447 448 // Add this reply to the end of the existing replies 449 $pre_spammed_replies[] = $reply_id; 450 451 // Update the pre_spammed_replies post meta 452 update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies ); 453 } 454 } 455 456 /** Update counts, etc... *********************************************/ 457 458 do_action( 'bbp_new_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author, false, $reply_to ); 459 460 /** Additional Actions (After Save) ***********************************/ 461 462 do_action( 'bbp_new_reply_post_extras', $reply_id ); 463 464 /** Redirect **********************************************************/ 465 466 // Redirect to 467 $redirect_to = bbp_get_redirect_to(); 468 469 // Get the reply URL 470 $reply_url = bbp_get_reply_url( $reply_id, $redirect_to ); 471 472 // Allow to be filtered 473 $reply_url = apply_filters( 'bbp_new_reply_redirect_to', $reply_url, $redirect_to, $reply_id ); 474 475 /** Successful Save ***************************************************/ 476 477 // Redirect back to new reply 478 bbp_redirect( $reply_url ); 479 480 /** Errors ****************************************************************/ 481 482 // WP_Error 483 } elseif ( is_wp_error( $reply_id ) ) { 484 bbp_add_error( 'bbp_reply_error', sprintf( __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ), $reply_id->get_error_message() ) ); 485 486 // Generic error 487 } else { 488 bbp_add_error( 'bbp_reply_error', __( '<strong>Error</strong>: The reply was not created.', 'bbpress' ) ); 489 } 490 } 491 492 /** 493 * Handles the front end edit reply submission 494 * 495 * @param string $action The requested action to compare this function to 496 * id, anonymous data, reply author, bool true (for edit), 497 * and the reply to id 498 */ 499 function bbp_edit_reply_handler( $action = '' ) { 500 501 // Bail if action is not bbp-edit-reply 502 if ( 'bbp-edit-reply' !== $action ) { 503 return; 504 } 505 506 // Define local variable(s) 507 $revisions_removed = false; 508 $reply = $reply_id = $reply_to = $reply_author = $topic_id = $forum_id = 0; 509 $reply_title = $reply_content = $reply_edit_reason = $terms = ''; 510 $anonymous_data = array(); 511 512 /** Reply *****************************************************************/ 513 514 // Reply id was not passed 515 if ( empty( $_POST['bbp_reply_id'] ) ) { 516 bbp_add_error( 'bbp_edit_reply_id', __( '<strong>Error</strong>: Reply ID not found.', 'bbpress' ) ); 517 return; 518 519 // Reply id was passed 520 } elseif ( is_numeric( $_POST['bbp_reply_id'] ) ) { 521 $reply_id = (int) $_POST['bbp_reply_id']; 522 $reply = bbp_get_reply( $reply_id ); 523 } 524 525 // Nonce check 526 if ( ! bbp_verify_nonce_request( 'bbp-edit-reply_' . $reply_id ) ) { 527 bbp_add_error( 'bbp_edit_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) ); 528 return; 529 } 530 531 // Reply does not exist 532 if ( empty( $reply ) ) { 533 bbp_add_error( 'bbp_edit_reply_not_found', __( '<strong>Error</strong>: The reply you want to edit was not found.', 'bbpress' ) ); 534 return; 535 536 // Reply exists 537 } else { 538 539 // Check users ability to create new reply 540 if ( ! bbp_is_reply_anonymous( $reply_id ) ) { 541 542 // User cannot edit this reply 543 if ( ! current_user_can( 'edit_reply', $reply_id ) ) { 544 bbp_add_error( 'bbp_edit_reply_permission', __( '<strong>Error</strong>: You do not have permission to edit that reply.', 'bbpress' ) ); 545 return; 546 } 547 548 // Set reply author 549 $reply_author = bbp_get_reply_author_id( $reply_id ); 550 551 // It is an anonymous post 552 } else { 553 554 // Filter anonymous data 555 $anonymous_data = bbp_filter_anonymous_post_data(); 556 } 557 } 558 559 // Remove kses filters from title and content for capable users and if the nonce is verified 560 if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $reply_id ) === $_POST['_bbp_unfiltered_html_reply'] ) { 561 remove_filter( 'bbp_edit_reply_pre_title', 'wp_filter_kses' ); 562 remove_filter( 'bbp_edit_reply_pre_content', 'bbp_encode_bad', 10 ); 563 remove_filter( 'bbp_edit_reply_pre_content', 'bbp_filter_kses', 30 ); 564 } 565 566 /** Reply Topic ***********************************************************/ 567 568 $topic_id = bbp_get_reply_topic_id( $reply_id ); 569 570 /** Topic Forum ***********************************************************/ 571 572 $forum_id = bbp_get_topic_forum_id( $topic_id ); 573 574 // Forum exists 575 if ( ! empty( $forum_id ) && ( $forum_id !== bbp_get_reply_forum_id( $reply_id ) ) ) { 576 577 // Forum is a category 578 if ( bbp_is_forum_category( $forum_id ) ) { 579 bbp_add_error( 'bbp_edit_reply_forum_category', __( '<strong>Error</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) ); 580 581 // Forum is not a category 582 } else { 583 584 // Forum is closed and user cannot access 585 if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) { 586 bbp_add_error( 'bbp_edit_reply_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new replies.', 'bbpress' ) ); 587 } 588 589 // Forum is private and user cannot access 590 if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) { 591 bbp_add_error( 'bbp_edit_reply_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) ); 592 593 // Forum is hidden and user cannot access 594 } elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) { 595 bbp_add_error( 'bbp_edit_reply_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) ); 596 } 597 } 598 } 599 600 /** Reply Title ***********************************************************/ 601 602 if ( ! empty( $_POST['bbp_reply_title'] ) ) { 603 $reply_title = sanitize_text_field( $_POST['bbp_reply_title'] ); 604 } 605 606 // Filter and sanitize 607 $reply_title = apply_filters( 'bbp_edit_reply_pre_title', $reply_title, $reply_id ); 608 609 // Title too long 610 if ( bbp_is_title_too_long( $reply_title ) ) { 611 bbp_add_error( 'bbp_reply_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) ); 612 } 613 614 /** Reply Content *********************************************************/ 615 616 if ( ! empty( $_POST['bbp_reply_content'] ) ) { 617 $reply_content = $_POST['bbp_reply_content']; 618 } 619 620 // Filter and sanitize 621 $reply_content = apply_filters( 'bbp_edit_reply_pre_content', $reply_content, $reply_id ); 622 623 // No reply content 624 if ( empty( $reply_content ) ) { 625 bbp_add_error( 'bbp_edit_reply_content', __( '<strong>Error</strong>: Your reply cannot be empty.', 'bbpress' ) ); 626 } 627 628 /** Reply Bad Words *******************************************************/ 629 630 if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content, true ) ) { 631 bbp_add_error( 'bbp_reply_moderation', __( '<strong>Error</strong>: Your reply cannot be edited at this time.', 'bbpress' ) ); 632 } 633 634 /** Reply Status **********************************************************/ 635 636 // Maybe put into moderation 637 if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) { 638 639 // Set post status to pending if public 640 if ( bbp_get_public_status_id() === $reply->post_status ) { 641 $reply_status = bbp_get_pending_status_id(); 642 } 643 644 // Use existing post_status 645 } else { 646 $reply_status = $reply->post_status; 647 } 648 649 /** Reply To **************************************************************/ 650 651 // Handle Reply To of the reply; $_REQUEST for non-JS submissions 652 if ( isset( $_REQUEST['bbp_reply_to'] ) && current_user_can( 'moderate', $reply_id ) ) { 653 $reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'], $reply_id ); 654 } elseif ( bbp_thread_replies() ) { 655 $reply_to = bbp_get_reply_to( $reply_id ); 656 } 657 658 /** Topic Tags ************************************************************/ 659 660 // Either replace terms 661 if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) { 662 $terms = sanitize_text_field( $_POST['bbp_topic_tags'] ); 663 664 // ...or remove them. 665 } elseif ( isset( $_POST['bbp_topic_tags'] ) ) { 666 $terms = ''; 667 668 // Existing terms 669 } else { 670 $terms = bbp_get_topic_tag_names( $topic_id ); 671 } 672 673 /** Additional Actions (Before Save) **************************************/ 674 675 do_action( 'bbp_edit_reply_pre_extras', $reply_id ); 676 677 // Bail if errors 678 if ( bbp_has_errors() ) { 679 return; 680 } 681 682 /** No Errors *************************************************************/ 683 684 // Add the content of the form to $reply_data as an array 685 // Just in time manipulation of reply data before being edited 686 $reply_data = apply_filters( 'bbp_edit_reply_pre_insert', array( 687 'ID' => $reply_id, 688 'post_title' => $reply_title, 689 'post_content' => $reply_content, 690 'post_status' => $reply_status, 691 'post_parent' => $topic_id, 692 'post_author' => $reply_author, 693 'post_type' => bbp_get_reply_post_type() 694 ) ); 695 696 // Toggle revisions to avoid duplicates 697 if ( post_type_supports( bbp_get_reply_post_type(), 'revisions' ) ) { 698 $revisions_removed = true; 699 remove_post_type_support( bbp_get_reply_post_type(), 'revisions' ); 700 } 701 702 // Insert reply 703 $reply_id = wp_update_post( $reply_data ); 704 705 // Toggle revisions back on 706 if ( true === $revisions_removed ) { 707 $revisions_removed = false; 708 add_post_type_support( bbp_get_reply_post_type(), 'revisions' ); 709 } 710 711 /** Topic Tags ************************************************************/ 712 713 // Just in time manipulation of reply terms before being edited 714 $terms = apply_filters( 'bbp_edit_reply_pre_set_terms', $terms, $topic_id, $reply_id ); 715 716 // Insert terms 717 $terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false ); 718 719 // Term error 720 if ( is_wp_error( $terms ) ) { 721 bbp_add_error( 'bbp_reply_tags', __( '<strong>Error</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) ); 722 } 723 724 /** No Errors *************************************************************/ 725 726 if ( ! empty( $reply_id ) && ! is_wp_error( $reply_id ) ) { 727 728 // Update counts, etc... 729 do_action( 'bbp_edit_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author, true, $reply_to ); 730 731 /** Revisions *********************************************************/ 732 733 // Revision Reason 734 if ( ! empty( $_POST['bbp_reply_edit_reason'] ) ) { 735 $reply_edit_reason = sanitize_text_field( $_POST['bbp_reply_edit_reason'] ); 736 } 737 738 // Update revision log 739 if ( ! empty( $_POST['bbp_log_reply_edit'] ) && ( '1' === $_POST['bbp_log_reply_edit'] ) ) { 740 $revision_id = wp_save_post_revision( $reply_id ); 741 if ( ! empty( $revision_id ) ) { 742 bbp_update_reply_revision_log( array( 743 'reply_id' => $reply_id, 744 'revision_id' => $revision_id, 745 'author_id' => bbp_get_current_user_id(), 746 'reason' => $reply_edit_reason 747 ) ); 748 } 749 } 750 751 /** Additional Actions (After Save) ***********************************/ 752 753 do_action( 'bbp_edit_reply_post_extras', $reply_id ); 754 755 /** Redirect **********************************************************/ 756 757 // Redirect to 758 $redirect_to = bbp_get_redirect_to(); 759 760 // Get the reply URL 761 $reply_url = bbp_get_reply_url( $reply_id, $redirect_to ); 762 763 // Allow to be filtered 764 $reply_url = apply_filters( 'bbp_edit_reply_redirect_to', $reply_url, $redirect_to ); 765 766 /** Successful Edit ***************************************************/ 767 768 // Redirect back to new reply 769 bbp_redirect( $reply_url ); 770 771 /** Errors ****************************************************************/ 772 773 } else { 774 $append_error = ( is_wp_error( $reply_id ) && $reply_id->get_error_message() ) ? $reply_id->get_error_message() . ' ' : ''; 775 bbp_add_error( 'bbp_reply_error', __( '<strong>Error</strong>: The following problem(s) have been found with your reply:' . $append_error . 'Please try again.', 'bbpress' ) ); 776 } 777 } 778 779 /** 780 * Handle all the extra meta stuff from posting a new reply or editing a reply 781 * 782 * @param int $reply_id Optional. Reply id 783 * @param int $topic_id Optional. Topic id 784 * @param int $forum_id Optional. Forum id 785 * @param array $anonymous_data Optional - if it's an anonymous post. Do not 786 * supply if supplying $author_id. Should be 787 * sanitized (see {@link bbp_filter_anonymous_post_data()} 788 * @param int $author_id Author id 789 * @param bool $is_edit Optional. Is the post being edited? Defaults to false. 790 * @param int $reply_to Optional. Reply to id 791 */ 792 function bbp_update_reply( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $author_id = 0, $is_edit = false, $reply_to = 0 ) { 793 794 // Validate the ID's passed from 'bbp_new_reply' action 795 $reply_id = bbp_get_reply_id( $reply_id ); 796 $topic_id = bbp_get_topic_id( $topic_id ); 797 $forum_id = bbp_get_forum_id( $forum_id ); 798 $reply_to = bbp_validate_reply_to( $reply_to, $reply_id ); 799 800 // Get the current user ID 801 $user_id = bbp_get_current_user_id(); 802 803 // Bail if there is no reply 804 if ( empty( $reply_id ) ) { 805 return; 806 } 807 808 // Check author_id, fallback to current user ID 809 if ( empty( $author_id ) ) { 810 $author_id = $user_id; 811 } 812 813 // Check topic_id, fallback to post_parent or meta 814 if ( empty( $topic_id ) ) { 815 $topic_id = bbp_get_reply_topic_id( $reply_id ); 816 } 817 818 // Check forum_id, fallback to post_parent or meta 819 if ( ! empty( $topic_id ) && empty( $forum_id ) ) { 820 $forum_id = bbp_get_topic_forum_id( $topic_id ); 821 } 822 823 // Update locks 824 update_post_meta( $reply_id, '_edit_last', $user_id ); 825 delete_post_meta( $reply_id, '_edit_lock' ); 826 827 // Forum/Topic meta (early, for use in downstream functions) 828 bbp_update_reply_forum_id( $reply_id, $forum_id ); 829 bbp_update_reply_topic_id( $reply_id, $topic_id ); 830 bbp_update_reply_to ( $reply_id, $reply_to ); 831 832 // If anonymous post, store name, email, website and ip in post_meta. 833 if ( ! empty( $anonymous_data ) ) { 834 835 // Update anonymous meta data (not cookies) 836 bbp_update_anonymous_post_author( $reply_id, $anonymous_data, bbp_get_reply_post_type() ); 837 838 // Set transient for throttle check (only on new, not edit) 839 if ( empty( $is_edit ) ) { 840 set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time(), HOUR_IN_SECONDS ); 841 } 842 } 843 844 // Handle Subscription Checkbox 845 if ( bbp_is_subscriptions_active() && ! empty( $author_id ) && ! empty( $topic_id ) ) { 846 847 // Check if subscribed 848 $subscribed = bbp_is_user_subscribed( $author_id, $topic_id ); 849 850 // Check for action 851 $subscheck = ( ! empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) ) 852 ? true 853 : false; 854 855 // Subscribed and unsubscribing 856 if ( ( true === $subscribed ) && ( false === $subscheck ) ) { 857 bbp_remove_user_subscription( $author_id, $topic_id ); 858 859 // Not subscribed and subscribing 860 } elseif ( ( false === $subscribed ) && ( true === $subscheck ) ) { 861 bbp_add_user_subscription( $author_id, $topic_id ); 862 } 863 } 864 865 // Update associated topic values if this is a new reply 866 if ( empty( $is_edit ) ) { 867 868 // Update poster activity time 869 bbp_update_user_last_posted( $author_id ); 870 871 // Update poster IP 872 update_post_meta( $reply_id, '_bbp_author_ip', bbp_current_author_ip(), false ); 873 874 // Last active time 875 $last_active_time = get_post_field( 'post_date', $reply_id ); 876 877 // Walk up ancestors and do the dirty work 878 bbp_update_reply_walker( $reply_id, $last_active_time, $forum_id, $topic_id, false ); 879 } 880 881 // Bump the custom query cache 882 wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' ); 883 } 884 885 /** 886 * Walk up the ancestor tree from the current reply, and update all the counts 887 * 888 * @since 2.0.0 bbPress (r2884) 889 * 890 * @param int $reply_id Optional. Reply id 891 * @param string $last_active_time Optional. Last active time 892 * @param int $forum_id Optional. Forum id 893 * @param int $topic_id Optional. Topic id 894 * @param bool $refresh If set to true, unsets all the previous parameters. 895 * Defaults to true 896 */ 897 function bbp_update_reply_walker( $reply_id, $last_active_time = '', $forum_id = 0, $topic_id = 0, $refresh = true ) { 898 899 // Verify the reply ID 900 $reply_id = bbp_get_reply_id( $reply_id ); 901 902 // Reply was passed 903 if ( ! empty( $reply_id ) ) { 904 905 // Get the topic ID if none was passed 906 if ( empty( $topic_id ) ) { 907 $topic_id = bbp_get_reply_topic_id( $reply_id ); 908 } 909 910 // Get the forum ID if none was passed 911 if ( empty( $forum_id ) ) { 912 $forum_id = bbp_get_reply_forum_id( $reply_id ); 913 } 914 } 915 916 // Set the active_id based on topic_id/reply_id 917 $active_id = empty( $reply_id ) ? $topic_id : $reply_id; 918 919 // Setup ancestors array to walk up 920 $ancestors = array_values( array_unique( array_merge( array( $topic_id, $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) ); 921 922 // If we want a full refresh, unset any of the possibly passed variables 923 if ( true === $refresh ) { 924 $forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0; 925 } 926 927 // Walk up ancestors 928 if ( ! empty( $ancestors ) ) { 929 foreach ( $ancestors as $ancestor ) { 930 931 // Reply meta relating to most recent reply 932 if ( bbp_is_reply( $ancestor ) ) { 933 // @todo - hierarchical replies 934 935 // Topic meta relating to most recent reply 936 } elseif ( bbp_is_topic( $ancestor ) ) { 937 938 // Only update if reply is published 939 if ( ! bbp_is_reply_pending( $reply_id ) ) { 940 941 // Last reply and active ID's 942 bbp_update_topic_last_reply_id ( $ancestor, $reply_id ); 943 bbp_update_topic_last_active_id( $ancestor, $active_id ); 944 945 // Get the last active time if none was passed 946 $topic_last_active_time = $last_active_time; 947 if ( empty( $last_active_time ) ) { 948 $topic_last_active_time = get_post_field( 'post_date', bbp_get_topic_last_active_id( $ancestor ) ); 949 } 950 951 bbp_update_topic_last_active_time( $ancestor, $topic_last_active_time ); 952 } 953 954 // Only update reply count if we've deleted a reply 955 if ( in_array( current_filter(), array( 'bbp_deleted_reply', 'save_post' ), true ) ) { 956 bbp_update_topic_reply_count( $ancestor ); 957 bbp_update_topic_reply_count_hidden( $ancestor ); 958 bbp_update_topic_voice_count( $ancestor ); 959 } 960 961 // Forum meta relating to most recent topic 962 } elseif ( bbp_is_forum( $ancestor ) ) { 963 964 // Only update if reply is published 965 if ( ! bbp_is_reply_pending( $reply_id ) && ! bbp_is_topic_pending( $topic_id ) ) { 966 967 // Last topic and reply ID's 968 bbp_update_forum_last_topic_id( $ancestor, $topic_id ); 969 bbp_update_forum_last_reply_id( $ancestor, $reply_id ); 970 971 // Last Active 972 bbp_update_forum_last_active_id( $ancestor, $active_id ); 973 974 // Get the last active time if none was passed 975 $forum_last_active_time = $last_active_time; 976 if ( empty( $last_active_time ) ) { 977 $forum_last_active_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $ancestor ) ); 978 } 979 980 bbp_update_forum_last_active_time( $ancestor, $forum_last_active_time ); 981 } 982 983 // Only update reply count if we've deleted a reply 984 if ( in_array( current_filter(), array( 'bbp_deleted_reply', 'save_post' ), true ) ) { 985 bbp_update_forum_reply_count( $ancestor ); 986 } 987 } 988 } 989 } 990 } 991 992 /** Reply Updaters ************************************************************/ 993 994 /** 995 * Update the reply with its forum id it is in 996 * 997 * @since 2.0.0 bbPress (r2855) 998 * 999 * @param int $reply_id Optional. Reply id to update 1000 * @param int $forum_id Optional. Forum id 1001 * @return bool The forum id of the reply 1002 */ 1003 function bbp_update_reply_forum_id( $reply_id = 0, $forum_id = 0 ) { 1004 1005 // Validation 1006 $reply_id = bbp_get_reply_id( $reply_id ); 1007 $forum_id = bbp_get_forum_id( $forum_id ); 1008 1009 // If no forum_id was passed, walk up ancestors and look for forum type 1010 if ( empty( $forum_id ) ) { 1011 1012 // Get ancestors 1013 $ancestors = get_post_ancestors( $reply_id ); 1014 1015 // Loop through ancestors 1016 if ( ! empty( $ancestors ) ) { 1017 foreach ( $ancestors as $ancestor ) { 1018 1019 // Get first parent that is a forum 1020 if ( get_post_field( 'post_type', $ancestor ) === bbp_get_forum_post_type() ) { 1021 $forum_id = $ancestor; 1022 1023 // Found a forum, so exit the loop and continue 1024 continue; 1025 } 1026 } 1027 } 1028 } 1029 1030 // Update the forum ID 1031 $retval = bbp_update_forum_id( $reply_id, $forum_id ); 1032 1033 // Filter & return 1034 return (int) apply_filters( 'bbp_update_reply_forum_id', $retval, $reply_id, $forum_id ); 1035 } 1036 1037 /** 1038 * Update the reply with its topic id it is in 1039 * 1040 * @since 2.0.0 bbPress (r2855) 1041 * 1042 * @param int $reply_id Optional. Reply id to update 1043 * @param int $topic_id Optional. Topic id 1044 * @return bool The topic id of the reply 1045 */ 1046 function bbp_update_reply_topic_id( $reply_id = 0, $topic_id = 0 ) { 1047 1048 // Validation 1049 $reply_id = bbp_get_reply_id( $reply_id ); 1050 $topic_id = bbp_get_topic_id( $topic_id ); 1051 1052 // If no topic_id was passed, walk up ancestors and look for topic type 1053 if ( empty( $topic_id ) ) { 1054 1055 // Get ancestors 1056 $ancestors = (array) get_post_ancestors( $reply_id ); 1057 1058 // Loop through ancestors 1059 if ( ! empty( $ancestors ) ) { 1060 foreach ( $ancestors as $ancestor ) { 1061 1062 // Get first parent that is a topic 1063 if ( get_post_field( 'post_type', $ancestor ) === bbp_get_topic_post_type() ) { 1064 $topic_id = $ancestor; 1065 1066 // Found a topic, so exit the loop and continue 1067 continue; 1068 } 1069 } 1070 } 1071 } 1072 1073 // Update the topic ID 1074 $retval = bbp_update_topic_id( $reply_id, $topic_id ); 1075 1076 // Filter & return 1077 return (int) apply_filters( 'bbp_update_reply_topic_id', $retval, $reply_id, $topic_id ); 1078 } 1079 1080 /* 1081 * Update the meta data with its parent reply-to id, of a reply 1082 * 1083 * @since 2.4.0 bbPress (r4944) 1084 * 1085 * @param int $reply_id Reply id to update 1086 * @param int $reply_to Optional. Reply to id 1087 * @return bool The parent reply id of the reply 1088 */ 1089 function bbp_update_reply_to( $reply_id = 0, $reply_to = 0 ) { 1090 1091 // Validation 1092 $reply_id = bbp_get_reply_id( $reply_id ); 1093 $reply_to = bbp_validate_reply_to( $reply_to, $reply_id ); 1094 1095 // Update or delete the `reply_to` postmeta 1096 if ( ! empty( $reply_id ) ) { 1097 1098 // Update the reply to 1099 if ( ! empty( $reply_to ) ) { 1100 $reply_to = bbp_update_reply_to_id( $reply_id, $reply_to ); 1101 1102 // Delete the reply to 1103 } else { 1104 delete_post_meta( $reply_id, '_bbp_reply_to' ); 1105 } 1106 } 1107 1108 // Filter & return 1109 return (int) apply_filters( 'bbp_update_reply_to', $reply_to, $reply_id ); 1110 } 1111 1112 /** 1113 * Get all ancestors to a reply 1114 * 1115 * Because settings can be changed, this function does not care if hierarchical 1116 * replies are active or to what depth. 1117 * 1118 * @since 2.6.0 bbPress (r5390) 1119 * 1120 * @param int $reply_id 1121 * @return array 1122 */ 1123 function bbp_get_reply_ancestors( $reply_id = 0 ) { 1124 1125 // Validation 1126 $reply_id = bbp_get_reply_id( $reply_id ); 1127 $ancestors = array(); 1128 1129 // Reply id is valid 1130 if ( ! empty( $reply_id ) ) { 1131 1132 // Try to get reply parent 1133 $reply_to = bbp_get_reply_to( $reply_id ); 1134 1135 // Reply has a hierarchical parent 1136 if ( ! empty( $reply_to ) ) { 1137 1138 // Setup the current ID and current post as an ancestor 1139 $id = $reply_to; 1140 $ancestors = array( $reply_to ); 1141 1142 // Get parent reply 1143 while ( $ancestor = bbp_get_reply( $id ) ) { 1144 1145 // Does parent have a parent? 1146 $grampy_id = bbp_get_reply_to( $ancestor->ID ); 1147 1148 // Loop detection: If the ancestor has been seen before, break. 1149 if ( empty( $ancestor->post_parent ) || ( $grampy_id === $reply_id ) || in_array( $grampy_id, $ancestors, true ) ) { 1150 break; 1151 } 1152 1153 $id = $ancestors[] = $grampy_id; 1154 } 1155 } 1156 } 1157 1158 // Filter & return 1159 return (array) apply_filters( 'bbp_get_reply_ancestors', $ancestors, $reply_id ); 1160 } 1161 1162 /** 1163 * Update the revision log of the reply 1164 * 1165 * @since 2.0.0 bbPress (r2782) 1166 * 1167 * @param array $args Supports these args: 1168 * - reply_id: reply id 1169 * - author_id: Author id 1170 * - reason: Reason for editing 1171 * - revision_id: Revision id 1172 * @return mixed False on failure, true on success 1173 */ 1174 function bbp_update_reply_revision_log( $args = array() ) { 1175 1176 // Parse arguments against default values 1177 $r = bbp_parse_args( $args, array( 1178 'reason' => '', 1179 'reply_id' => 0, 1180 'author_id' => 0, 1181 'revision_id' => 0 1182 ), 'update_reply_revision_log' ); 1183 1184 // Populate the variables 1185 $r['reason'] = bbp_format_revision_reason( $r['reason'] ); 1186 $r['reply_id'] = bbp_get_reply_id( $r['reply_id'] ); 1187 $r['author_id'] = bbp_get_user_id ( $r['author_id'], false, true ); 1188 $r['revision_id'] = (int) $r['revision_id']; 1189 1190 // Get the logs and append the new one to those 1191 $revision_log = bbp_get_reply_raw_revision_log( $r['reply_id'] ); 1192 $revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] ); 1193 1194 // Finally, update 1195 update_post_meta( $r['reply_id'], '_bbp_revision_log', $revision_log ); 1196 1197 // Filter & return 1198 return apply_filters( 'bbp_update_reply_revision_log', $revision_log, $r['reply_id'] ); 1199 } 1200 1201 /** 1202 * Move reply handler 1203 * 1204 * Handles the front end move reply submission 1205 * 1206 * @since 2.3.0 bbPress (r4521) 1207 * 1208 * @param string $action The requested action to compare this function to 1209 */ 1210 function bbp_move_reply_handler( $action = '' ) { 1211 1212 // Bail if action is not 'bbp-move-reply' 1213 if ( 'bbp-move-reply' !== $action ) { 1214 return; 1215 } 1216 1217 // Prevent debug notices 1218 $move_reply_id = $destination_topic_id = 0; 1219 $destination_topic_title = ''; 1220 $destination_topic = $move_reply = $source_topic = ''; 1221 1222 /** Move Reply ***********************************************************/ 1223 1224 if ( empty( $_POST['bbp_reply_id'] ) ) { 1225 bbp_add_error( 'bbp_move_reply_reply_id', __( '<strong>Error</strong>: A reply ID is required.', 'bbpress' ) ); 1226 } else { 1227 $move_reply_id = (int) $_POST['bbp_reply_id']; 1228 } 1229 1230 $move_reply = bbp_get_reply( $move_reply_id ); 1231 1232 // Reply exists 1233 if ( empty( $move_reply ) ) { 1234 bbp_add_error( 'bbp_mover_reply_r_not_found', __( '<strong>Error</strong>: The reply you want to move was not found.', 'bbpress' ) ); 1235 } 1236 1237 /** Topic to Move From ***************************************************/ 1238 1239 // Get the current topic a reply is in 1240 $source_topic = bbp_get_topic( $move_reply->post_parent ); 1241 1242 // No topic 1243 if ( empty( $source_topic ) ) { 1244 bbp_add_error( 'bbp_move_reply_source_not_found', __( '<strong>Error</strong>: The topic you want to move from was not found.', 'bbpress' ) ); 1245 } 1246 1247 // Nonce check failed 1248 if ( ! bbp_verify_nonce_request( 'bbp-move-reply_' . $move_reply->ID ) ) { 1249 bbp_add_error( 'bbp_move_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) ); 1250 return; 1251 } 1252 1253 // Use cannot edit topic 1254 if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) { 1255 bbp_add_error( 'bbp_move_reply_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) ); 1256 } 1257 1258 // How to move 1259 if ( ! empty( $_POST['bbp_reply_move_option'] ) ) { 1260 $move_option = (string) trim( $_POST['bbp_reply_move_option'] ); 1261 } 1262 1263 // Invalid move option 1264 if ( empty( $move_option ) || ! in_array( $move_option, array( 'existing', 'topic' ), true ) ) { 1265 bbp_add_error( 'bbp_move_reply_option', __( '<strong>Error</strong>: You need to choose a valid move option.', 'bbpress' ) ); 1266 1267 // Valid move option 1268 } else { 1269 1270 // What kind of move 1271 switch ( $move_option ) { 1272 1273 // Into an existing topic 1274 case 'existing' : 1275 1276 // Get destination topic id 1277 if ( empty( $_POST['bbp_destination_topic'] ) ) { 1278 bbp_add_error( 'bbp_move_reply_destination_id', __( '<strong>Error</strong>: A topic ID is required.', 'bbpress' ) ); 1279 } else { 1280 $destination_topic_id = (int) $_POST['bbp_destination_topic']; 1281 } 1282 1283 // Get the destination topic 1284 $destination_topic = bbp_get_topic( $destination_topic_id ); 1285 1286 // No destination topic 1287 if ( empty( $destination_topic ) ) { 1288 bbp_add_error( 'bbp_move_reply_destination_not_found', __( '<strong>Error</strong>: The topic you want to move to was not found.', 'bbpress' ) ); 1289 } 1290 1291 // User cannot edit the destination topic 1292 if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) { 1293 bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) ); 1294 } 1295 1296 // Bump the reply position 1297 $reply_position = bbp_get_topic_reply_count( $destination_topic->ID, true ) + 1; 1298 1299 // Update the reply 1300 wp_update_post( array( 1301 'ID' => $move_reply->ID, 1302 'post_title' => '', 1303 'post_name' => false, // will be automatically generated 1304 'post_parent' => $destination_topic->ID, 1305 'menu_order' => $reply_position, 1306 'guid' => '' 1307 ) ); 1308 1309 // Adjust reply meta values 1310 bbp_update_reply_topic_id( $move_reply->ID, $destination_topic->ID ); 1311 bbp_update_reply_forum_id( $move_reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) ); 1312 1313 break; 1314 1315 // Move reply to a new topic 1316 case 'topic' : 1317 default : 1318 1319 // User needs to be able to publish topics 1320 if ( current_user_can( 'publish_topics' ) ) { 1321 1322 // Use the new title that was passed 1323 if ( ! empty( $_POST['bbp_reply_move_destination_title'] ) ) { 1324 $destination_topic_title = sanitize_text_field( $_POST['bbp_reply_move_destination_title'] ); 1325 1326 // Use the source topic title 1327 } else { 1328 $destination_topic_title = $source_topic->post_title; 1329 } 1330 1331 // Update the topic 1332 $destination_topic_id = wp_update_post( array( 1333 'ID' => $move_reply->ID, 1334 'post_title' => $destination_topic_title, 1335 'post_name' => false, 1336 'post_type' => bbp_get_topic_post_type(), 1337 'post_parent' => $source_topic->post_parent, 1338 'guid' => '' 1339 ) ); 1340 $destination_topic = bbp_get_topic( $destination_topic_id ); 1341 1342 // Make sure the new topic knows its a topic 1343 bbp_update_topic_topic_id( $move_reply->ID ); 1344 1345 // Shouldn't happen 1346 if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) { 1347 bbp_add_error( 'bbp_move_reply_destination_reply', __( '<strong>Error</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) ); 1348 } 1349 1350 // User cannot publish posts 1351 } else { 1352 bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>Error</strong>: You do not have permission to create new topics. The reply could not be converted into a topic.', 'bbpress' ) ); 1353 } 1354 1355 break; 1356 } 1357 } 1358 1359 // Bail if there are errors 1360 if ( bbp_has_errors() ) { 1361 return; 1362 } 1363 1364 /** No Errors - Clean Up **************************************************/ 1365 1366 // Update counts, etc... 1367 do_action( 'bbp_pre_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID ); 1368 1369 /** Date Check ************************************************************/ 1370 1371 // Check if the destination topic is older than the move reply 1372 if ( strtotime( $move_reply->post_date ) < strtotime( $destination_topic->post_date ) ) { 1373 1374 // Set destination topic post_date to 1 second before from reply 1375 $destination_post_date = date( 'Y-m-d H:i:s', strtotime( $move_reply->post_date ) - 1 ); 1376 1377 // Update destination topic 1378 wp_update_post( array( 1379 'ID' => $destination_topic_id, 1380 'post_date' => $destination_post_date, 1381 'post_date_gmt' => get_gmt_from_date( $destination_post_date ) 1382 ) ); 1383 } 1384 1385 // Set the last reply ID and freshness to the move_reply 1386 $last_reply_id = $move_reply->ID; 1387 $freshness = $move_reply->post_date; 1388 1389 // Get the reply to 1390 $parent = bbp_get_reply_to( $move_reply->ID ); 1391 1392 // Fix orphaned children 1393 $children = get_posts( array( 1394 'post_type' => bbp_get_reply_post_type(), 1395 'meta_key' => '_bbp_reply_to', 1396 'meta_type' => 'NUMERIC', 1397 'meta_value' => $move_reply->ID, 1398 ) ); 1399 foreach ( $children as $child ) { 1400 bbp_update_reply_to( $child->ID, $parent ); 1401 } 1402 1403 // Remove reply_to from moved reply 1404 delete_post_meta( $move_reply->ID, '_bbp_reply_to' ); 1405 1406 // It is a new topic and we need to set some default metas to make 1407 // the topic display in bbp_has_topics() list 1408 if ( 'topic' === $move_option ) { 1409 bbp_update_topic_last_reply_id ( $destination_topic->ID, $last_reply_id ); 1410 bbp_update_topic_last_active_id ( $destination_topic->ID, $last_reply_id ); 1411 bbp_update_topic_last_active_time( $destination_topic->ID, $freshness ); 1412 1413 // Otherwise update the existing destination topic 1414 } else { 1415 bbp_update_topic_last_reply_id ( $destination_topic->ID ); 1416 bbp_update_topic_last_active_id ( $destination_topic->ID ); 1417 bbp_update_topic_last_active_time( $destination_topic->ID ); 1418 } 1419 1420 // Update source topic ID last active 1421 bbp_update_topic_last_reply_id ( $source_topic->ID ); 1422 bbp_update_topic_last_active_id ( $source_topic->ID ); 1423 bbp_update_topic_last_active_time( $source_topic->ID ); 1424 1425 /** Successful Move ******************************************************/ 1426 1427 // Update counts, etc... 1428 do_action( 'bbp_post_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID ); 1429 1430 // Redirect back to the topic 1431 bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) ); 1432 } 1433 1434 /** 1435 * Fix counts on reply move 1436 * 1437 * When a reply is moved, update the counts of source and destination topic 1438 * and their forums. 1439 * 1440 * @since 2.3.0 bbPress (r4521) 1441 * 1442 * @param int $move_reply_id Move reply id 1443 * @param int $source_topic_id Source topic id 1444 * @param int $destination_topic_id Destination topic id 1445 */ 1446 function bbp_move_reply_count( $move_reply_id, $source_topic_id, $destination_topic_id ) { 1447 1448 // Forum topic counts 1449 bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1450 1451 // Forum reply counts 1452 bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1453 1454 // Topic reply counts 1455 bbp_update_topic_reply_count( $source_topic_id ); 1456 bbp_update_topic_reply_count( $destination_topic_id ); 1457 1458 // Topic hidden reply counts 1459 bbp_update_topic_reply_count_hidden( $source_topic_id ); 1460 bbp_update_topic_reply_count_hidden( $destination_topic_id ); 1461 1462 // Topic voice counts 1463 bbp_update_topic_voice_count( $source_topic_id ); 1464 bbp_update_topic_voice_count( $destination_topic_id ); 1465 1466 do_action( 'bbp_move_reply_count', $move_reply_id, $source_topic_id, $destination_topic_id ); 1467 } 1468 1469 /** Reply Actions *************************************************************/ 1470 1471 /** 1472 * Handles the front end spamming/unspamming and trashing/untrashing/deleting of 1473 * replies 1474 * 1475 * @since 2.0.0 bbPress (r2740) 1476 * 1477 * @param string $action The requested action to compare this function to 1478 */ 1479 function bbp_toggle_reply_handler( $action = '' ) { 1480 1481 // Bail if required GET actions aren't passed 1482 if ( empty( $_GET['reply_id'] ) ) { 1483 return; 1484 } 1485 1486 // What's the reply id? 1487 $reply_id = bbp_get_reply_id( (int) $_GET['reply_id'] ); 1488 1489 // Get possible reply-handler toggles 1490 $toggles = bbp_get_reply_toggles( $reply_id ); 1491 1492 // Bail if action isn't meant for this function 1493 if ( ! in_array( $action, $toggles, true ) ) { 1494 return; 1495 } 1496 1497 // Make sure reply exists 1498 $reply = bbp_get_reply( $reply_id ); 1499 if ( empty( $reply ) ) { 1500 bbp_add_error( 'bbp_toggle_reply_missing', __( '<strong>Error</strong>: This reply could not be found or no longer exists.', 'bbpress' ) ); 1501 return; 1502 } 1503 1504 // What is the user doing here? 1505 if ( ! current_user_can( 'edit_reply', $reply_id ) || ( 'bbp_toggle_reply_trash' === $action && ! current_user_can( 'delete_reply', $reply_id ) ) ) { 1506 bbp_add_error( 'bbp_toggle_reply_permission', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) ); 1507 return; 1508 } 1509 1510 // Sub-action? 1511 $sub_action = ! empty( $_GET['sub_action'] ) 1512 ? sanitize_key( $_GET['sub_action'] ) 1513 : false; 1514 1515 // Preliminary array 1516 $post_data = array( 'ID' => $reply_id ); 1517 1518 // Do the reply toggling 1519 $retval = bbp_toggle_reply( array( 1520 'id' => $reply_id, 1521 'action' => $action, 1522 'sub_action' => $sub_action, 1523 'data' => $post_data 1524 ) ); 1525 1526 // Do additional reply toggle actions 1527 do_action( 'bbp_toggle_reply_handler', $retval['status'], $post_data, $action ); 1528 1529 // Redirect back to reply 1530 if ( ( false !== $retval['status'] ) && ! is_wp_error( $retval['status'] ) ) { 1531 bbp_redirect( $retval['redirect_to'] ); 1532 1533 // Handle errors 1534 } else { 1535 bbp_add_error( 'bbp_toggle_reply', $retval['message'] ); 1536 } 1537 } 1538 1539 /** 1540 * Do the actual reply toggling 1541 * 1542 * This function is used by `bbp_toggle_reply_handler()` to do the actual heavy 1543 * lifting when it comes to toggling replies. It only really makes sense to call 1544 * within that context, so if you need to call this function directly, make sure 1545 * you're also doing what the handler does too. 1546 * 1547 * @since 2.6.0 bbPress (r6133) 1548 * @access private 1549 * 1550 * @param array $args 1551 */ 1552 function bbp_toggle_reply( $args = array() ) { 1553 1554 // Parse the arguments 1555 $r = bbp_parse_args( $args, array( 1556 'id' => 0, 1557 'action' => '', 1558 'sub_action' => '', 1559 'data' => array() 1560 ) ); 1561 1562 // Build the nonce suffix 1563 $nonce_suffix = bbp_get_reply_post_type() . '_' . (int) $r['id']; 1564 1565 // Default return values 1566 $retval = array( 1567 'status' => 0, 1568 'message' => '', 1569 'redirect_to' => bbp_get_reply_url( $r['id'], bbp_get_redirect_to() ), 1570 'view_all' => false 1571 ); 1572 1573 // What action are we trying to perform? 1574 switch ( $r['action'] ) { 1575 1576 // Toggle approve 1577 case 'bbp_toggle_reply_approve' : 1578 check_ajax_referer( "approve-{$nonce_suffix}" ); 1579 1580 $is_approve = bbp_is_reply_pending( $r['id'] ); 1581 $retval['status'] = $is_approve ? bbp_approve_reply( $r['id'] ) : bbp_unapprove_reply( $r['id'] ); 1582 $retval['message'] = $is_approve ? __( '<strong>Error</strong>: There was a problem approving the reply.', 'bbpress' ) : __( '<strong>Error</strong>: There was a problem unapproving the reply.', 'bbpress' ); 1583 $retval['view_all'] = ! $is_approve; 1584 1585 break; 1586 1587 // Toggle spam 1588 case 'bbp_toggle_reply_spam' : 1589 check_ajax_referer( "spam-{$nonce_suffix}" ); 1590 1591 $is_spam = bbp_is_reply_spam( $r['id'] ); 1592 $retval['status'] = $is_spam ? bbp_unspam_reply( $r['id'] ) : bbp_spam_reply( $r['id'] ); 1593 $retval['message'] = $is_spam ? __( '<strong>Error</strong>: There was a problem unmarking the reply as spam.', 'bbpress' ) : __( '<strong>Error</strong>: There was a problem marking the reply as spam.', 'bbpress' ); 1594 $retval['view_all'] = ! $is_spam; 1595 1596 break; 1597 1598 // Toggle trash 1599 case 'bbp_toggle_reply_trash' : 1600 1601 // Which subaction? 1602 switch ( $r['sub_action'] ) { 1603 case 'trash': 1604 check_ajax_referer( "trash-{$nonce_suffix}" ); 1605 1606 $retval['view_all'] = true; 1607 $retval['status'] = wp_trash_post( $r['id'] ); 1608 $retval['message'] = __( '<strong>Error</strong>: There was a problem trashing the reply.', 'bbpress' ); 1609 1610 break; 1611 1612 case 'untrash': 1613 check_ajax_referer( "untrash-{$nonce_suffix}" ); 1614 1615 $retval['status'] = wp_untrash_post( $r['id'] ); 1616 $retval['message'] = __( '<strong>Error</strong>: There was a problem untrashing the reply.', 'bbpress' ); 1617 1618 break; 1619 1620 case 'delete': 1621 check_ajax_referer( "delete-{$nonce_suffix}" ); 1622 1623 $retval['status'] = wp_delete_post( $r['id'] ); 1624 $retval['message'] = __( '<strong>Error</strong>: There was a problem deleting the reply.', 'bbpress' ); 1625 1626 break; 1627 } 1628 1629 break; 1630 } 1631 1632 // Add view all if needed 1633 if ( ! empty( $retval['view_all'] ) ) { 1634 $retval['redirect_to'] = bbp_add_view_all( $retval['redirect_to'], true ); 1635 } 1636 1637 // Filter & return 1638 return apply_filters( 'bbp_toggle_reply', $retval, $r, $args ); 1639 } 1640 1641 /** Helpers *******************************************************************/ 1642 1643 /** 1644 * Return an associative array of available reply statuses 1645 * 1646 * @since 2.6.0 bbPress (r5399) 1647 * 1648 * @param int $reply_id Optional. Reply id. 1649 * 1650 * @return array 1651 */ 1652 function bbp_get_reply_statuses( $reply_id = 0 ) { 1653 1654 // Filter & return 1655 return (array) apply_filters( 'bbp_get_reply_statuses', array( 1656 bbp_get_public_status_id() => _x( 'Publish', 'Publish the reply', 'bbpress' ), 1657 bbp_get_spam_status_id() => _x( 'Spam', 'Spam the reply', 'bbpress' ), 1658 bbp_get_trash_status_id() => _x( 'Trash', 'Trash the reply', 'bbpress' ), 1659 bbp_get_pending_status_id() => _x( 'Pending', 'Mark reply as pending', 'bbpress' ) 1660 ), $reply_id ); 1661 } 1662 1663 /** 1664 * Return array of available reply toggle actions 1665 * 1666 * @since 2.6.0 bbPress (r6133) 1667 * 1668 * @param int $reply_id Optional. Reply id. 1669 * 1670 * @return array 1671 */ 1672 function bbp_get_reply_toggles( $reply_id = 0 ) { 1673 1674 // Filter & return 1675 return (array) apply_filters( 'bbp_get_toggle_reply_actions', array( 1676 'bbp_toggle_reply_spam', 1677 'bbp_toggle_reply_trash', 1678 'bbp_toggle_reply_approve' 1679 ), $reply_id ); 1680 } 1681 1682 /** 1683 * Return array of public reply statuses. 1684 * 1685 * @since 2.6.0 bbPress (r6705) 1686 * 1687 * @return array 1688 */ 1689 function bbp_get_public_reply_statuses() { 1690 $statuses = array( 1691 bbp_get_public_status_id() 1692 ); 1693 1694 // Filter & return 1695 return (array) apply_filters( 'bbp_get_public_reply_statuses', $statuses ); 1696 } 1697 1698 /** 1699 * Return array of non-public reply statuses. 1700 * 1701 * @since 2.6.0 bbPress (r6791) 1702 * 1703 * @return array 1704 */ 1705 function bbp_get_non_public_reply_statuses() { 1706 $statuses = array( 1707 bbp_get_trash_status_id(), 1708 bbp_get_spam_status_id(), 1709 bbp_get_pending_status_id() 1710 ); 1711 1712 // Filter & return 1713 return (array) apply_filters( 'bbp_get_non_public_reply_statuses', $statuses ); 1714 } 1715 1716 /** Reply Actions *************************************************************/ 1717 1718 /** 1719 * Marks a reply as spam 1720 * 1721 * @since 2.0.0 bbPress (r2740) 1722 * 1723 * @param int $reply_id Reply id 1724 * @return mixed False or {@link WP_Error} on failure, reply id on success 1725 */ 1726 function bbp_spam_reply( $reply_id = 0 ) { 1727 1728 // Get reply 1729 $reply = bbp_get_reply( $reply_id ); 1730 if ( empty( $reply ) ) { 1731 return $reply; 1732 } 1733 1734 // Bail if already spam 1735 if ( bbp_get_spam_status_id() === $reply->post_status ) { 1736 return false; 1737 } 1738 1739 // Execute pre spam code 1740 do_action( 'bbp_spam_reply', $reply_id ); 1741 1742 // Add the original post status as post meta for future restoration 1743 add_post_meta( $reply_id, '_bbp_spam_meta_status', $reply->post_status ); 1744 1745 // Set post status to spam 1746 $reply->post_status = bbp_get_spam_status_id(); 1747 1748 // No revisions 1749 remove_action( 'pre_post_update', 'wp_save_post_revision' ); 1750 1751 // Update the reply 1752 $reply_id = wp_update_post( $reply ); 1753 1754 // Execute post spam code 1755 do_action( 'bbp_spammed_reply', $reply_id ); 1756 1757 // Return reply_id 1758 return $reply_id; 1759 } 1760 1761 /** 1762 * Unspams a reply 1763 * 1764 * @since 2.0.0 bbPress (r2740) 1765 * 1766 * @param int $reply_id Reply id 1767 * @return mixed False or {@link WP_Error} on failure, reply id on success 1768 */ 1769 function bbp_unspam_reply( $reply_id = 0 ) { 1770 1771 // Get reply 1772 $reply = bbp_get_reply( $reply_id ); 1773 if ( empty( $reply ) ) { 1774 return $reply; 1775 } 1776 1777 // Bail if already not spam 1778 if ( bbp_get_spam_status_id() !== $reply->post_status ) { 1779 return false; 1780 } 1781 1782 // Execute pre unspam code 1783 do_action( 'bbp_unspam_reply', $reply_id ); 1784 1785 // Get pre spam status 1786 $reply->post_status = get_post_meta( $reply_id, '_bbp_spam_meta_status', true ); 1787 1788 // If no previous status, default to publish 1789 if ( empty( $reply->post_status ) ) { 1790 $reply->post_status = bbp_get_public_status_id(); 1791 } 1792 1793 // Delete pre spam meta 1794 delete_post_meta( $reply_id, '_bbp_spam_meta_status' ); 1795 1796 // No revisions 1797 remove_action( 'pre_post_update', 'wp_save_post_revision' ); 1798 1799 // Update the reply 1800 $reply_id = wp_update_post( $reply ); 1801 1802 // Execute post unspam code 1803 do_action( 'bbp_unspammed_reply', $reply_id ); 1804 1805 // Return reply_id 1806 return $reply_id; 1807 } 1808 1809 /** 1810 * Approves a reply 1811 * 1812 * @since 2.6.0 bbPress (r5506) 1813 * 1814 * @param int $reply_id Reply id 1815 * @return mixed False or {@link WP_Error} on failure, reply id on success 1816 */ 1817 function bbp_approve_reply( $reply_id = 0 ) { 1818 1819 // Get reply 1820 $reply = bbp_get_reply( $reply_id ); 1821 if ( empty( $reply ) ) { 1822 return $reply; 1823 } 1824 1825 // Get new status 1826 $status = bbp_get_public_status_id(); 1827 1828 // Bail if already approved 1829 if ( $status === $reply->post_status ) { 1830 return false; 1831 } 1832 1833 // Execute pre pending code 1834 do_action( 'bbp_approve_reply', $reply_id ); 1835 1836 // Set publish status 1837 $reply->post_status = $status; 1838 1839 // Set post date GMT - prevents post_date override in wp_update_post() 1840 $reply->post_date_gmt = get_gmt_from_date( $reply->post_date ); 1841 1842 // No revisions 1843 remove_action( 'pre_post_update', 'wp_save_post_revision' ); 1844 1845 // Update reply 1846 $reply_id = wp_update_post( $reply ); 1847 1848 // Execute post pending code 1849 do_action( 'bbp_approved_reply', $reply_id ); 1850 1851 // Return reply_id 1852 return $reply_id; 1853 } 1854 1855 /** 1856 * Unapproves a reply 1857 * 1858 * @since 2.6.0 bbPress (r5506) 1859 * 1860 * @param int $reply_id Reply id 1861 * @return mixed False or {@link WP_Error} on failure, reply id on success 1862 */ 1863 function bbp_unapprove_reply( $reply_id = 0 ) { 1864 1865 // Get reply 1866 $reply = bbp_get_reply( $reply_id ); 1867 if ( empty( $reply ) ) { 1868 return $reply; 1869 } 1870 1871 // Get new status 1872 $status = bbp_get_pending_status_id(); 1873 1874 // Bail if already pending 1875 if ( $status === $reply->post_status ) { 1876 return false; 1877 } 1878 1879 // Execute pre open code 1880 do_action( 'bbp_unapprove_reply', $reply_id ); 1881 1882 // Set pending status 1883 $reply->post_status = $status; 1884 1885 // No revisions 1886 remove_action( 'pre_post_update', 'wp_save_post_revision' ); 1887 1888 // Update reply 1889 $reply_id = wp_update_post( $reply ); 1890 1891 // Execute post open code 1892 do_action( 'bbp_unapproved_reply', $reply_id ); 1893 1894 // Return reply_id 1895 return $reply_id; 1896 } 1897 1898 /** Before Delete/Trash/Untrash ***********************************************/ 1899 1900 /** 1901 * Called before deleting a reply 1902 */ 1903 function bbp_delete_reply( $reply_id = 0 ) { 1904 $reply_id = bbp_get_reply_id( $reply_id ); 1905 1906 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1907 return false; 1908 } 1909 1910 do_action( 'bbp_delete_reply', $reply_id ); 1911 } 1912 1913 /** 1914 * Called before trashing a reply 1915 */ 1916 function bbp_trash_reply( $reply_id = 0 ) { 1917 $reply_id = bbp_get_reply_id( $reply_id ); 1918 1919 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1920 return false; 1921 } 1922 1923 do_action( 'bbp_trash_reply', $reply_id ); 1924 } 1925 1926 /** 1927 * Called before untrashing (restoring) a reply 1928 */ 1929 function bbp_untrash_reply( $reply_id = 0 ) { 1930 $reply_id = bbp_get_reply_id( $reply_id ); 1931 1932 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1933 return false; 1934 } 1935 1936 do_action( 'bbp_untrash_reply', $reply_id ); 1937 } 1938 1939 /** After Delete/Trash/Untrash ************************************************/ 1940 1941 /** 1942 * Called after deleting a reply 1943 * 1944 * @since 2.0.0 bbPress (r2993) 1945 */ 1946 function bbp_deleted_reply( $reply_id = 0 ) { 1947 $reply_id = bbp_get_reply_id( $reply_id ); 1948 1949 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1950 return false; 1951 } 1952 1953 do_action( 'bbp_deleted_reply', $reply_id ); 1954 } 1955 1956 /** 1957 * Called after trashing a reply 1958 * 1959 * @since 2.0.0 bbPress (r2993) 1960 */ 1961 function bbp_trashed_reply( $reply_id = 0 ) { 1962 $reply_id = bbp_get_reply_id( $reply_id ); 1963 1964 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1965 return false; 1966 } 1967 1968 do_action( 'bbp_trashed_reply', $reply_id ); 1969 } 1970 1971 /** 1972 * Called after untrashing (restoring) a reply 1973 * 1974 * @since 2.0.0 bbPress (r2993) 1975 */ 1976 function bbp_untrashed_reply( $reply_id = 0 ) { 1977 $reply_id = bbp_get_reply_id( $reply_id ); 1978 1979 if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) { 1980 return false; 1981 } 1982 1983 do_action( 'bbp_untrashed_reply', $reply_id ); 1984 } 1985 1986 /** Settings ******************************************************************/ 1987 1988 /** 1989 * Return the replies per page setting 1990 * 1991 * @since 2.0.0 bbPress (r3540) 1992 * 1993 * @param int $default Default replies per page (15) 1994 * @return int 1995 */ 1996 function bbp_get_replies_per_page( $default = 15 ) { 1997 1998 // Get database option and cast as integer 1999 $retval = get_option( '_bbp_replies_per_page', $default ); 2000 2001 // If return val is empty, set it to default 2002 if ( empty( $retval ) ) { 2003 $retval = $default; 2004 } 2005 2006 // Filter & return 2007 return (int) apply_filters( 'bbp_get_replies_per_page', $retval, $default ); 2008 } 2009 2010 /** 2011 * Return the replies per RSS page setting 2012 * 2013 * @since 2.0.0 bbPress (r3540) 2014 * 2015 * @param int $default Default replies per page (25) 2016 * @return int 2017 */ 2018 function bbp_get_replies_per_rss_page( $default = 25 ) { 2019 2020 // Get database option and cast as integer 2021 $retval = get_option( '_bbp_replies_per_rss_page', $default ); 2022 2023 // If return val is empty, set it to default 2024 if ( empty( $retval ) ) { 2025 $retval = $default; 2026 } 2027 2028 // Filter & return 2029 return (int) apply_filters( 'bbp_get_replies_per_rss_page', $retval, $default ); 2030 } 2031 2032 /** Autoembed *****************************************************************/ 2033 2034 /** 2035 * Check if autoembeds are enabled and hook them in if so 2036 * 2037 * @since 2.1.0 bbPress (r3752) 2038 * 2039 * @global WP_Embed $wp_embed 2040 */ 2041 function bbp_reply_content_autoembed() { 2042 global $wp_embed; 2043 2044 if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) { 2045 add_filter( 'bbp_get_reply_content', array( $wp_embed, 'autoembed' ), 2 ); 2046 } 2047 } 2048 2049 /** Filters *******************************************************************/ 2050 2051 /** 2052 * Used by bbp_has_replies() to add the lead topic post to the posts loop 2053 * 2054 * This function filters the 'post_where' of the WP_Query, and changes the query 2055 * to include both the topic AND its children in the same loop. 2056 * 2057 * @since 2.1.0 bbPress (r4058) 2058 * 2059 * @param string $where 2060 * @return string 2061 */ 2062 function _bbp_has_replies_where( $where = '', $query = false ) { 2063 2064 /** Bail ******************************************************************/ 2065 2066 // Bail if the sky is falling 2067 if ( empty( $where ) || empty( $query ) ) { 2068 return $where; 2069 } 2070 2071 // Bail if no post_parent to replace 2072 if ( ! is_numeric( $query->get( 'post_parent' ) ) ) { 2073 return $where; 2074 } 2075 2076 // Bail if not a topic and reply query 2077 if ( array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ) !== $query->get( 'post_type' ) ) { 2078 return $where; 2079 } 2080 2081 // Bail if including specific post ID's 2082 if ( $query->get( 'post__in' ) ) { 2083 return $where; 2084 } 2085 2086 /** Proceed ***************************************************************/ 2087 2088 // Table name for posts 2089 $table_name = bbp_db()->prefix . 'posts'; 2090 2091 // Get the topic ID from the post_parent, set in bbp_has_replies() 2092 $topic_id = bbp_get_topic_id( $query->get( 'post_parent' ) ); 2093 2094 // The texts to search for 2095 $search = array( 2096 "FROM {$table_name} ", 2097 "WHERE 1=1 AND {$table_name}.post_parent = {$topic_id}", 2098 ") AND {$table_name}.post_parent = {$topic_id}" 2099 ); 2100 2101 // The texts to replace them with 2102 $replace = array( 2103 $search[0] . 'FORCE INDEX (PRIMARY, post_parent) ', 2104 "WHERE 1=1 AND ({$table_name}.ID = {$topic_id} OR {$table_name}.post_parent = {$topic_id})", 2105 ") AND ({$table_name}.ID = {$topic_id} OR {$table_name}.post_parent = {$topic_id})" 2106 ); 2107 2108 // Try to replace the search text with the replacement 2109 $new_where = str_replace( $search, $replace, $where ); 2110 if ( ! empty( $new_where ) ) { 2111 $where = $new_where; 2112 } 2113 2114 return $where; 2115 } 2116 2117 /** Feeds *********************************************************************/ 2118 2119 /** 2120 * Output an RSS2 feed of replies, based on the query passed. 2121 * 2122 * @since 2.0.0 bbPress (r3171) 2123 * 2124 * @param array $replies_query 2125 */ 2126 function bbp_display_replies_feed_rss2( $replies_query = array() ) { 2127 2128 // User cannot access forum this topic is in 2129 if ( bbp_is_single_topic() && ! bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) { 2130 return; 2131 } 2132 2133 // Adjust the title based on context 2134 if ( bbp_is_single_topic() ) { 2135 $title = get_wp_title_rss(); 2136 } elseif ( ! bbp_show_lead_topic() ) { 2137 $title = get_bloginfo_rss( 'name' ) . ' » ' . __( 'All Posts', 'bbpress' ); 2138 } else { 2139 $title = get_bloginfo_rss( 'name' ) . ' » ' . __( 'All Replies', 'bbpress' ); 2140 } 2141 2142 $title = apply_filters( 'wp_title_rss', $title ); 2143 2144 // Display the feed 2145 header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true ); 2146 header( 'Status: 200 OK' ); 2147 echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?> 2148 2149 <rss version="2.0" 2150 xmlns:content="http://purl.org/rss/1.0/modules/content/" 2151 xmlns:wfw="http://wellformedweb.org/CommentAPI/" 2152 xmlns:dc="http://purl.org/dc/elements/1.1/" 2153 xmlns:atom="http://www.w3.org/2005/Atom" 2154 2155 <?php do_action( 'bbp_feed' ); ?> 2156 > 2157 2158 <channel> 2159 2160 <title><?php echo $title; // Already escaped ?></title> 2161 <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" /> 2162 <link><?php self_link(); ?></link> 2163 <description><?php //?></description><?php // phpcs:ignore ?> 2164 <lastBuildDate><?php echo date( 'r' ); ?></lastBuildDate> 2165 <generator><?php echo esc_url_raw( 'https://bbpress.org/?v=' . convert_chars( bbp_get_version() ) ); ?></generator> 2166 <language><?php bloginfo_rss( 'language' ); ?></language> 2167 2168 <?php do_action( 'bbp_feed_head' ); ?> 2169 2170 <?php if ( bbp_is_single_topic() ) : ?> 2171 <?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) : ?> 2172 <?php if ( bbp_show_lead_topic() ) : ?> 2173 2174 <item> 2175 <guid><?php bbp_topic_permalink(); ?></guid> 2176 <title><![CDATA[<?php bbp_topic_title(); ?>]]></title> 2177 <link><?php bbp_topic_permalink(); ?></link> 2178 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> 2179 <dc:creator><?php the_author(); ?></dc:creator> 2180 2181 <description> 2182 <![CDATA[ 2183 <p><?php printf( __( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p> 2184 <?php bbp_topic_content(); ?> 2185 ]]> 2186 </description> 2187 2188 <?php rss_enclosure(); ?> 2189 2190 <?php do_action( 'bbp_feed_item' ); ?> 2191 2192 </item> 2193 2194 <?php endif; ?> 2195 <?php endif; ?> 2196 <?php endif; ?> 2197 2198 <?php if ( bbp_has_replies( $replies_query ) ) : ?> 2199 <?php while ( bbp_replies() ) : bbp_the_reply(); ?> 2200 2201 <item> 2202 <guid><?php bbp_reply_url(); ?></guid> 2203 <title><![CDATA[<?php bbp_reply_title(); ?>]]></title> 2204 <link><?php bbp_reply_url(); ?></link> 2205 <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate> 2206 <dc:creator><?php the_author(); ?></dc:creator> 2207 2208 <description> 2209 <![CDATA[ 2210 <?php bbp_reply_content(); ?> 2211 ]]> 2212 </description> 2213 2214 <?php rss_enclosure(); ?> 2215 2216 <?php do_action( 'bbp_feed_item' ); ?> 2217 2218 </item> 2219 2220 <?php endwhile; ?> 2221 <?php endif; ?> 2222 2223 <?php do_action( 'bbp_feed_footer' ); ?> 2224 2225 </channel> 2226 </rss> 2227 2228 <?php 2229 2230 // We're done here 2231 exit(); 2232 } 2233 2234 /** Permissions ***************************************************************/ 2235 2236 /** 2237 * Redirect if unauthorized user is attempting to edit a reply 2238 * 2239 * @since 2.1.0 bbPress (r3605) 2240 */ 2241 function bbp_check_reply_edit() { 2242 2243 // Bail if not editing a topic 2244 if ( ! bbp_is_reply_edit() ) { 2245 return; 2246 } 2247 2248 // User cannot edit topic, so redirect back to reply 2249 if ( ! current_user_can( 'edit_reply', bbp_get_reply_id() ) ) { 2250 bbp_redirect( bbp_get_reply_url() ); 2251 } 2252 } 2253 2254 /** Reply Position ************************************************************/ 2255 2256 /** 2257 * Update the position of the reply. 2258 * 2259 * The reply position is stored in the menu_order column of the posts table. 2260 * This is done to prevent using a meta_query to retrieve posts in the proper 2261 * freshness order. By updating the menu_order accordingly, we're able to 2262 * leverage core WordPress query ordering much more effectively. 2263 * 2264 * @since 2.1.0 bbPress (r3933) 2265 * 2266 * @param int $reply_id 2267 * @param int $reply_position 2268 * 2269 * @return mixed 2270 */ 2271 function bbp_update_reply_position( $reply_id = 0, $reply_position = false ) { 2272 2273 // Bail if reply_id is empty 2274 $reply_id = bbp_get_reply_id( $reply_id ); 2275 if ( empty( $reply_id ) ) { 2276 return false; 2277 } 2278 2279 // Prepare the reply position 2280 $reply_position = is_numeric( $reply_position ) 2281 ? (int) $reply_position 2282 : bbp_get_reply_position_raw( $reply_id, bbp_get_reply_topic_id( $reply_id ) ); 2283 2284 // Get the current reply position 2285 $current_position = get_post_field( 'menu_order', $reply_id ); 2286 2287 // Bail if no change 2288 if ( $reply_position === $current_position ) { 2289 return false; 2290 } 2291 2292 // Filters not removed 2293 $removed = false; 2294 2295 // Toggle revisions off as we are not altering content 2296 if ( has_filter( 'clean_post_cache', 'bbp_clean_post_cache' ) ) { 2297 $removed = true; 2298 remove_filter( 'clean_post_cache', 'bbp_clean_post_cache', 10, 2 ); 2299 } 2300 2301 // Update the replies' 'menu_order' with the reply position 2302 $bbp_db = bbp_db(); 2303 $bbp_db->update( $bbp_db->posts, array( 'menu_order' => $reply_position ), array( 'ID' => $reply_id ) ); 2304 clean_post_cache( $reply_id ); 2305 2306 // Toggle revisions back on 2307 if ( true === $removed ) { 2308 $removed = false; 2309 add_filter( 'clean_post_cache', 'bbp_clean_post_cache', 10, 2 ); 2310 } 2311 2312 return (int) $reply_position; 2313 } 2314 2315 /** 2316 * Get the position of a reply by querying the DB directly for the replies 2317 * of a given topic. 2318 * 2319 * @since 2.1.0 bbPress (r3933) 2320 * 2321 * @param int $reply_id 2322 * @param int $topic_id 2323 */ 2324 function bbp_get_reply_position_raw( $reply_id = 0, $topic_id = 0 ) { 2325 2326 // Get required data 2327 $reply_position = 0; 2328 $reply_id = bbp_get_reply_id( $reply_id ); 2329 $topic_id = ! empty( $topic_id ) 2330 ? bbp_get_topic_id( $topic_id ) 2331 : bbp_get_reply_topic_id( $reply_id ); 2332 2333 // If reply is actually the first post in a topic, return 0 2334 if ( $reply_id !== $topic_id ) { 2335 2336 // Make sure the topic has replies before running another query 2337 $reply_count = bbp_get_topic_reply_count( $topic_id, false ); 2338 if ( ! empty( $reply_count ) ) { 2339 2340 // Get reply id's 2341 $topic_replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() ); 2342 if ( ! empty( $topic_replies ) ) { 2343 2344 // Reverse replies array and search for current reply position 2345 $topic_replies = array_reverse( $topic_replies ); 2346 $reply_position = array_search( (string) $reply_id, $topic_replies ); 2347 2348 // Bump the position to compensate for the lead topic post 2349 $reply_position++; 2350 } 2351 } 2352 } 2353 2354 return (int) $reply_position; 2355 } 2356 2357 /** Hierarchical Replies ******************************************************/ 2358 2359 /** 2360 * Are replies threaded? 2361 * 2362 * @since 2.4.0 bbPress (r4944) 2363 * @since 2.6.0 bbPress (r6245) Always false on user profile reply pages 2364 * 2365 * @param bool $default Optional. Default value true 2366 * 2367 * @return bool Are replies threaded? 2368 */ 2369 function bbp_thread_replies() { 2370 $depth = bbp_thread_replies_depth(); 2371 $allow = bbp_allow_threaded_replies(); 2372 2373 // Never thread replies on user profile pages. It looks weird, and we know 2374 // it is undesirable for the majority of installations. 2375 if ( bbp_is_single_user_replies() ) { 2376 $retval = false; 2377 } else { 2378 $retval = (bool) ( ( $depth >= 2 ) && ( true === $allow ) ); 2379 } 2380 2381 // Filter & return 2382 return (bool) apply_filters( 'bbp_thread_replies', $retval, $depth, $allow ); 2383 } 2384 2385 /** 2386 * List threaded replies 2387 * 2388 * @since 2.4.0 bbPress (r4944) 2389 */ 2390 function bbp_list_replies( $args = array() ) { 2391 2392 // Get bbPress 2393 $bbp = bbpress(); 2394 2395 // Reset the reply depth 2396 $bbp->reply_query->reply_depth = 0; 2397 2398 // In reply loop 2399 $bbp->reply_query->in_the_loop = true; 2400 2401 // Parse arguments 2402 $r = bbp_parse_args( $args, array( 2403 'walker' => new BBP_Walker_Reply(), 2404 'max_depth' => bbp_thread_replies_depth(), 2405 'style' => 'ul', 2406 'callback' => null, 2407 'end_callback' => null, 2408 'page' => 1, 2409 'per_page' => -1 2410 ), 'list_replies' ); 2411 2412 // Get replies to loop through in $_replies 2413 echo '<ul>' . $r['walker']->paged_walk( $bbp->reply_query->posts, $r['max_depth'], $r['page'], $r['per_page'], $r ) . '</ul>'; 2414 2415 $bbp->max_num_pages = $r['walker']->max_pages; 2416 $bbp->reply_query->in_the_loop = false; 2417 } 2418 2419 /** 2420 * Validate a `reply_to` field for hierarchical replies 2421 * 2422 * Checks for 2 scenarios: 2423 * -- The reply to ID is actually a reply 2424 * -- The reply to ID does not match the current reply 2425 * 2426 * @see https://bbpress.trac.wordpress.org/ticket/2588 2427 * @see https://bbpress.trac.wordpress.org/ticket/2586 2428 * 2429 * @since 2.5.4 bbPress (r5377) 2430 * 2431 * @param int $reply_to 2432 * @param int $reply_id 2433 * 2434 * @return int $reply_to 2435 */ 2436 function bbp_validate_reply_to( $reply_to = 0, $reply_id = 0 ) { 2437 2438 // The parent reply must actually be a reply 2439 if ( ! bbp_is_reply( $reply_to ) ) { 2440 $reply_to = 0; 2441 } 2442 2443 // The parent reply cannot be itself 2444 if ( $reply_id === $reply_to ) { 2445 $reply_to = 0; 2446 } 2447 2448 return (int) $reply_to; 2449 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sat Jan 16 01:01:25 2021 | Cross-referenced by PHPXref 0.7.1 |