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