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