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