/includes/replies/functions.php

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