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/forums/functions.php +2221 -911 2.2.12.6.17 View file →
@@ -7,9 +7,9 @@
7 7 * @subpackage Functions
8 8 */
9 9
10 10 // Exit if accessed directly
11 -if ( !defined( 'ABSPATH' ) ) exit;
11 +defined( 'ABSPATH' ) || exit;
12 12
13 13 /** Insert ********************************************************************/
14 14
15 15 /**
@@ -15,61 +15,106 @@
15 15 /**
16 16 * A wrapper for wp_insert_post() that also includes the necessary meta values
17 17 * for the forum 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_forum_post_type()
23 - * @uses wp_insert_post()
24 - * @uses update_post_meta()
25 - *
26 21 * @param array $forum_data Forum post data
27 - * @param arrap $forum_meta Forum meta data
22 + * @param array $forum_meta Forum meta data
28 23 */
29 24 function bbp_insert_forum( $forum_data = array(), $forum_meta = array() ) {
30 25
31 26 // Forum
32 - $default_forum = array(
33 - 'post_parent' => 0, // forum ID
34 - 'post_status' => bbp_get_public_status_id(),
35 - 'post_type' => bbp_get_forum_post_type(),
36 - 'post_author' => bbp_get_current_user_id(),
37 - 'post_password' => '',
38 - 'post_content' => '',
39 - 'post_title' => '',
40 - 'menu_order' => 0,
41 - 'comment_status' => 'closed'
27 + $forum_data = bbp_parse_args(
28 + $forum_data,
29 + array(
30 + 'post_parent' => 0, // forum ID
31 + 'post_status' => bbp_get_public_status_id(),
32 + 'post_type' => bbp_get_forum_post_type(),
33 + 'post_author' => bbp_get_current_user_id(),
34 + 'post_password' => '',
35 + 'post_content' => '',
36 + 'post_title' => '',
37 + 'menu_order' => 0,
38 + 'comment_status' => 'closed'
39 + ),
40 + 'insert_forum'
42 41 );
43 - $forum_data = bbp_parse_args( $forum_data, $default_forum, 'insert_forum' );
44 42
45 43 // Insert forum
46 - $forum_id = wp_insert_post( $forum_data );
44 + $forum_id = wp_insert_post( $forum_data, false );
47 45
48 46 // Bail if no forum was added
49 - if ( empty( $forum_id ) )
47 + if ( empty( $forum_id ) ) {
50 48 return false;
49 + }
51 50
52 51 // Forum meta
53 - $default_meta = array(
54 - 'reply_count' => 0,
55 - 'topic_count' => 0,
56 - 'topic_count_hidden' => 0,
57 - 'total_reply_count' => 0,
58 - 'total_topic_count' => 0,
59 - 'last_topic_id' => 0,
60 - 'last_reply_id' => 0,
61 - 'last_active_id' => 0,
62 - 'last_active_time' => 0,
63 - 'forum_subforum_count' => 0,
52 + $forum_meta = bbp_parse_args(
53 + $forum_meta,
54 + array(
55 + 'forum_type' => 'forum',
56 + 'status' => 'open',
57 + 'reply_count' => 0,
58 + 'topic_count' => 0,
59 + 'topic_count_hidden' => 0,
60 + 'total_reply_count' => 0,
61 + 'total_topic_count' => 0,
62 + 'last_topic_id' => 0,
63 + 'last_reply_id' => 0,
64 + 'last_active_id' => 0,
65 + 'last_active_time' => 0,
66 + 'forum_subforum_count' => 0,
67 + ),
68 + 'insert_forum_meta'
64 69 );
65 - $forum_meta = bbp_parse_args( $forum_meta, $default_meta, 'insert_forum_meta' );
66 70
67 71 // Insert forum meta
68 - foreach ( $forum_meta as $meta_key => $meta_value )
69 - update_post_meta( $forum_id, '_bbp_' . $meta_key, $meta_value );
72 + foreach ( $forum_meta as $meta_key => $meta_value ) {
70 73
71 - // Return new forum ID
74 + // Prefix if not prefixed
75 + if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
76 + $meta_key = '_bbp_' . $meta_key;
77 + }
78 +
79 + // Update the meta
80 + update_post_meta( $forum_id, $meta_key, $meta_value );
81 + }
82 +
83 + // Update the forum and hierarchy
84 + bbp_update_forum(
85 + array(
86 + 'forum_id' => $forum_id,
87 + 'post_parent' => $forum_data['post_parent']
88 + )
89 + );
90 +
91 + // Maybe make private
92 + if ( bbp_is_forum_private( $forum_id, false ) ) {
93 + bbp_privatize_forum( $forum_id );
94 +
95 + // Maybe make hidden
96 + } elseif ( bbp_is_forum_hidden( $forum_id, false ) ) {
97 + bbp_hide_forum( $forum_id );
98 +
99 + // Publicize
100 + } else {
101 + bbp_publicize_forum( $forum_id );
102 + }
103 +
104 + /**
105 + * Fires after forum has been inserted via `bbp_insert_forum`.
106 + *
107 + * @since 2.6.0 bbPress (r6036)
108 + *
109 + * @param int $forum_id The forum id.
110 + */
111 + do_action( 'bbp_insert_forum', (int) $forum_id );
112 +
113 + // Bump the last changed cache
114 + wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
115 +
116 + // Return forum_id
72 117 return $forum_id;
73 118 }
74 119
75 120 /** Post Form Handlers ********************************************************/
@@ -76,63 +121,34 @@
76 121
77 122 /**
78 123 * Handles the front end forum submission
79 124 *
80 - * @uses bbPress:errors::add() To log various error messages
81 - * @uses bbp_verify_nonce_request() To verify the nonce and check the request
82 - * @uses bbp_is_anonymous() To check if an anonymous post is being made
83 - * @uses current_user_can() To check if the current user can publish forum
84 - * @uses bbp_get_current_user_id() To get the current user id
85 - * @uses bbp_filter_anonymous_post_data() To filter anonymous data
86 - * @uses bbp_set_current_anonymous_user_data() To set the anonymous user cookies
87 - * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
88 - * @uses esc_attr() For sanitization
89 - * @uses bbp_is_forum_category() To check if the forum is a category
90 - * @uses bbp_is_forum_closed() To check if the forum is closed
91 - * @uses bbp_is_forum_private() To check if the forum is private
92 - * @uses bbp_check_for_flood() To check for flooding
93 - * @uses bbp_check_for_duplicate() To check for duplicates
94 - * @uses bbp_get_forum_post_type() To get the forum post type
95 - * @uses remove_filter() To remove 'wp_filter_kses' filters if needed
96 - * @uses apply_filters() Calls 'bbp_new_forum_pre_title' with the content
97 - * @uses apply_filters() Calls 'bbp_new_forum_pre_content' with the content
98 - * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
99 - * @uses wp_insert_post() To insert the forum
100 - * @uses do_action() Calls 'bbp_new_forum' with the forum id, forum id,
101 - * anonymous data and reply author
102 - * @uses bbp_stick_forum() To stick or super stick the forum
103 - * @uses bbp_unstick_forum() To unstick the forum
104 - * @uses bbp_get_forum_permalink() To get the forum permalink
105 - * @uses wp_safe_redirect() To redirect to the forum link
106 - * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
107 - * messages
125 + * @param string $action The requested action to compare this function to
108 126 */
109 -function bbp_new_forum_handler() {
127 +function bbp_new_forum_handler( $action = '' ) {
110 128
111 - // Bail if not a POST action
112 - if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
113 - return;
114 -
115 129 // Bail if action is not bbp-new-forum
116 - if ( empty( $_POST['action'] ) || ( 'bbp-new-forum' !== $_POST['action'] ) )
130 + if ( 'bbp-new-forum' !== $action ) {
117 131 return;
132 + }
118 133
119 134 // Nonce check
120 135 if ( ! bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
121 - bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
136 + bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
122 137 return;
123 138 }
124 139
125 140 // Define local variable(s)
126 - $view_all = $anonymous_data = false;
141 + $view_all = false;
127 142 $forum_parent_id = $forum_author = 0;
128 143 $forum_title = $forum_content = '';
144 + $anonymous_data = array();
129 145
130 146 /** Forum Author **********************************************************/
131 147
132 148 // User cannot create forums
133 - if ( !current_user_can( 'publish_forums' ) ) {
134 - bbp_add_error( 'bbp_forum_permissions', __( '<strong>ERROR</strong>: You do not have permission to create new forums.', 'bbpress' ) );
149 + if ( ! current_user_can( 'publish_forums' ) ) {
150 + bbp_add_error( 'bbp_forum_permission', __( '<strong>Error</strong>: You do not have permission to create new forums.', 'bbpress' ) );
135 151 return;
136 152 }
137 153
138 154 // Forum author is current user
@@ -137,130 +153,160 @@
137 153
138 154 // Forum author is current user
139 155 $forum_author = bbp_get_current_user_id();
140 156
141 - // Remove wp_filter_kses filters from title and content for capable users and if the nonce is verified
142 - if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) == $_POST['_bbp_unfiltered_html_forum'] ) {
143 - remove_filter( 'bbp_new_forum_pre_title', 'wp_filter_kses' );
144 - remove_filter( 'bbp_new_forum_pre_content', 'wp_filter_kses' );
157 + // Remove kses filters from title and content for capable users and if the nonce is verified
158 + if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) === $_POST['_bbp_unfiltered_html_forum'] ) {
159 + remove_filter( 'bbp_new_forum_pre_title', 'wp_filter_kses' );
160 + remove_filter( 'bbp_new_forum_pre_content', 'bbp_encode_bad', 10 );
161 + remove_filter( 'bbp_new_forum_pre_content', 'bbp_filter_kses', 30 );
145 162 }
146 163
147 164 /** Forum Title ***********************************************************/
148 165
149 - if ( !empty( $_POST['bbp_forum_title'] ) )
150 - $forum_title = esc_attr( strip_tags( $_POST['bbp_forum_title'] ) );
166 + if ( ! empty( $_POST['bbp_forum_title'] ) ) {
167 + $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
168 + }
151 169
152 170 // Filter and sanitize
153 171 $forum_title = apply_filters( 'bbp_new_forum_pre_title', $forum_title );
154 172
155 173 // No forum title
156 - if ( empty( $forum_title ) )
157 - bbp_add_error( 'bbp_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
174 + if ( empty( $forum_title ) ) {
175 + bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
176 + }
158 177
178 + // Title too long
179 + if ( bbp_is_title_too_long( $forum_title ) ) {
180 + bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
181 + }
182 +
159 183 /** Forum Content *********************************************************/
160 184
161 - if ( !empty( $_POST['bbp_forum_content'] ) )
185 + if ( ! empty( $_POST['bbp_forum_content'] ) ) {
162 186 $forum_content = $_POST['bbp_forum_content'];
187 + }
163 188
164 189 // Filter and sanitize
165 190 $forum_content = apply_filters( 'bbp_new_forum_pre_content', $forum_content );
166 191
167 192 // No forum content
168 - if ( empty( $forum_content ) )
169 - bbp_add_error( 'bbp_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
193 + if ( empty( $forum_content ) ) {
194 + bbp_add_error( 'bbp_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
195 + }
170 196
171 197 /** Forum Parent **********************************************************/
172 198
173 199 // Forum parent was passed (the norm)
174 - if ( !empty( $_POST['bbp_forum_parent_id'] ) )
175 - $forum_parent_id = (int) $_POST['bbp_forum_parent_id'];
176 -
200 + if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
201 + $forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
202 + }
203 +
177 204 // Filter and sanitize
178 205 $forum_parent_id = apply_filters( 'bbp_new_forum_pre_parent_id', $forum_parent_id );
179 206
180 207 // No forum parent was passed (should never happen)
181 208 if ( empty( $forum_parent_id ) ) {
182 - bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>ERROR</strong>: Your forum must have a parent.', 'bbpress' ) );
209 + bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>Error</strong>: Your forum must have a parent.', 'bbpress' ) );
183 210
184 211 // Forum exists
185 - } elseif ( !empty( $forum_parent_id ) ) {
212 + } elseif ( ! empty( $forum_parent_id ) ) {
186 213
187 214 // Forum is a category
188 215 if ( bbp_is_forum_category( $forum_parent_id ) ) {
189 - bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
216 + bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>Error</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
190 217 }
191 218
192 219 // Forum is closed and user cannot access
193 - if ( bbp_is_forum_closed( $forum_parent_id ) && !current_user_can( 'edit_forum', $forum_parent_id ) ) {
194 - bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
220 + if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
221 + bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
195 222 }
196 223
197 224 // Forum is private and user cannot access
198 - if ( bbp_is_forum_private( $forum_parent_id ) && !current_user_can( 'read_private_forums' ) ) {
199 - bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
225 + if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
226 + bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
200 227 }
201 228
202 229 // Forum is hidden and user cannot access
203 - if ( bbp_is_forum_hidden( $forum_parent_id ) && !current_user_can( 'read_hidden_forums' ) ) {
204 - bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
205 - }
230 + if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
231 + bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
232 + }
206 233 }
207 234
208 235 /** Forum Flooding ********************************************************/
209 236
210 - if ( !bbp_check_for_flood( $anonymous_data, $forum_author ) )
211 - bbp_add_error( 'bbp_forum_flood', __( '<strong>ERROR</strong>: Slow down; you move too fast.', 'bbpress' ) );
237 + if ( ! bbp_check_for_flood( $anonymous_data, $forum_author ) ) {
238 + bbp_add_error( 'bbp_forum_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
239 + }
212 240
213 241 /** Forum Duplicate *******************************************************/
214 242
215 - if ( !bbp_check_for_duplicate( array( 'post_type' => bbp_get_forum_post_type(), 'post_author' => $forum_author, 'post_content' => $forum_content, 'anonymous_data' => $anonymous_data ) ) )
216 - bbp_add_error( 'bbp_forum_duplicate', __( '<strong>ERROR</strong>: This forum already exists.', 'bbpress' ) );
243 + $dupe_args = array(
244 + 'post_type' => bbp_get_forum_post_type(),
245 + 'post_author' => $forum_author,
246 + 'post_content' => $forum_content,
247 + 'post_parent' => $forum_parent_id,
248 + 'anonymous_data' => $anonymous_data
249 + );
217 250
218 - /** Forum Blacklist *******************************************************/
251 + if ( ! bbp_check_for_duplicate( $dupe_args ) ) {
252 + bbp_add_error( 'bbp_forum_duplicate', __( '<strong>Error</strong>: This forum already exists.', 'bbpress' ) );
253 + }
219 254
220 - if ( !bbp_check_for_blacklist( $anonymous_data, $forum_author, $forum_title, $forum_content ) )
221 - bbp_add_error( 'bbp_forum_blacklist', __( '<strong>ERROR</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
255 + /** Forum Bad Words *******************************************************/
222 256
257 + if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content, true ) ) {
258 + bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
259 + }
260 +
223 261 /** Forum Moderation ******************************************************/
224 262
225 - $post_status = bbp_get_public_status_id();
226 - if ( !bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) )
227 - $post_status = bbp_get_pending_status_id();
263 + // Default to published
264 + $forum_status = bbp_get_public_status_id();
228 265
266 + // Maybe force into pending
267 + if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) ) {
268 + $forum_status = bbp_get_pending_status_id();
269 + }
270 +
229 271 /** Additional Actions (Before Save) **************************************/
230 272
231 273 do_action( 'bbp_new_forum_pre_extras', $forum_parent_id );
232 274
233 275 // Bail if errors
234 - if ( bbp_has_errors() )
276 + if ( bbp_has_errors() ) {
235 277 return;
278 + }
236 279
237 280 /** No Errors *************************************************************/
238 281
239 282 // Add the content of the form to $forum_data as an array
240 283 // Just in time manipulation of forum data before being created
241 - $forum_data = apply_filters( 'bbp_new_forum_pre_insert', array(
242 - 'post_author' => $forum_author,
243 - 'post_title' => $forum_title,
244 - 'post_content' => $forum_content,
245 - 'post_parent' => $forum_parent_id,
246 - 'post_status' => $post_status,
247 - 'post_type' => bbp_get_forum_post_type(),
248 - 'comment_status' => 'closed'
249 - ) );
284 + $forum_data = apply_filters(
285 + 'bbp_new_forum_pre_insert',
286 + array(
287 + 'post_author' => $forum_author,
288 + 'post_title' => $forum_title,
289 + 'post_content' => $forum_content,
290 + 'post_parent' => $forum_parent_id,
291 + 'post_status' => $forum_status,
292 + 'post_type' => bbp_get_forum_post_type(),
293 + 'comment_status' => 'closed'
294 + )
295 + );
250 296
251 297 // Insert forum
252 - $forum_id = wp_insert_post( $forum_data );
298 + $forum_id = wp_insert_post( $forum_data, true );
253 299
254 300 /** No Errors *************************************************************/
255 301
256 - if ( !empty( $forum_id ) && !is_wp_error( $forum_id ) ) {
302 + if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
257 303
258 304 /** Trash Check *******************************************************/
259 305
260 306 // If the forum is trash, or the forum_status is switched to
261 307 // trash, trash it properly
262 - if ( ( get_post_field( 'post_status', $forum_id ) == bbp_get_trash_status_id() ) || ( $forum_data['post_status'] == bbp_get_trash_status_id() ) ) {
308 + if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( bbp_get_trash_status_id() === $forum_data['post_status'] ) ) {
263 309
264 310 // Trash the reply
265 311 wp_trash_post( $forum_id );
266 312
@@ -270,9 +316,9 @@
270 316
271 317 /** Spam Check ********************************************************/
272 318
273 319 // If reply or forum are spam, officially spam this reply
274 - if ( $forum_data['post_status'] == bbp_get_spam_status_id() ) {
320 + if ( bbp_get_spam_status_id() === $forum_data['post_status'] ) {
275 321 add_post_meta( $forum_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
276 322
277 323 // Force view=all
278 324 $view_all = true;
@@ -279,19 +325,21 @@
279 325 }
280 326
281 327 /** Update counts, etc... *********************************************/
282 328
283 - $forum_args = array(
284 - 'forum_id' => $forum_id,
285 - 'post_parent' => $forum_parent_id,
286 - 'forum_author' => $forum_author,
287 - 'last_topic_id' => 0,
288 - 'last_reply_id' => 0,
289 - 'last_active_id' => 0,
290 - 'last_active_time' => 0,
291 - 'last_active_status' => bbp_get_public_status_id()
329 + do_action(
330 + 'bbp_new_forum',
331 + array(
332 + 'forum_id' => $forum_id,
333 + 'post_parent' => $forum_data['post_parent'],
334 + 'forum_author' => $forum_data['post_author'],
335 + 'last_topic_id' => 0,
336 + 'last_reply_id' => 0,
337 + 'last_active_id' => 0,
338 + 'last_active_time' => 0,
339 + 'last_active_status' => bbp_get_public_status_id()
340 + )
292 341 );
293 - do_action( 'bbp_new_forum', $forum_args );
294 342
295 343 /** Additional Actions (After Save) ***********************************/
296 344
297 345 do_action( 'bbp_new_forum_post_extras', $forum_id );
@@ -298,18 +346,18 @@
298 346
299 347 /** Redirect **********************************************************/
300 348
301 349 // Redirect to
302 - $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
350 + $redirect_to = bbp_get_redirect_to();
303 351
304 352 // Get the forum URL
305 353 $redirect_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
306 354
307 355 // Add view all?
308 - if ( bbp_get_view_all() || !empty( $view_all ) ) {
356 + if ( bbp_get_view_all() || ! empty( $view_all ) ) {
309 357
310 358 // User can moderate, so redirect to forum with view all set
311 - if ( current_user_can( 'moderate' ) ) {
359 + if ( current_user_can( 'moderate', $forum_id ) ) {
312 360 $redirect_url = bbp_add_view_all( $redirect_url );
313 361
314 362 // User cannot moderate, so redirect to forum
315 363 } else {
@@ -322,65 +370,43 @@
322 370
323 371 /** Successful Save ***************************************************/
324 372
325 373 // Redirect back to new forum
326 - wp_safe_redirect( $redirect_url );
374 + bbp_redirect( $redirect_url );
327 375
328 - // For good measure
329 - exit();
376 + /** Errors ****************************************************************/
330 377
331 - // Errors
378 + // WP_Error
379 +
380 + } elseif ( is_wp_error( $forum_id ) ) {
381 + bbp_add_error(
382 + 'bbp_forum_error',
383 + sprintf( /* translators: %s: Error message(s) */ __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ),
384 + $forum_id->get_error_message()
385 + )
386 + );
387 +
388 + // Generic error
332 389 } else {
333 - $append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
334 - bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your forum:' . $append_error, 'bbpress' ) );
335 - }
390 + bbp_add_error( 'bbp_forum_error', __( '<strong>Error</strong>: The forum was not created.', 'bbpress' ) );
391 + }
336 392 }
337 393
338 394 /**
339 395 * Handles the front end edit forum submission
340 396 *
341 - * @uses bbPress:errors::add() To log various error messages
342 - * @uses bbp_get_forum() To get the forum
343 - * @uses bbp_verify_nonce_request() To verify the nonce and check the request
344 - * @uses bbp_is_forum_anonymous() To check if forum is by an anonymous user
345 - * @uses current_user_can() To check if the current user can edit the forum
346 - * @uses bbp_filter_anonymous_post_data() To filter anonymous data
347 - * @uses is_wp_error() To check if the value retrieved is a {@link WP_Error}
348 - * @uses esc_attr() For sanitization
349 - * @uses bbp_is_forum_category() To check if the forum is a category
350 - * @uses bbp_is_forum_closed() To check if the forum is closed
351 - * @uses bbp_is_forum_private() To check if the forum is private
352 - * @uses remove_filter() To remove 'wp_filter_kses' filters if needed
353 - * @uses apply_filters() Calls 'bbp_edit_forum_pre_title' with the title and
354 - * forum id
355 - * @uses apply_filters() Calls 'bbp_edit_forum_pre_content' with the content
356 - * and forum id
357 - * @uses bbPress::errors::get_error_codes() To get the {@link WP_Error} errors
358 - * @uses wp_save_post_revision() To save a forum revision
359 - * @uses bbp_update_forum_revision_log() To update the forum revision log
360 - * @uses wp_update_post() To update the forum
361 - * @uses do_action() Calls 'bbp_edit_forum' with the forum id, forum id,
362 - * anonymous data and reply author
363 - * @uses bbp_move_forum_handler() To handle movement of a forum from one forum
364 - * to another
365 - * @uses bbp_get_forum_permalink() To get the forum permalink
366 - * @uses wp_safe_redirect() To redirect to the forum link
367 - * @uses bbPress::errors::get_error_messages() To get the {@link WP_Error} error
368 - * messages
397 + * @param string $action The requested action to compare this function to
369 398 */
370 -function bbp_edit_forum_handler() {
399 +function bbp_edit_forum_handler( $action = '' ) {
371 400
372 - // Bail if not a POST action
373 - if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) )
374 - return;
375 -
376 401 // Bail if action is not bbp-edit-forum
377 - if ( empty( $_POST['action'] ) || ( 'bbp-edit-forum' !== $_POST['action'] ) )
402 + if ( 'bbp-edit-forum' !== $action ) {
378 403 return;
404 + }
379 405
380 406 // Define local variable(s)
381 407 $anonymous_data = array();
382 - $forum = $forum_id = $forum_parent_id = 0;
408 + $forum = $forum_id = $forum_author = $forum_parent_id = 0;
383 409 $forum_title = $forum_content = $forum_edit_reason = '';
384 410
385 411 /** Forum *****************************************************************/
386 412
@@ -385,9 +411,9 @@
385 411 /** Forum *****************************************************************/
386 412
387 413 // Forum id was not passed
388 414 if ( empty( $_POST['bbp_forum_id'] ) ) {
389 - bbp_add_error( 'bbp_edit_forum_id', __( '<strong>ERROR</strong>: Forum ID not found.', 'bbpress' ) );
415 + bbp_add_error( 'bbp_edit_forum_id', __( '<strong>Error</strong>: Forum ID not found.', 'bbpress' ) );
390 416 return;
391 417
392 418 // Forum id was passed
393 419 } elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
@@ -396,158 +422,193 @@
396 422 }
397 423
398 424 // Nonce check
399 425 if ( ! bbp_verify_nonce_request( 'bbp-edit-forum_' . $forum_id ) ) {
400 - bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
426 + bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
401 427 return;
402 428
403 429 // Forum does not exist
404 430 } elseif ( empty( $forum ) ) {
405 - bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>ERROR</strong>: The forum you want to edit was not found.', 'bbpress' ) );
431 + bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>Error</strong>: The forum you want to edit was not found.', 'bbpress' ) );
406 432 return;
407 433
408 434 // User cannot edit this forum
409 - } elseif ( !current_user_can( 'edit_forum', $forum_id ) ) {
410 - bbp_add_error( 'bbp_edit_forum_permissions', __( '<strong>ERROR</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
435 + } elseif ( ! current_user_can( 'edit_forum', $forum_id ) ) {
436 + bbp_add_error( 'bbp_edit_forum_permission', __( '<strong>Error</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
411 437 return;
412 438 }
413 439
414 - // Remove wp_filter_kses filters from title and content for capable users and if the nonce is verified
415 - if ( current_user_can( 'unfiltered_html' ) && !empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) == $_POST['_bbp_unfiltered_html_forum'] ) ) {
416 - remove_filter( 'bbp_edit_forum_pre_title', 'wp_filter_kses' );
417 - remove_filter( 'bbp_edit_forum_pre_content', 'wp_filter_kses' );
440 + // Remove kses filters from title and content for capable users and if the nonce is verified
441 + if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) === $_POST['_bbp_unfiltered_html_forum'] ) ) {
442 + remove_filter( 'bbp_edit_forum_pre_title', 'wp_filter_kses' );
443 + remove_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad', 10 );
444 + remove_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
418 445 }
419 446
447 + // Get forum author
448 + $forum_author = bbp_get_forum_author_id( $forum_id );
449 +
420 450 /** Forum Parent ***********************************************************/
421 451
422 - // Forum parent id was passed
423 - if ( is_numeric( $_POST['bbp_forum_parent_id'] ) ) {
424 - $forum_parent_id = (int) $_POST['bbp_forum_parent_id'];
425 - }
426 -
427 452 // Current forum this forum is in
428 453 $current_parent_forum_id = bbp_get_forum_parent_id( $forum_id );
429 454
455 + // Only users who can assign forum moderators can change forum structure
456 + if ( current_user_can( 'assign_moderators' ) ) {
457 + $forum_parent_id = ! empty( $_POST['bbp_forum_parent_id'] )
458 + ? bbp_get_forum_id( $_POST['bbp_forum_parent_id'] )
459 + : 0;
460 + } else {
461 + $forum_parent_id = $current_parent_forum_id;
462 + }
463 +
430 464 // Forum exists
431 - if ( !empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {
465 + if ( ! empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {
432 466
433 467 // Forum is closed and user cannot access
434 - if ( bbp_is_forum_closed( $forum_parent_id ) && !current_user_can( 'edit_forum', $forum_parent_id ) ) {
435 - bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
468 + if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
469 + bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
436 470 }
437 471
438 472 // Forum is private and user cannot access
439 - if ( bbp_is_forum_private( $forum_parent_id ) && !current_user_can( 'read_private_forums' ) ) {
440 - bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
473 + if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
474 + bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
441 475 }
442 476
443 477 // Forum is hidden and user cannot access
444 - if ( bbp_is_forum_hidden( $forum_parent_id ) && !current_user_can( 'read_hidden_forums' ) ) {
445 - bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
478 + if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
479 + bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
446 480 }
447 481 }
448 482
449 483 /** Forum Title ***********************************************************/
450 484
451 - if ( !empty( $_POST['bbp_forum_title'] ) )
452 - $forum_title = esc_attr( strip_tags( $_POST['bbp_forum_title'] ) );
485 + if ( ! empty( $_POST['bbp_forum_title'] ) ) {
486 + $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
487 + }
453 488
454 489 // Filter and sanitize
455 490 $forum_title = apply_filters( 'bbp_edit_forum_pre_title', $forum_title, $forum_id );
456 491
457 492 // No forum title
458 - if ( empty( $forum_title ) )
459 - bbp_add_error( 'bbp_edit_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
493 + if ( empty( $forum_title ) ) {
494 + bbp_add_error( 'bbp_edit_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
495 + }
460 496
497 + // Title too long
498 + if ( bbp_is_title_too_long( $forum_title ) ) {
499 + bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
500 + }
501 +
461 502 /** Forum Content *********************************************************/
462 503
463 - if ( !empty( $_POST['bbp_forum_content'] ) )
504 + if ( ! empty( $_POST['bbp_forum_content'] ) ) {
464 505 $forum_content = $_POST['bbp_forum_content'];
506 + }
465 507
466 508 // Filter and sanitize
467 509 $forum_content = apply_filters( 'bbp_edit_forum_pre_content', $forum_content, $forum_id );
468 510
469 511 // No forum content
470 - if ( empty( $forum_content ) )
471 - bbp_add_error( 'bbp_edit_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
512 + if ( empty( $forum_content ) ) {
513 + bbp_add_error( 'bbp_edit_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
514 + }
472 515
473 - /** Forum Blacklist *******************************************************/
516 + /** Forum Bad Words *******************************************************/
474 517
475 - if ( !bbp_check_for_blacklist( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) )
476 - bbp_add_error( 'bbp_forum_blacklist', __( '<strong>ERROR</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
518 + if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content, true ) ) {
519 + bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
520 + }
477 521
478 522 /** Forum Moderation ******************************************************/
479 523
480 - $post_status = bbp_get_public_status_id();
481 - if ( !bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) )
482 - $post_status = bbp_get_pending_status_id();
524 + // Use existing post_status
525 + $forum_status = $forum->post_status;
483 526
527 + // Maybe force into pending
528 + if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) ) {
529 + $forum_status = bbp_get_pending_status_id();
530 + }
531 +
484 532 /** Additional Actions (Before Save) **************************************/
485 533
486 534 do_action( 'bbp_edit_forum_pre_extras', $forum_id );
487 535
488 536 // Bail if errors
489 - if ( bbp_has_errors() )
537 + if ( bbp_has_errors() ) {
490 538 return;
539 + }
491 540
492 541 /** No Errors *************************************************************/
493 542
494 543 // Add the content of the form to $forum_data as an array
495 544 // Just in time manipulation of forum data before being edited
496 - $forum_data = apply_filters( 'bbp_edit_forum_pre_insert', array(
497 - 'ID' => $forum_id,
498 - 'post_title' => $forum_title,
499 - 'post_content' => $forum_content,
500 - 'post_status' => $post_status,
501 - 'post_parent' => $forum_parent_id
502 - ) );
545 + $forum_data = apply_filters(
546 + 'bbp_edit_forum_pre_insert',
547 + array(
548 + 'ID' => $forum_id,
549 + 'post_title' => $forum_title,
550 + 'post_content' => $forum_content,
551 + 'post_status' => $forum_status,
552 + 'post_parent' => $forum_parent_id,
553 + 'post_author' => $forum_author
554 + )
555 + );
503 556
504 557 // Insert forum
505 558 $forum_id = wp_update_post( $forum_data );
506 559
507 - /** Revisions *************************************************************/
560 + /** No Errors *************************************************************/
508 561
509 - /**
510 - * @todo omitted for 2.1
511 - // Revision Reason
512 - if ( !empty( $_POST['bbp_forum_edit_reason'] ) )
513 - $forum_edit_reason = esc_attr( strip_tags( $_POST['bbp_forum_edit_reason'] ) );
562 + if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
514 563
515 - // Update revision log
516 - if ( !empty( $_POST['bbp_log_forum_edit'] ) && ( 1 == $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
517 - bbp_update_forum_revision_log( array(
518 - 'forum_id' => $forum_id,
519 - 'revision_id' => $revision_id,
520 - 'author_id' => bbp_get_current_user_id(),
521 - 'reason' => $forum_edit_reason
522 - ) );
523 - }
524 - */
564 + // Update counts, etc...
565 + do_action(
566 + 'bbp_edit_forum',
567 + array(
568 + 'forum_id' => $forum_id,
569 + 'post_parent' => $forum_data['post_parent'],
570 + 'forum_author' => $forum_data['post_author'],
571 + 'last_topic_id' => 0,
572 + 'last_reply_id' => 0,
573 + 'last_active_id' => 0,
574 + 'last_active_time' => 0,
575 + 'last_active_status' => bbp_get_public_status_id()
576 + )
577 + );
525 578
526 - /** No Errors *************************************************************/
579 + /** Revisions *********************************************************/
527 580
528 - if ( !empty( $forum_id ) && !is_wp_error( $forum_id ) ) {
581 + // Update locks
582 + update_post_meta( $forum_id, '_edit_last', bbp_get_current_user_id() );
583 + delete_post_meta( $forum_id, '_edit_lock' );
529 584
530 - // Update counts, etc...
531 - $forum_args = array(
532 - 'forum_id' => $forum_id,
533 - 'post_parent' => $forum_parent_id,
534 - 'forum_author' => $forum->post_author,
535 - 'last_topic_id' => 0,
536 - 'last_reply_id' => 0,
537 - 'last_active_id' => 0,
538 - 'last_active_time' => 0,
539 - 'last_active_status' => bbp_get_public_status_id()
540 - );
541 - do_action( 'bbp_edit_forum', $forum_args );
585 + /**
586 + * @todo omitted for now
587 + // Revision Reason
588 + if ( ! empty( $_POST['bbp_forum_edit_reason'] ) )
589 + $forum_edit_reason = sanitize_text_field( $_POST['bbp_forum_edit_reason'] );
542 590
591 + // Update revision log
592 + if ( ! empty( $_POST['bbp_log_forum_edit'] ) && ( "1" === $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
593 + bbp_update_forum_revision_log( array(
594 + 'forum_id' => $forum_id,
595 + 'revision_id' => $revision_id,
596 + 'author_id' => bbp_get_current_user_id(),
597 + 'reason' => $forum_edit_reason
598 + ) );
599 + }
600 +
543 601 // If the new forum parent id is not equal to the old forum parent
544 602 // id, run the bbp_move_forum action and pass the forum's parent id
545 - // as the first arg and new forum parent id as the second.
603 + // as the first argument and new forum parent id as the second.
546 604 // @todo implement
547 - //if ( $forum_id != $forum->post_parent )
548 - // bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
605 + if ( $forum_id !== $forum->post_parent ) {
606 + bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
607 + }
549 608
609 + */
610 +
550 611 /** Additional Actions (After Save) ***********************************/
551 612
552 613 do_action( 'bbp_edit_forum_post_extras', $forum_id );
553 614
@@ -553,9 +614,9 @@
553 614
554 615 /** Redirect **********************************************************/
555 616
556 617 // Redirect to
557 - $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
618 + $redirect_to = bbp_get_redirect_to();
558 619
559 620 // View all?
560 621 $view_all = bbp_get_view_all();
561 622
@@ -562,10 +623,11 @@
562 623 // Get the forum URL
563 624 $forum_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
564 625
565 626 // Add view all?
566 - if ( !empty( $view_all ) )
627 + if ( ! empty( $view_all ) ) {
567 628 $forum_url = bbp_add_view_all( $forum_url );
629 + }
568 630
569 631 // Allow to be filtered
570 632 $forum_url = apply_filters( 'bbp_edit_forum_redirect_to', $forum_url, $view_all, $redirect_to );
571 633
@@ -571,39 +633,68 @@
571 633
572 634 /** Successful Edit ***************************************************/
573 635
574 636 // Redirect back to new forum
575 - wp_safe_redirect( $forum_url );
637 + bbp_redirect( $forum_url );
576 638
577 - // For good measure
578 - exit();
579 -
580 639 /** Errors ****************************************************************/
581 640
582 641 } else {
583 642 $append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
584 - bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your forum:' . $append_error . 'Please try again.', 'bbpress' ) );
643 + bbp_add_error(
644 + 'bbp_forum_error',
645 + sprintf(
646 + /* translators: %s: Error message */
647 + __( '<strong>Error</strong>: The following problem(s) have been found with your forum: %sPlease try again.', 'bbpress' ),
648 + $append_error
649 + )
650 + );
585 651 }
586 652 }
587 653
588 654 /**
655 + * Filter forum data submitted through the WordPress administration area.
656 + *
657 + * @since 2.6.17 bbPress
658 + *
659 + * @param array $data Sanitized post data.
660 + * @param array $postarr Raw post data.
661 + * @return array Filtered post data.
662 + */
663 +function bbp_filter_admin_forum_post_data( $data = array(), $postarr = array() ) {
664 +
665 + // Bail unless an existing forum is being updated in wp-admin
666 + if ( ! is_admin() || empty( $postarr['ID'] ) || empty( $data['post_type'] ) || ( bbp_get_forum_post_type() !== $data['post_type'] ) ) {
667 + return $data;
668 + }
669 +
670 + $forum_id = bbp_get_forum_id( $postarr['ID'] );
671 + $forum = bbp_get_forum( $forum_id );
672 +
673 + if ( empty( $forum ) ) {
674 + return $data;
675 + }
676 +
677 + // Preserve structure unless the user can assign forum moderators
678 + if ( ! current_user_can( 'assign_moderators' ) ) {
679 + $data['post_parent'] = $forum->post_parent;
680 + $data['menu_order'] = $forum->menu_order;
681 + }
682 +
683 + // Preserve visibility unless the user can manage forum attributes
684 + if ( ! current_user_can( 'manage_forum_attributes', $forum_id ) ) {
685 + $data['post_status'] = $forum->post_status;
686 + }
687 +
688 + return $data;
689 +}
690 +
691 +/**
589 692 * Handle the saving of core forum metadata (Status, Visibility, and Type)
590 693 *
591 - * @since bbPress (r3678)
694 + * @since 2.1.0 bbPress (r3678)
695 + *
592 696 * @param int $forum_id
593 - * @uses bbp_is_forum_closed() To check if forum is closed
594 - * @uses bbp_close_forum() To close forum
595 - * @uses bbp_open_forum() To open forum
596 - * @uses bbp_is_forum_category() To check if forum is a category
597 - * @uses bbp_categorize_forum() To turn forum into a category
598 - * @uses bbp_normalize_forum() To turn category into forum
599 - * @uses bbp_get_public_status_id() To get the public status ID
600 - * @uses bbp_get_private_status_id() To get the private status ID
601 - * @uses bbp_get_hidden_status_id() To get the hidden status ID
602 - * @uses bbp_get_forum_visibility() To get the forums visibility
603 - * @uses bbp_hide_forum() To hide a forum
604 - * @uses bbp_privatize_forum() To make a forum private
605 - * @uses bbp_publicize_forum() To make a forum public
606 697 * @return If forum ID is empty
607 698 */
608 699 function bbp_save_forum_extras( $forum_id = 0 ) {
609 700
@@ -610,90 +701,115 @@
610 701 // Validate the forum ID
611 702 $forum_id = bbp_get_forum_id( $forum_id );
612 703
613 704 // Bail if forum ID is empty
614 - if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) )
705 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
615 706 return;
707 + }
616 708
617 - /** Forum Status ******************************************************/
709 + /** Forum Status **********************************************************/
618 710
619 - if ( !empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ) ) ) {
620 - if ( 'closed' == $_POST['bbp_forum_status'] && !bbp_is_forum_closed( $forum_id, false ) ) {
711 + if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ), true ) ) {
712 + if ( 'closed' === $_POST['bbp_forum_status'] && ! bbp_is_forum_closed( $forum_id, false ) ) {
621 713 bbp_close_forum( $forum_id );
622 - } elseif ( 'open' == $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
714 + } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_open( $forum_id, false ) ) {
623 715 bbp_open_forum( $forum_id );
716 + } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
717 + bbp_open_forum( $forum_id );
624 718 }
625 719 }
626 720
627 - /** Forum Type ********************************************************/
721 + /** Forum Type ************************************************************/
628 722
629 - if ( !empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ) ) ) {
630 - if ( 'category' == $_POST['bbp_forum_type'] && !bbp_is_forum_category( $forum_id ) ) {
723 + if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ), true ) ) {
724 + if ( 'category' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
631 725 bbp_categorize_forum( $forum_id );
632 - } elseif ( 'forum' == $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
726 + } elseif ( 'forum' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
633 727 bbp_normalize_forum( $forum_id );
728 + } elseif ( 'forum' === $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
729 + bbp_normalize_forum( $forum_id );
634 730 }
635 731 }
636 732
637 - /** Forum Visibility **************************************************/
733 + /** Forum Visibility ******************************************************/
638 734
639 - if ( !empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array( bbp_get_public_status_id(), bbp_get_private_status_id(), bbp_get_hidden_status_id() ) ) ) {
735 + if ( current_user_can( 'manage_forum_attributes', $forum_id ) && ! empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array_keys( bbp_get_forum_visibilities() ), true ) ) {
640 736
641 737 // Get forums current visibility
642 - $visibility = bbp_get_forum_visibility( $forum_id );
738 + $old_visibility = bbp_get_forum_visibility( $forum_id );
643 739
740 + // Sanitize the new visibility
741 + $new_visibility = sanitize_key( $_POST['bbp_forum_visibility'] );
742 +
644 743 // What is the new forum visibility setting?
645 - switch ( $_POST['bbp_forum_visibility'] ) {
744 + switch ( $new_visibility ) {
646 745
647 746 // Hidden
648 747 case bbp_get_hidden_status_id() :
649 - bbp_hide_forum( $forum_id, $visibility );
748 + bbp_hide_forum( $forum_id, $old_visibility );
650 749 break;
651 750
652 751 // Private
653 752 case bbp_get_private_status_id() :
654 - bbp_privatize_forum( $forum_id, $visibility );
753 + bbp_privatize_forum( $forum_id, $old_visibility );
655 754 break;
656 755
657 756 // Publish (default)
658 757 case bbp_get_public_status_id() :
659 - default :
660 - bbp_publicize_forum( $forum_id, $visibility );
758 + default :
759 + bbp_publicize_forum( $forum_id, $old_visibility );
661 760 break;
662 761 }
762 +
763 + /**
764 + * Allow custom forum visibility save actions
765 + *
766 + * @since 2.6.0 bbPress (r5855)
767 + *
768 + * @param int $forum_id The forum ID
769 + * @param string $old_visibility The current forum visibility
770 + * @param string $new_visibility The new forum visibility
771 + */
772 + do_action( 'bbp_update_forum_visibility', $forum_id, $old_visibility, $new_visibility );
663 773 }
664 -}
665 774
666 -/** Walk **********************************************************************/
775 + /** Forum Moderators ******************************************************/
667 776
668 -/**
669 - * Walk the forum tree
670 - *
671 - * @param object $forums Forums
672 - * @param int $depth Depth
673 - * @param int $current Current forum
674 - * @param array $r Parsed arguments, supported by the walker. If you want to
675 - * use your own walker, pass the 'walker' arg with the walker.
676 - * The walker defaults to {@link BBP_Walker_Forum}
677 - * @return object Walked forum tree
678 - */
679 -function bbp_walk_forum( $forums, $depth, $current, $r ) {
680 - $walker = empty( $r['walker'] ) ? new BBP_Walker_Forum : $r['walker'];
681 - $args = array( $forums, $depth, $r, $current );
682 - return call_user_func_array( array( &$walker, 'walk' ), $args );
777 + // Either replace terms
778 + if ( bbp_allow_forum_mods() && current_user_can( 'assign_moderators' ) ) {
779 + if ( ! empty( $_POST['bbp_moderators'] ) ) {
780 +
781 + // Escape tag input
782 + $users = sanitize_text_field( $_POST['bbp_moderators'] );
783 + $user_ids = bbp_get_user_ids_from_nicenames( $users );
784 +
785 + // Update forum moderators
786 + if ( ! empty( $user_ids ) ) {
787 +
788 + // Remove all moderators
789 + bbp_remove_moderator( $forum_id, null );
790 +
791 + // Add moderators
792 + foreach ( $user_ids as $user_id ) {
793 + bbp_add_moderator( $forum_id, $user_id );
794 + }
795 + }
796 +
797 + // ...or remove them.
798 + } elseif ( isset( $_POST['bbp_moderators'] ) ) {
799 + bbp_remove_moderator( $forum_id, null );
800 + }
801 + }
683 802 }
684 803
685 -/** Forum Actions *************************************************************/
804 +/** Forum Open/Close **********************************************************/
686 805
687 806 /**
688 807 * Closes a forum
689 808 *
690 - * @since bbPress (r2746)
809 + * @since 2.0.0 bbPress (r2746)
691 810 *
692 811 * @param int $forum_id forum id
693 - * @uses do_action() Calls 'bbp_close_forum' with the forum id
694 - * @uses update_post_meta() To add the previous status to a meta
695 - * @uses do_action() Calls 'bbp_opened_forum' with the forum id
696 812 * @return mixed False or {@link WP_Error} on failure, forum id on success
697 813 */
698 814 function bbp_close_forum( $forum_id = 0 ) {
699 815
@@ -710,15 +826,11 @@
710 826
711 827 /**
712 828 * Opens a forum
713 829 *
714 - * @since bbPress (r2746)
830 + * @since 2.0.0 bbPress (r2746)
715 831 *
716 832 * @param int $forum_id forum id
717 - * @uses do_action() Calls 'bbp_open_forum' with the forum id
718 - * @uses get_post_meta() To get the previous status
719 - * @uses update_post_meta() To delete the previous status meta
720 - * @uses do_action() Calls 'bbp_opened_forum' with the forum id
721 833 * @return mixed False or {@link WP_Error} on failure, forum id on success
722 834 */
723 835 function bbp_open_forum( $forum_id = 0 ) {
724 836
@@ -732,15 +844,16 @@
732 844
733 845 return $forum_id;
734 846 }
735 847
848 +/** Forum Type ****************************************************************/
849 +
736 850 /**
737 851 * Make the forum a category
738 852 *
739 - * @since bbPress (r2746)
853 + * @since 2.0.0 bbPress (r2746)
740 854 *
741 855 * @param int $forum_id Optional. Forum id
742 - * @uses update_post_meta() To update the forum category meta
743 856 * @return bool False on failure, true on success
744 857 */
745 858 function bbp_categorize_forum( $forum_id = 0 ) {
746 859
@@ -757,12 +870,11 @@
757 870
758 871 /**
759 872 * Remove the category status from a forum
760 873 *
761 - * @since bbPress (r2746)
874 + * @since 2.0.0 bbPress (r2746)
762 875 *
763 876 * @param int $forum_id Optional. Forum id
764 - * @uses delete_post_meta() To delete the forum category meta
765 877 * @return bool False on failure, true on success
766 878 */
767 879 function bbp_normalize_forum( $forum_id = 0 ) {
768 880
@@ -776,15 +888,16 @@
776 888
777 889 return $forum_id;
778 890 }
779 891
892 +/** Forum Visibility **********************************************************/
893 +
780 894 /**
781 895 * Mark the forum as public
782 896 *
783 - * @since bbPress (r2746)
897 + * @since 2.0.0 bbPress (r2746)
784 898 *
785 899 * @param int $forum_id Optional. Forum id
786 - * @uses update_post_meta() To update the forum private meta
787 900 * @return bool False on failure, true on success
788 901 */
789 902 function bbp_publicize_forum( $forum_id = 0, $current_visibility = '' ) {
790 903
@@ -795,17 +908,17 @@
795 908 // Get private forums
796 909 $private = bbp_get_private_forum_ids();
797 910
798 911 // Find this forum in the array
799 - if ( in_array( $forum_id, $private ) ) {
912 + if ( in_array( $forum_id, $private, true ) ) {
800 913
801 - $offset = array_search( $forum_id, $private );
914 + $offset = array_search( $forum_id, $private, true );
802 915
803 916 // Splice around it
804 917 array_splice( $private, $offset, 1 );
805 918
806 919 // Update private forums minus this one
807 - update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
920 + update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
808 921 }
809 922
810 923 // Get hidden forums
811 924 $hidden = bbp_get_hidden_forum_ids();
@@ -810,26 +923,25 @@
810 923 // Get hidden forums
811 924 $hidden = bbp_get_hidden_forum_ids();
812 925
813 926 // Find this forum in the array
814 - if ( in_array( $forum_id, $hidden ) ) {
927 + if ( in_array( $forum_id, $hidden, true ) ) {
815 928
816 - $offset = array_search( $forum_id, $hidden );
929 + $offset = array_search( $forum_id, $hidden, true );
817 930
818 931 // Splice around it
819 932 array_splice( $hidden, $offset, 1 );
820 933
821 934 // Update hidden forums minus this one
822 - update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
935 + update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
823 936 }
824 937
825 938 // Only run queries if visibility is changing
826 - if ( bbp_get_public_status_id() != $current_visibility ) {
827 -
828 - // Update forum post_status
829 - global $wpdb;
830 - $wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
939 + if ( bbp_get_public_status_id() !== $current_visibility ) {
940 + $bbp_db = bbp_db();
941 + $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
831 942 wp_transition_post_status( bbp_get_public_status_id(), $current_visibility, get_post( $forum_id ) );
943 + clean_post_cache( $forum_id );
832 944 }
833 945
834 946 do_action( 'bbp_publicized_forum', $forum_id );
835 947
@@ -838,12 +950,11 @@
838 950
839 951 /**
840 952 * Mark the forum as private
841 953 *
842 - * @since bbPress (r2746)
954 + * @since 2.0.0 bbPress (r2746)
843 955 *
844 956 * @param int $forum_id Optional. Forum id
845 - * @uses update_post_meta() To update the forum private meta
846 957 * @return bool False on failure, true on success
847 958 */
848 959 function bbp_privatize_forum( $forum_id = 0, $current_visibility = '' ) {
849 960
@@ -851,34 +962,35 @@
851 962
852 963 do_action( 'bbp_privatize_forum', $forum_id );
853 964
854 965 // Only run queries if visibility is changing
855 - if ( bbp_get_private_status_id() != $current_visibility ) {
966 + if ( bbp_get_private_status_id() !== $current_visibility ) {
856 967
857 968 // Get hidden forums
858 969 $hidden = bbp_get_hidden_forum_ids();
859 970
860 971 // Find this forum in the array
861 - if ( in_array( $forum_id, $hidden ) ) {
972 + if ( in_array( $forum_id, $hidden, true ) ) {
862 973
863 - $offset = array_search( $forum_id, $hidden );
974 + $offset = array_search( $forum_id, $hidden, true );
864 975
865 976 // Splice around it
866 977 array_splice( $hidden, $offset, 1 );
867 978
868 979 // Update hidden forums minus this one
869 - update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
980 + update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
870 981 }
871 982
872 983 // Add to '_bbp_private_forums' site option
873 984 $private = bbp_get_private_forum_ids();
874 985 $private[] = $forum_id;
875 - update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
986 + update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
876 987
877 988 // Update forums visibility setting
878 - global $wpdb;
879 - $wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
989 + $bbp_db = bbp_db();
990 + $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
880 991 wp_transition_post_status( bbp_get_private_status_id(), $current_visibility, get_post( $forum_id ) );
992 + clean_post_cache( $forum_id );
881 993 }
882 994
883 995 do_action( 'bbp_privatized_forum', $forum_id );
884 996
@@ -887,12 +999,11 @@
887 999
888 1000 /**
889 1001 * Mark the forum as hidden
890 1002 *
891 - * @since bbPress (r2996)
1003 + * @since 2.0.0 bbPress (r2996)
892 1004 *
893 1005 * @param int $forum_id Optional. Forum id
894 - * @uses update_post_meta() To update the forum private meta
895 1006 * @return bool False on failure, true on success
896 1007 */
897 1008 function bbp_hide_forum( $forum_id = 0, $current_visibility = '' ) {
898 1009
@@ -900,34 +1011,35 @@
900 1011
901 1012 do_action( 'bbp_hide_forum', $forum_id );
902 1013
903 1014 // Only run queries if visibility is changing
904 - if ( bbp_get_hidden_status_id() != $current_visibility ) {
1015 + if ( bbp_get_hidden_status_id() !== $current_visibility ) {
905 1016
906 1017 // Get private forums
907 1018 $private = bbp_get_private_forum_ids();
908 1019
909 1020 // Find this forum in the array
910 - if ( in_array( $forum_id, $private ) ) {
1021 + if ( in_array( $forum_id, $private, true ) ) {
911 1022
912 - $offset = array_search( $forum_id, $private );
1023 + $offset = array_search( $forum_id, $private, true );
913 1024
914 1025 // Splice around it
915 1026 array_splice( $private, $offset, 1 );
916 1027
917 1028 // Update private forums minus this one
918 - update_option( '_bbp_private_forums', array_unique( array_filter( array_values( $private ) ) ) );
1029 + update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
919 1030 }
920 1031
921 1032 // Add to '_bbp_hidden_forums' site option
922 1033 $hidden = bbp_get_hidden_forum_ids();
923 1034 $hidden[] = $forum_id;
924 - update_option( '_bbp_hidden_forums', array_unique( array_filter( array_values( $hidden ) ) ) );
1035 + update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
925 1036
926 1037 // Update forums visibility setting
927 - global $wpdb;
928 - $wpdb->update( $wpdb->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
1038 + $bbp_db = bbp_db();
1039 + $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
929 1040 wp_transition_post_status( bbp_get_hidden_status_id(), $current_visibility, get_post( $forum_id ) );
1041 + clean_post_cache( $forum_id );
930 1042 }
931 1043
932 1044 do_action( 'bbp_hid_forum', $forum_id );
933 1045
@@ -933,34 +1045,142 @@
933 1045
934 1046 return $forum_id;
935 1047 }
936 1048
1049 +/**
1050 + * Recaches the private and hidden forums
1051 + *
1052 + * @since 2.4.0 bbPress (r5017)
1053 + *
1054 + * @return array An array of the status code and the message
1055 + */
1056 +function bbp_repair_forum_visibility() {
1057 +
1058 + // First, delete everything.
1059 + delete_option( '_bbp_private_forums' );
1060 + delete_option( '_bbp_hidden_forums' );
1061 +
1062 + /**
1063 + * Don't search for both private/hidden statuses. Since 'pre_get_posts' is an
1064 + * action, it's not removed by suppress_filters. We need to make sure that
1065 + * we're only searching for the supplied post_status.
1066 + *
1067 + * @see https://bbpress.trac.wordpress.org/ticket/2512
1068 + */
1069 + remove_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
1070 +
1071 + // Query for private forums
1072 + $private_forums = new WP_Query(
1073 + array(
1074 + 'fields' => 'ids',
1075 + 'post_type' => bbp_get_forum_post_type(),
1076 + 'post_status' => bbp_get_private_status_id(),
1077 + 'posts_per_page' => -1,
1078 +
1079 + // Performance
1080 + 'nopaging' => true,
1081 + 'suppress_filters' => true,
1082 + 'update_post_term_cache' => false,
1083 + 'update_post_meta_cache' => false,
1084 + 'ignore_sticky_posts' => true,
1085 + 'no_found_rows' => true
1086 + )
1087 + );
1088 +
1089 + // Query for hidden forums
1090 + $hidden_forums = new WP_Query(
1091 + array(
1092 + 'fields' => 'ids',
1093 + 'post_type' => bbp_get_forum_post_type(),
1094 + 'post_status' => bbp_get_hidden_status_id(),
1095 + 'posts_per_page' => -1,
1096 +
1097 + // Performance
1098 + 'nopaging' => true,
1099 + 'suppress_filters' => true,
1100 + 'update_post_term_cache' => false,
1101 + 'update_post_meta_cache' => false,
1102 + 'ignore_sticky_posts' => true,
1103 + 'no_found_rows' => true
1104 + )
1105 + );
1106 +
1107 + // Enable forum visibilty normalization
1108 + add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
1109 +
1110 + // Reset the $post global
1111 + wp_reset_postdata();
1112 +
1113 + // Private
1114 + if ( ! is_wp_error( $private_forums ) ) {
1115 + update_option( '_bbp_private_forums', $private_forums->posts );
1116 + }
1117 +
1118 + // Hidden forums
1119 + if ( ! is_wp_error( $hidden_forums ) ) {
1120 + update_option( '_bbp_hidden_forums', $hidden_forums->posts );
1121 + }
1122 +
1123 + // Complete results
1124 + return true;
1125 +}
1126 +
1127 +/** Subscriptions *************************************************************/
1128 +
1129 +/**
1130 + * Remove a deleted forum from all user subscriptions
1131 + *
1132 + * @since 2.5.0 bbPress (r5156)
1133 + *
1134 + * @param int $forum_id Get the forum ID to remove
1135 + */
1136 +function bbp_remove_forum_from_all_subscriptions( $forum_id = 0 ) {
1137 +
1138 + // Subscriptions are not active
1139 + if ( ! bbp_is_subscriptions_active() ) {
1140 + return;
1141 + }
1142 +
1143 + // Bail if no forum
1144 + $forum_id = bbp_get_forum_id( $forum_id );
1145 + if ( empty( $forum_id ) ) {
1146 + return;
1147 + }
1148 +
1149 + // Remove forum from all subscriptions
1150 + return bbp_remove_object_from_all_users( $forum_id, '_bbp_subscription', 'post' );
1151 +}
1152 +
937 1153 /** Count Bumpers *************************************************************/
938 1154
939 1155 /**
940 1156 * Bump the total topic count of a forum
941 1157 *
942 - * @since bbPress (r3825)
1158 + * @since 2.1.0 bbPress (r3825)
1159 + * @since 2.6.17 Use atomic metadata writes and non-negative counts.
943 1160 *
944 1161 * @param int $forum_id Optional. Forum id.
945 1162 * @param int $difference Optional. Default 1
946 1163 * @param bool $update_ancestors Optional. Default true
947 - * @uses bbp_get_forum_id() To get the forum id
948 - * @uses update_post_meta() To update the forum's topic count meta
949 - * @uses apply_filters() Calls 'bbp_bump_forum_topic_count' with the topic
950 - * count, forum id, and difference
1164 + *
951 1165 * @return int Forum topic count
952 1166 */
953 1167 function bbp_bump_forum_topic_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
954 1168
1169 + // Bail if no bump
1170 + if ( empty( $difference ) ) {
1171 + return false;
1172 + }
1173 +
955 1174 // Get some counts
956 1175 $forum_id = bbp_get_forum_id( $forum_id );
957 - $topic_count = bbp_get_forum_topic_count( $forum_id, false, false );
958 - $total_topic_count = bbp_get_forum_topic_count( $forum_id, true, false );
1176 + $topic_count = bbp_get_forum_topic_count( $forum_id, false, true );
1177 + $total_topic_count = bbp_get_forum_topic_count( $forum_id, true, true );
1178 + $difference = (int) $difference;
959 1179
960 1180 // Update this forum id
961 - update_post_meta( $forum_id, '_bbp_topic_count', (int) $topic_count + (int) $difference );
962 - update_post_meta( $forum_id, '_bbp_total_topic_count', (int) $total_topic_count + (int) $difference );
1181 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count', $difference, $topic_count );
1182 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count', $difference, $total_topic_count );
963 1183
964 1184 // Check for ancestors
965 1185 if ( true === $update_ancestors ) {
966 1186
@@ -968,75 +1188,246 @@
968 1188 $forum = get_post( $forum_id );
969 1189 $ancestors = get_post_ancestors( $forum );
970 1190
971 1191 // If has ancestors, loop through them...
972 - if ( !empty( $ancestors ) ) {
1192 + if ( ! empty( $ancestors ) ) {
973 1193 foreach ( (array) $ancestors as $parent_forum_id ) {
974 1194
975 - // Get forum counts
976 - $parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, false );
977 - $parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true, false );
1195 + // Only update topic count when an ancestor is not a category.
1196 + if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
978 1197
979 - // Update counts
980 - update_post_meta( $parent_forum_id, '_bbp_topic_count', (int) $parent_topic_count + (int) $difference );
981 - update_post_meta( $parent_forum_id, '_bbp_total_topic_count', (int) $parent_total_topic_count + (int) $difference );
1198 + $parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, true );
1199 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count', $difference, $parent_topic_count );
1200 + }
1201 +
1202 + // Update the total topic count.
1203 + $parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true, true );
1204 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count', $difference, $parent_total_topic_count );
982 1205 }
983 1206 }
984 1207 }
985 1208
986 - return (int) apply_filters( 'bbp_bump_forum_topic_count', (int) $total_topic_count + (int) $difference, $forum_id, (int) $difference, (bool) $update_ancestors );
1209 + $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference );
1210 +
1211 + // Filter & return
1212 + return (int) apply_filters( 'bbp_bump_forum_topic_count', $forum_topic_count, $forum_id, $difference, $update_ancestors );
987 1213 }
988 1214
989 1215 /**
990 - * Bump the total hidden topic count of a forum
1216 + * Increase the total topic count of a forum by one.
991 1217 *
992 - * @since bbPress (r3825)
1218 + * @since 2.6.0 bbPress (r6036)
993 1219 *
1220 + * @param int $forum_id The forum id.
1221 + * @return void
1222 + */
1223 +function bbp_increase_forum_topic_count( $forum_id = 0 ) {
1224 +
1225 + // Bail early if no id is passed.
1226 + if ( empty( $forum_id ) ) {
1227 + return;
1228 + }
1229 +
1230 + // If it's a topic, get the forum id.
1231 + if ( bbp_is_topic( $forum_id ) ) {
1232 + $topic_id = $forum_id;
1233 + $forum_id = bbp_get_topic_forum_id( $topic_id );
1234 +
1235 + // Update inverse based on item status
1236 + if ( ! bbp_is_topic_public( $topic_id ) ) {
1237 + bbp_increase_forum_topic_count_hidden( $forum_id );
1238 + return;
1239 + }
1240 + }
1241 +
1242 + // Bump up
1243 + bbp_bump_forum_topic_count( $forum_id );
1244 +}
1245 +
1246 +/**
1247 + * Decrease the total topic count of a forum by one.
1248 + *
1249 + * @since 2.6.0 bbPress (r6036)
1250 + *
1251 + * @param int $forum_id The forum id.
1252 + *
1253 + * @return void
1254 + */
1255 +function bbp_decrease_forum_topic_count( $forum_id = 0 ) {
1256 +
1257 + // Bail early if no id is passed.
1258 + if ( empty( $forum_id ) ) {
1259 + return;
1260 + }
1261 +
1262 + // If it's a topic, get the forum id.
1263 + if ( bbp_is_topic( $forum_id ) ) {
1264 + $topic_id = $forum_id;
1265 + $forum_id = bbp_get_topic_forum_id( $topic_id );
1266 +
1267 + // Update inverse based on item status
1268 + if ( ! bbp_is_topic_public( $topic_id ) ) {
1269 + bbp_decrease_forum_topic_count_hidden( $forum_id );
1270 + return;
1271 + }
1272 + }
1273 +
1274 + // Bump down
1275 + bbp_bump_forum_topic_count( $forum_id, -1 );
1276 +}
1277 +
1278 +/**
1279 + * Bump the total topic count of a forum
1280 + *
1281 + * @since 2.1.0 bbPress (r3825)
1282 + * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1283 + *
994 1284 * @param int $forum_id Optional. Forum id.
995 1285 * @param int $difference Optional. Default 1
996 - * @uses bbp_get_forum_id() To get the forum id
997 - * @uses update_post_meta() To update the forum's topic count meta
998 - * @uses apply_filters() Calls 'bbp_bump_forum_topic_count_hidden' with the
999 - * topic count, forum id, and difference
1000 - * @return int Forum hidden topic count
1286 + * @param bool $update_ancestors Optional. Default true
1287 + *
1288 + * @return int Forum topic count
1001 1289 */
1002 -function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1 ) {
1290 +function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1003 1291
1292 + // Bail if no bump
1293 + if ( empty( $difference ) ) {
1294 + return false;
1295 + }
1296 +
1004 1297 // Get some counts
1005 - $forum_id = bbp_get_forum_id( $forum_id );
1006 - $topic_count = bbp_get_forum_topic_count_hidden( $forum_id, false );
1007 - $new_count = (int) $topic_count + (int) $difference;
1298 + $forum_id = bbp_get_forum_id( $forum_id );
1299 + $reply_count = bbp_get_forum_topic_count_hidden( $forum_id, false, true );
1300 + $total_topic_count = bbp_get_forum_topic_count_hidden( $forum_id, true, true );
1301 + $difference = (int) $difference;
1008 1302
1009 1303 // Update this forum id
1010 - update_post_meta( $forum_id, '_bbp_topic_count_hidden', (int) $new_count );
1304 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count_hidden', $difference, $reply_count );
1305 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count_hidden', $difference, $total_topic_count );
1011 1306
1012 - return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', (int) $new_count, $forum_id, (int) $difference );
1307 + // Check for ancestors
1308 + if ( true === $update_ancestors ) {
1309 +
1310 + // Get post ancestors
1311 + $forum = get_post( $forum_id );
1312 + $ancestors = get_post_ancestors( $forum );
1313 +
1314 + // If has ancestors, loop through them...
1315 + if ( ! empty( $ancestors ) ) {
1316 + foreach ( (array) $ancestors as $parent_forum_id ) {
1317 +
1318 + // Only update topic count when an ancestor is not a category.
1319 + if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1320 +
1321 + $parent_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, false, true );
1322 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count_hidden', $difference, $parent_topic_count );
1323 + }
1324 +
1325 + // Update the total topic count.
1326 + $parent_total_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, true, true );
1327 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count_hidden', $difference, $parent_total_topic_count );
1328 + }
1329 + }
1330 + }
1331 +
1332 + $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference );
1333 +
1334 + // Filter & return
1335 + return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', $forum_topic_count, $forum_id, $difference, $update_ancestors );
1013 1336 }
1014 1337
1015 1338 /**
1339 + * Increase the total hidden topic count of a forum by one.
1340 + *
1341 + * @since 2.6.0 bbPress (r6036)
1342 + *
1343 + * @param int $forum_id The forum id.
1344 + *
1345 + * @return void
1346 + */
1347 +function bbp_increase_forum_topic_count_hidden( $forum_id = 0 ) {
1348 +
1349 + // Bail early if no id is passed.
1350 + if ( empty( $forum_id ) ) {
1351 + return;
1352 + }
1353 +
1354 + // If it's a topic, get the forum id.
1355 + if ( bbp_is_topic( $forum_id ) ) {
1356 + $topic_id = $forum_id;
1357 + $forum_id = bbp_get_topic_forum_id( $topic_id );
1358 +
1359 + // Update inverse based on item status
1360 + if ( bbp_is_topic_public( $topic_id ) ) {
1361 + bbp_increase_forum_topic_count( $forum_id );
1362 + return;
1363 + }
1364 + }
1365 +
1366 + // Bump up
1367 + bbp_bump_forum_topic_count_hidden( $forum_id );
1368 +}
1369 +
1370 +/**
1371 + * Decrease the total hidden topic count of a forum by one.
1372 + *
1373 + * @since 2.6.0 bbPress (r6036)
1374 + *
1375 + * @param int $forum_id The forum id.
1376 + *
1377 + * @return void
1378 + */
1379 +function bbp_decrease_forum_topic_count_hidden( $forum_id = 0 ) {
1380 +
1381 + // Bail early if no id is passed.
1382 + if ( empty( $forum_id ) ) {
1383 + return;
1384 + }
1385 +
1386 + // If it's a topic, get the forum id.
1387 + if ( bbp_is_topic( $forum_id ) ) {
1388 + $topic_id = $forum_id;
1389 + $forum_id = bbp_get_topic_forum_id( $topic_id );
1390 +
1391 + // Update inverse based on item status
1392 + if ( bbp_is_topic_public( $topic_id ) ) {
1393 + bbp_decrease_forum_topic_count( $forum_id );
1394 + return;
1395 + }
1396 + }
1397 +
1398 + // Bump down
1399 + bbp_bump_forum_topic_count_hidden( $forum_id, -1 );
1400 +}
1401 +
1402 +/**
1016 1403 * Bump the total topic count of a forum
1017 1404 *
1018 - * @since bbPress (r3825)
1405 + * @since 2.1.0 bbPress (r3825)
1406 + * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1019 1407 *
1020 1408 * @param int $forum_id Optional. Forum id.
1021 1409 * @param int $difference Optional. Default 1
1022 1410 * @param bool $update_ancestors Optional. Default true
1023 - * @uses bbp_get_forum_id() To get the forum id
1024 - * @uses update_post_meta() To update the forum's topic count meta
1025 - * @uses apply_filters() Calls 'bbp_bump_forum_reply_count' with the topic
1026 - * count, forum id, and difference
1411 + *
1027 1412 * @return int Forum topic count
1028 1413 */
1029 1414 function bbp_bump_forum_reply_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1030 1415
1416 + // Bail if no bump
1417 + if ( empty( $difference ) ) {
1418 + return false;
1419 + }
1420 +
1031 1421 // Get some counts
1032 1422 $forum_id = bbp_get_forum_id( $forum_id );
1033 - $topic_count = bbp_get_forum_reply_count( $forum_id, false );
1034 - $total_reply_count = bbp_get_forum_reply_count( $forum_id, true );
1423 + $reply_count = bbp_get_forum_reply_count( $forum_id, false, true );
1424 + $total_reply_count = bbp_get_forum_reply_count( $forum_id, true, true );
1425 + $difference = (int) $difference;
1035 1426
1036 1427 // Update this forum id
1037 - update_post_meta( $forum_id, '_bbp_reply_count', (int) $topic_count + (int) $difference );
1038 - update_post_meta( $forum_id, '_bbp_total_reply_count', (int) $total_reply_count + (int) $difference );
1428 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count', $difference, $reply_count );
1429 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count', $difference, $total_reply_count );
1039 1430
1040 1431 // Check for ancestors
1041 1432 if ( true === $update_ancestors ) {
1042 1433
@@ -1044,43 +1435,313 @@
1044 1435 $forum = get_post( $forum_id );
1045 1436 $ancestors = get_post_ancestors( $forum );
1046 1437
1047 1438 // If has ancestors, loop through them...
1048 - if ( !empty( $ancestors ) ) {
1439 + if ( ! empty( $ancestors ) ) {
1049 1440 foreach ( (array) $ancestors as $parent_forum_id ) {
1050 1441
1051 - // Get forum counts
1052 - $parent_topic_count = bbp_get_forum_reply_count( $parent_forum_id, false );
1053 - $parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true );
1442 + // Only update reply count when an ancestor is not a category.
1443 + if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1054 1444
1055 - // Update counts
1056 - update_post_meta( $parent_forum_id, '_bbp_reply_count', (int) $parent_topic_count + (int) $difference );
1057 - update_post_meta( $parent_forum_id, '_bbp_total_reply_count', (int) $parent_total_reply_count + (int) $difference );
1445 + $parent_reply_count = bbp_get_forum_reply_count( $parent_forum_id, false, true );
1446 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count', $difference, $parent_reply_count );
1447 + }
1448 +
1449 + // Update the total reply count.
1450 + $parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true, true );
1451 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count', $difference, $parent_total_reply_count );
1058 1452 }
1059 1453 }
1060 1454 }
1061 1455
1062 - return (int) apply_filters( 'bbp_bump_forum_reply_count', (int) $total_reply_count + (int) $difference, $forum_id, (int) $difference, (bool) $update_ancestors );
1456 + $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference );
1457 +
1458 + // Filter & return
1459 + return (int) apply_filters( 'bbp_bump_forum_reply_count', $forum_reply_count, $forum_id, $difference, $update_ancestors );
1063 1460 }
1064 1461
1462 +/**
1463 + * Bump the total topic count of a forum
1464 + *
1465 + * @since 2.6.0 bbPress (r6922)
1466 + * @since 2.6.17 Use atomic metadata writes and non-negative counts.
1467 + *
1468 + * @param int $forum_id Optional. Forum id.
1469 + * @param int $difference Optional. Default 1
1470 + * @param bool $update_ancestors Optional. Default true
1471 + *
1472 + * @return int Forum topic count
1473 + */
1474 +function bbp_bump_forum_reply_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1475 +
1476 + // Bail if no bump
1477 + if ( empty( $difference ) ) {
1478 + return false;
1479 + }
1480 +
1481 + // Get some counts
1482 + $forum_id = bbp_get_forum_id( $forum_id );
1483 + $reply_count = bbp_get_forum_reply_count_hidden( $forum_id, false, true );
1484 + $total_reply_count = bbp_get_forum_reply_count_hidden( $forum_id, true, true );
1485 + $difference = (int) $difference;
1486 +
1487 + // Update this forum id
1488 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count_hidden', $difference, $reply_count );
1489 + bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count_hidden', $difference, $total_reply_count );
1490 +
1491 + // Check for ancestors
1492 + if ( true === $update_ancestors ) {
1493 +
1494 + // Get post ancestors
1495 + $forum = get_post( $forum_id );
1496 + $ancestors = get_post_ancestors( $forum );
1497 +
1498 + // If has ancestors, loop through them...
1499 + if ( ! empty( $ancestors ) ) {
1500 + foreach ( (array) $ancestors as $parent_forum_id ) {
1501 +
1502 + // Only update reply count when an ancestor is not a category.
1503 + if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1504 +
1505 + $parent_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, false, true );
1506 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count_hidden', $difference, $parent_reply_count );
1507 + }
1508 +
1509 + // Update the total reply count.
1510 + $parent_total_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, true, true );
1511 + bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count_hidden', $difference, $parent_total_reply_count );
1512 + }
1513 + }
1514 + }
1515 +
1516 + $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference );
1517 +
1518 + // Filter & return
1519 + return (int) apply_filters( 'bbp_bump_forum_reply_count_hidden', $forum_reply_count, $forum_id, $difference, $update_ancestors );
1520 +}
1521 +
1522 +/**
1523 + * Bump one total count through a forum's ancestors.
1524 + *
1525 + * This is used after recounting a forum that may be nested as a subforum. The
1526 + * starting forum's total has already been updated, so only its parent forums
1527 + * receive the difference between the old and new totals. The supplied metadata
1528 + * key identifies which total topic or reply count is propagated.
1529 + *
1530 + * Forum hierarchy is stored in `post_parent`, making get_post_ancestors() the
1531 + * canonical, cache-aware way to walk from a subforum toward its root forum.
1532 + * Only parent forums are traversed: topics and replies are never ancestors in
1533 + * a valid forum hierarchy, even when the metadata key stores their totals. The
1534 + * walk stops if a malformed parent relationship leaves the forum post type.
1535 + *
1536 + * @since 2.6.17
1537 + *
1538 + * @param int $forum_id Starting forum ID. Its own count is not changed.
1539 + * @param string $meta_key Topic or reply total count metadata key.
1540 + * @param int $difference Amount to add to the stored value.
1541 + * @return bool True when all ancestor counts were updated, false otherwise.
1542 + */
1543 +function bbp_bump_forum_ancestor_count( $forum_id = 0, $meta_key = '', $difference = 0 ) {
1544 + $forum_id = bbp_get_forum_id( $forum_id );
1545 + $difference = (int) $difference;
1546 +
1547 + // Bail if nothing can change
1548 + if ( empty( $forum_id ) || empty( $meta_key ) || empty( $difference ) ) {
1549 + return false;
1550 + }
1551 +
1552 + $updated = true;
1553 + $ancestor_ids = get_post_ancestors( $forum_id );
1554 +
1555 + // Return if this forum has no ancestors
1556 + if ( empty( $ancestor_ids ) ) {
1557 + return $updated;
1558 + }
1559 +
1560 + // Update only total counts on ancestor forums
1561 + foreach ( $ancestor_ids as $ancestor_id ) {
1562 +
1563 + // Stop if malformed data leaves the subforum hierarchy
1564 + if ( ! bbp_is_forum( $ancestor_id ) ) {
1565 + break;
1566 + }
1567 +
1568 + $count = (int) get_post_meta( $ancestor_id, $meta_key, true );
1569 +
1570 + if ( ! bbp_bump_count_meta( 'post', $ancestor_id, $meta_key, $difference, $count ) ) {
1571 + $updated = false;
1572 + }
1573 + }
1574 +
1575 + return $updated;
1576 +}
1577 +
1578 +/**
1579 + * Increase the total reply count of a forum by one.
1580 + *
1581 + * @since 2.6.0 bbPress (r6036)
1582 + *
1583 + * @param int $forum_id The forum id.
1584 + *
1585 + * @return void
1586 + */
1587 +function bbp_increase_forum_reply_count( $forum_id = 0 ) {
1588 +
1589 + // Bail early if no id is passed.
1590 + if ( empty( $forum_id ) ) {
1591 + return;
1592 + }
1593 +
1594 + // If it's a reply, get the forum id.
1595 + if ( bbp_is_reply( $forum_id ) ) {
1596 + $reply_id = $forum_id;
1597 + $forum_id = bbp_get_reply_forum_id( $reply_id );
1598 +
1599 + // Update inverse based on item status
1600 + if ( ! bbp_is_reply_public( $reply_id ) ) {
1601 + bbp_increase_forum_reply_count_hidden( $forum_id );
1602 + return;
1603 + }
1604 + }
1605 +
1606 + // Bump up
1607 + bbp_bump_forum_reply_count( $forum_id );
1608 +}
1609 +
1610 +/**
1611 + * Decrease the total reply count of a forum by one.
1612 + *
1613 + * @since 2.6.0 bbPress (r6036)
1614 + *
1615 + * @param int $forum_id The forum id.
1616 + *
1617 + * @return void
1618 + */
1619 +function bbp_decrease_forum_reply_count( $forum_id = 0 ) {
1620 +
1621 + // Bail early if no id is passed.
1622 + if ( empty( $forum_id ) ) {
1623 + return;
1624 + }
1625 +
1626 + // If it's a reply, get the forum id.
1627 + if ( bbp_is_reply( $forum_id ) ) {
1628 + $reply_id = $forum_id;
1629 + $forum_id = bbp_get_reply_forum_id( $reply_id );
1630 +
1631 + // Update inverse based on item status
1632 + if ( ! bbp_is_reply_public( $reply_id ) ) {
1633 + bbp_decrease_forum_reply_count_hidden( $forum_id );
1634 + return;
1635 + }
1636 + }
1637 +
1638 + // Bump down
1639 + bbp_bump_forum_reply_count( $forum_id, -1 );
1640 +}
1641 +
1642 +/**
1643 + * Increase the total hidden reply count of a forum by one.
1644 + *
1645 + * @since 2.6.0 bbPress (r6036)
1646 + *
1647 + * @param int $forum_id The forum id.
1648 + *
1649 + * @return void
1650 + */
1651 +function bbp_increase_forum_reply_count_hidden( $forum_id = 0 ) {
1652 +
1653 + // Bail early if no id is passed.
1654 + if ( empty( $forum_id ) ) {
1655 + return;
1656 + }
1657 +
1658 + // If it's a reply, get the forum id.
1659 + if ( bbp_is_reply( $forum_id ) ) {
1660 + $reply_id = $forum_id;
1661 + $forum_id = bbp_get_reply_forum_id( $reply_id );
1662 +
1663 + // Update inverse based on item status
1664 + if ( bbp_is_reply_public( $reply_id ) ) {
1665 + bbp_increase_forum_reply_count( $forum_id );
1666 + return;
1667 + }
1668 + }
1669 +
1670 + // Bump up
1671 + bbp_bump_forum_reply_count_hidden( $forum_id );
1672 +}
1673 +
1674 +/**
1675 + * Decrease the total hidden reply count of a forum by one.
1676 + *
1677 + * @since 2.6.0 bbPress (r6036)
1678 + *
1679 + * @param int $forum_id The forum id.
1680 + *
1681 + * @return void
1682 + */
1683 +function bbp_decrease_forum_reply_count_hidden( $forum_id = 0 ) {
1684 +
1685 + // Bail early if no id is passed.
1686 + if ( empty( $forum_id ) ) {
1687 + return;
1688 + }
1689 +
1690 + // If it's a reply, get the forum id.
1691 + if ( bbp_is_reply( $forum_id ) ) {
1692 + $reply_id = $forum_id;
1693 + $forum_id = bbp_get_reply_forum_id( $reply_id );
1694 +
1695 + // Update inverse based on item status
1696 + if ( bbp_is_reply_public( $reply_id ) ) {
1697 + bbp_decrease_forum_reply_count( $forum_id );
1698 + return;
1699 + }
1700 + }
1701 +
1702 + // Bump down
1703 + bbp_bump_forum_reply_count_hidden( $forum_id, -1 );
1704 +}
1705 +
1706 +/**
1707 + * Update forum reply counts when a topic is approved or unapproved.
1708 + *
1709 + * @since 2.6.0 bbPress (r6036)
1710 + *
1711 + * @param int $topic_id The topic id.
1712 + *
1713 + * @return void
1714 + */
1715 +function bbp_approved_unapproved_topic_update_forum_reply_count( $topic_id = 0 ) {
1716 +
1717 + // Bail early if we don't have a topic id.
1718 + if ( empty( $topic_id ) ) {
1719 + return;
1720 + }
1721 +
1722 + // Get the topic's replies.
1723 + $count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
1724 +
1725 + // If we're unapproving, set count to negative.
1726 + if ( 'bbp_unapproved_topic' === current_filter() ) {
1727 + $count = -$count;
1728 + }
1729 +
1730 + // Bump up or down
1731 + bbp_bump_forum_reply_count( bbp_get_topic_forum_id( $topic_id ), $count );
1732 +}
1733 +
1065 1734 /** Forum Updaters ************************************************************/
1066 1735
1067 1736 /**
1068 1737 * Update the forum last topic id
1069 1738 *
1070 - * @since bbPress (r2625)
1739 + * @since 2.0.0 bbPress (r2625)
1071 1740 *
1072 - * @param int $forum_id Optional. Forum id
1073 - * @param int $topic_id Optional. Topic id
1074 - * @uses bbp_get_forum_id() To get the forum id
1075 - * @uses bbp_forum_query_subforum_ids() To get the subforum ids
1076 - * @uses bbp_update_forum_last_topic_id() To update the last topic id of child
1077 - * forums
1078 - * @uses get_posts() To get the most recent topic in the forum
1079 - * @uses update_post_meta() To update the forum's last active id meta
1080 - * @uses apply_filters() Calls 'bbp_update_forum_last_topic_id' with the last
1081 - * reply id and forum id
1082 - * @return bool True on success, false on failure
1741 + * @param int $forum_id Optional. Forum id.
1742 + * @param int $topic_id Optional. Topic id.
1743 + * @return int Id of the forums most recent topic
1083 1744 */
1084 1745 function bbp_update_forum_last_topic_id( $forum_id = 0, $topic_id = 0 ) {
1085 1746 $forum_id = bbp_get_forum_id( $forum_id );
1086 1747
@@ -1091,10 +1752,10 @@
1091 1752 if ( empty( $topic_id ) ) {
1092 1753
1093 1754 // Loop through children and add together forum reply counts
1094 1755 $children = bbp_forum_query_subforum_ids( $forum_id );
1095 - if ( !empty( $children ) ) {
1096 - foreach ( (array) $children as $child ) {
1756 + if ( ! empty( $children ) ) {
1757 + foreach ( $children as $child ) {
1097 1758 $children_last_topic = bbp_update_forum_last_topic_id( $child ); // Recursive
1098 1759 }
1099 1760 }
1100 1761
@@ -1102,8 +1763,9 @@
1102 1763 $post_vars = array(
1103 1764 'post_parent' => $forum_id,
1104 1765 'post_type' => bbp_get_topic_post_type(),
1105 1766 'meta_key' => '_bbp_last_active_time',
1767 + 'meta_type' => 'DATETIME',
1106 1768 'orderby' => 'meta_value',
1107 1769 'numberposts' => 1
1108 1770 );
1109 1771
@@ -1108,9 +1770,9 @@
1108 1770 );
1109 1771
1110 1772 // Get the most recent topic in this forum_id
1111 1773 $recent_topic = get_posts( $post_vars );
1112 - if ( !empty( $recent_topic ) ) {
1774 + if ( ! empty( $recent_topic ) ) {
1113 1775 $topic_id = $recent_topic[0]->ID;
1114 1776 }
1115 1777 }
1116 1778
@@ -1118,15 +1780,16 @@
1118 1780 $topic_id = (int) $topic_id;
1119 1781 $children_last_topic = (int) $children_last_topic;
1120 1782
1121 1783 // If child forums have higher id, use that instead
1122 - if ( !empty( $children ) && ( $children_last_topic > $topic_id ) )
1784 + if ( ! empty( $children ) && ( $children_last_topic > $topic_id ) ) {
1123 1785 $topic_id = $children_last_topic;
1786 + }
1124 1787
1125 1788 // Update the last public topic ID
1126 - if ( bbp_is_topic_published( $topic_id ) )
1127 - update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );
1789 + update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );
1128 1790
1791 + // Filter & return
1129 1792 return (int) apply_filters( 'bbp_update_forum_last_topic_id', $topic_id, $forum_id );
1130 1793 }
1131 1794
1132 1795 /**
@@ -1131,23 +1794,13 @@
1131 1794
1132 1795 /**
1133 1796 * Update the forum last reply id
1134 1797 *
1135 - * @since bbPress (r2625)
1798 + * @since 2.0.0 bbPress (r2625)
1136 1799 *
1137 - * @param int $forum_id Optional. Forum id
1138 - * @param int $reply_id Optional. Reply id
1139 - * @uses bbp_get_forum_id() To get the forum id
1140 - * @uses bbp_forum_query_subforum_ids() To get the subforum ids
1141 - * @uses bbp_update_forum_last_reply_id() To update the last reply id of child
1142 - * forums
1143 - * @uses bbp_forum_query_topic_ids() To get the topic ids in the forum
1144 - * @uses bbp_forum_query_last_reply_id() To get the forum's last reply id
1145 - * @uses bbp_is_reply_published() To make sure the reply is published
1146 - * @uses update_post_meta() To update the forum's last active id meta
1147 - * @uses apply_filters() Calls 'bbp_update_forum_last_reply_id' with the last
1148 - * reply id and forum id
1149 - * @return bool True on success, false on failure
1800 + * @param int $forum_id Optional. Forum id.
1801 + * @param int $reply_id Optional. Reply id.
1802 + * @return int Id of the forums most recent reply
1150 1803 */
1151 1804 function bbp_update_forum_last_reply_id( $forum_id = 0, $reply_id = 0 ) {
1152 1805 $forum_id = bbp_get_forum_id( $forum_id );
1153 1806
@@ -1158,10 +1811,10 @@
1158 1811 if ( empty( $reply_id ) ) {
1159 1812
1160 1813 // Loop through children and get the most recent reply id
1161 1814 $children = bbp_forum_query_subforum_ids( $forum_id );
1162 - if ( !empty( $children ) ) {
1163 - foreach ( (array) $children as $child ) {
1815 + if ( ! empty( $children ) ) {
1816 + foreach ( $children as $child ) {
1164 1817 $children_last_reply = bbp_update_forum_last_reply_id( $child ); // Recursive
1165 1818 }
1166 1819 }
1167 1820
@@ -1166,15 +1819,17 @@
1166 1819 }
1167 1820
1168 1821 // If this forum has topics...
1169 1822 $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1170 - if ( !empty( $topic_ids ) ) {
1823 + if ( ! empty( $topic_ids ) ) {
1171 1824
1172 1825 // ...get the most recent reply from those topics...
1173 1826 $reply_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1174 1827
1175 1828 // ...and compare it to the most recent topic id...
1176 - $reply_id = ( $reply_id > max( $topic_ids ) ) ? $reply_id : max( $topic_ids );
1829 + $reply_id = ( $reply_id > max( $topic_ids ) )
1830 + ? $reply_id
1831 + : max( $topic_ids );
1177 1832 }
1178 1833 }
1179 1834
1180 1835 // Cast as integer in case of empty or string
@@ -1179,17 +1834,18 @@
1179 1834
1180 1835 // Cast as integer in case of empty or string
1181 1836 $reply_id = (int) $reply_id;
1182 1837 $children_last_reply = (int) $children_last_reply;
1183 -
1838 +
1184 1839 // If child forums have higher ID, check for newer reply id
1185 - if ( !empty( $children ) && ( $children_last_reply > $reply_id ) )
1840 + if ( ! empty( $children ) && ( $children_last_reply > $reply_id ) ) {
1186 1841 $reply_id = $children_last_reply;
1842 + }
1187 1843
1188 1844 // Update the last public reply ID
1189 - if ( bbp_is_reply_published( $reply_id ) )
1190 - update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );
1845 + update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );
1191 1846
1847 + // Filter & return
1192 1848 return (int) apply_filters( 'bbp_update_forum_last_reply_id', $reply_id, $forum_id );
1193 1849 }
1194 1850
1195 1851 /**
@@ -1194,23 +1850,13 @@
1194 1850
1195 1851 /**
1196 1852 * Update the forum last active post id
1197 1853 *
1198 - * @since bbPress (r2860)
1854 + * @since 2.0.0 bbPress (r2860)
1199 1855 *
1200 - * @param int $forum_id Optional. Forum id
1201 - * @param int $active_id Optional. Active post id
1202 - * @uses bbp_get_forum_id() To get the forum id
1203 - * @uses bbp_forum_query_subforum_ids() To get the subforum ids
1204 - * @uses bbp_update_forum_last_active_id() To update the last active id of
1205 - * child forums
1206 - * @uses bbp_forum_query_topic_ids() To get the topic ids in the forum
1207 - * @uses bbp_forum_query_last_reply_id() To get the forum's last reply id
1208 - * @uses get_post_status() To make sure the reply is published
1209 - * @uses update_post_meta() To update the forum's last active id meta
1210 - * @uses apply_filters() Calls 'bbp_update_forum_last_active_id' with the last
1211 - * active post id and forum id
1212 - * @return bool True on success, false on failure
1856 + * @param int $forum_id Optional. Forum id.
1857 + * @param int $active_id Optional. Active post id.
1858 + * @return int Id of the forums last active post
1213 1859 */
1214 1860 function bbp_update_forum_last_active_id( $forum_id = 0, $active_id = 0 ) {
1215 1861
1216 1862 $forum_id = bbp_get_forum_id( $forum_id );
@@ -1220,21 +1866,25 @@
1220 1866
1221 1867 // Do some calculation if not manually set
1222 1868 if ( empty( $active_id ) ) {
1223 1869
1224 - // Loop through children and add together forum reply counts
1870 + // Loop through children and get the last active ID
1225 1871 $children = bbp_forum_query_subforum_ids( $forum_id );
1226 - if ( !empty( $children ) ) {
1227 - foreach ( (array) $children as $child ) {
1872 + if ( ! empty( $children ) ) {
1873 + foreach ( $children as $child ) {
1228 1874 $children_last_active = bbp_update_forum_last_active_id( $child, $active_id );
1229 1875 }
1230 1876 }
1231 1877
1232 - // Don't count replies if the forum is a category
1878 + // Get topic IDs and only accept larger IDs
1233 1879 $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1234 - if ( !empty( $topic_ids ) ) {
1880 + if ( ! empty( $topic_ids ) ) {
1881 +
1882 + // Make sure ID is larger
1235 1883 $active_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1236 - $active_id = $active_id > max( $topic_ids ) ? $active_id : max( $topic_ids );
1884 + $active_id = $active_id > max( $topic_ids )
1885 + ? $active_id
1886 + : max( $topic_ids );
1237 1887
1238 1888 // Forum has no topics
1239 1889 } else {
1240 1890 $active_id = 0;
@@ -1244,132 +1894,271 @@
1244 1894 // Cast as integer in case of empty or string
1245 1895 $active_id = (int) $active_id;
1246 1896 $children_last_active = (int) $children_last_active;
1247 1897
1248 - // If child forums have higher id, use that instead
1249 - if ( !empty( $children ) && ( $children_last_active > $active_id ) )
1898 + // If child forums have higher ID, use that instead
1899 + if ( ! empty( $children ) && ( $children_last_active > $active_id ) ) {
1250 1900 $active_id = $children_last_active;
1901 + }
1251 1902
1252 - // Update only if published
1253 - if ( bbp_get_public_status_id() == get_post_status( $active_id ) )
1254 - update_post_meta( $forum_id, '_bbp_last_active_id', (int) $active_id );
1903 + update_post_meta( $forum_id, '_bbp_last_active_id', $active_id );
1255 1904
1256 - return (int) apply_filters( 'bbp_update_forum_last_active_id', (int) $active_id, $forum_id );
1905 + // Filter & return
1906 + return (int) apply_filters( 'bbp_update_forum_last_active_id', $active_id, $forum_id );
1257 1907 }
1258 1908
1259 1909 /**
1260 1910 * Update the forums last active date/time (aka freshness)
1261 1911 *
1262 - * @since bbPress (r2680)
1912 + * @since 2.0.0 bbPress (r2680)
1263 1913 *
1264 - * @param int $forum_id Optional. Topic id
1265 - * @param string $new_time Optional. New time in mysql format
1266 - * @uses bbp_get_forum_id() To get the forum id
1267 - * @uses bbp_get_forum_last_active_id() To get the forum's last post id
1268 - * @uses get_post_field() To get the post date of the forum's last post
1269 - * @uses update_post_meta() To update the forum last active time
1270 - * @uses apply_filters() Calls 'bbp_update_forum_last_active' with the new time
1271 - * and forum id
1272 - * @return bool True on success, false on failure
1914 + * @param int $forum_id Optional. Topic id.
1915 + * @param string $new_time Optional. New time in mysql format.
1916 + *
1917 + * @return string MySQL timestamp of last active topic or reply
1273 1918 */
1274 1919 function bbp_update_forum_last_active_time( $forum_id = 0, $new_time = '' ) {
1275 1920 $forum_id = bbp_get_forum_id( $forum_id );
1276 1921
1277 1922 // Check time and use current if empty
1278 - if ( empty( $new_time ) )
1923 + if ( empty( $new_time ) ) {
1279 1924 $new_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $forum_id ) );
1925 + }
1280 1926
1281 1927 // Update only if there is a time
1282 - if ( !empty( $new_time ) )
1928 + if ( ! empty( $new_time ) ) {
1283 1929 update_post_meta( $forum_id, '_bbp_last_active_time', $new_time );
1930 + }
1284 1931
1285 - return (int) apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
1932 + // Filter & return
1933 + return apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
1286 1934 }
1287 1935
1288 1936 /**
1289 1937 * Update the forum sub-forum count
1290 1938 *
1291 - * @since bbPress (r2625)
1939 + * @since 2.0.0 bbPress (r2625)
1940 + * @since 2.6.17 Count supported forum visibilities from the post hierarchy.
1292 1941 *
1293 - * @param int $forum_id Optional. Forum id
1294 - * @uses bbp_get_forum_id() To get the forum id
1295 - * @return bool True on success, false on failure
1942 + * @param int $forum_id Optional. Forum ID.
1943 + * @param int|bool $subforums Optional. Number of subforums, or false to query.
1944 + * @return int|false Number of subforums, or false on query failure.
1945 +*/
1946 +function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = false ) {
1947 + $forum_id = bbp_get_forum_id( $forum_id );
1948 +
1949 + // Maybe query for counts
1950 + if ( ! is_int( $subforums ) ) {
1951 + $bbp_db = bbp_db();
1952 + $post_type = bbp_get_forum_post_type();
1953 + $statuses = bbp_get_countable_forum_statuses();
1954 +
1955 + if ( ! empty( $statuses ) ) {
1956 + $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
1957 + $sql = "SELECT COUNT(*) FROM {$bbp_db->posts} WHERE post_parent = %d AND post_type = %s AND post_status IN ({$placeholders})";
1958 + $query = $bbp_db->prepare( $sql, array_merge( array( $forum_id, $post_type ), $statuses ) );
1959 + $subforums = $bbp_db->get_var( $query );
1960 +
1961 + // Bail if the count query failed
1962 + if ( ! empty( $bbp_db->last_error ) ) {
1963 + return false;
1964 + }
1965 +
1966 + $subforums = bbp_number_not_negative( $subforums );
1967 + } else {
1968 + $subforums = 0;
1969 + }
1970 + }
1971 +
1972 + update_post_meta( $forum_id, '_bbp_forum_subforum_count', $subforums );
1973 +
1974 + // Filter & return
1975 + return (int) apply_filters( 'bbp_update_forum_subforum_count', $subforums, $forum_id );
1976 +}
1977 +
1978 +/**
1979 + * Synchronize child-forum metadata after WordPress reparents deleted children.
1980 + *
1981 + * @since 2.6.17
1982 + *
1983 + * @param int $forum_id Deleted forum ID.
1984 + * @param WP_Post $forum Deleted forum post object.
1296 1985 */
1297 -function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = 0 ) {
1298 - $forum_id = bbp_get_forum_id( $forum_id );
1986 +function bbp_reparent_forum_subforums( $forum_id = 0, $forum = false ) {
1987 + $bbp_db = bbp_db();
1988 + $post_type = bbp_get_forum_post_type();
1989 + $meta_key = '_bbp_forum_id';
1990 + $sql = "SELECT posts.ID
1991 + FROM {$bbp_db->posts} AS posts
1992 + INNER JOIN {$bbp_db->postmeta} AS postmeta
1993 + ON posts.ID = postmeta.post_id
1994 + AND postmeta.meta_key = %s
1995 + WHERE posts.post_type = %s
1996 + AND posts.post_parent = %d
1997 + AND postmeta.meta_value = %d";
1998 + $query = $bbp_db->prepare( $sql, $meta_key, $post_type, $forum->post_parent, $forum_id );
1299 1999
1300 - if ( empty( $subforums ) )
1301 - $subforums = count( bbp_forum_query_subforum_ids( $forum_id ) );
2000 + foreach ( wp_parse_id_list( $bbp_db->get_col( $query ) ) as $subforum_id ) {
2001 + bbp_update_forum_id( $subforum_id, $forum->post_parent );
2002 + }
2003 +}
1302 2004
1303 - update_post_meta( $forum_id, '_bbp_forum_subforum_count', (int) $subforums );
2005 +/**
2006 + * Update a parent forum's subforum count after a child is permanently deleted.
2007 + *
2008 + * @since 2.6.17
2009 + *
2010 + * @param int $forum_id Forum ID.
2011 + * @param WP_Post|bool $forum Optional. Forum post object.
2012 + * @return int|false Updated subforum count, or false if there is no parent.
2013 + */
2014 +function bbp_update_parent_forum_subforum_count( $forum_id = 0, $forum = false ) {
2015 + $forum = ( $forum instanceof WP_Post )
2016 + ? $forum
2017 + : get_post( $forum_id );
1304 2018
1305 - return (int) apply_filters( 'bbp_update_forum_subforum_count', (int) $subforums, $forum_id );
2019 + // Bail if the forum has no parent
2020 + if ( empty( $forum ) || empty( $forum->post_parent ) ) {
2021 + return false;
2022 + }
2023 +
2024 + return bbp_update_forum_subforum_count( $forum->post_parent );
1306 2025 }
1307 2026
1308 2027 /**
1309 - * Adjust the total topic count of a forum
2028 + * Update a parent forum's subforum count after a child changes count status.
1310 2029 *
1311 - * @since bbPress (r2464)
2030 + * @since 2.6.17
1312 2031 *
2032 + * @param string $new_status New post status.
2033 + * @param string $old_status Old post status.
2034 + * @param WP_Post $forum Forum post object.
2035 + * @return int|false Updated subforum count, or false when no update is needed.
2036 + */
2037 +function bbp_update_forum_subforum_count_on_transition_post_status( $new_status = '', $old_status = '', $forum = false ) {
2038 +
2039 + // Bail if this is not a child forum
2040 + if ( ( bbp_get_forum_post_type() !== $forum->post_type ) || empty( $forum->post_parent ) ) {
2041 + return false;
2042 + }
2043 +
2044 + $statuses = bbp_get_countable_forum_statuses();
2045 + $was_counted = in_array( $old_status, $statuses, true );
2046 + $is_counted = in_array( $new_status, $statuses, true );
2047 +
2048 + // Bail if subforum count membership did not change
2049 + if ( $was_counted === $is_counted ) {
2050 + return false;
2051 + }
2052 +
2053 + return bbp_update_forum_subforum_count( $forum->post_parent );
2054 +}
2055 +
2056 +/**
2057 + * Update subforum counts after a forum changes parent or post type.
2058 + *
2059 + * @since 2.6.17
2060 + *
2061 + * @param int $forum_id Forum ID.
2062 + * @param WP_Post $forum_after Forum object following the update.
2063 + * @param WP_Post $forum_before Forum object before the update.
2064 + */
2065 +function bbp_update_forum_subforum_counts_on_post_updated( $forum_id = 0, $forum_after = false, $forum_before = false ) {
2066 + $post_type = bbp_get_forum_post_type();
2067 + $parent_moved = ( $forum_after->post_parent !== $forum_before->post_parent );
2068 +
2069 + // Bail if forum hierarchy membership did not change
2070 + if ( ! $parent_moved && ( $forum_after->post_type === $forum_before->post_type ) ) {
2071 + return false;
2072 + }
2073 +
2074 + // Synchronize parent metadata when the updated post remains a forum
2075 + if ( ( $post_type === $forum_after->post_type ) && ( $parent_moved || ( $post_type !== $forum_before->post_type ) ) ) {
2076 + bbp_update_forum_id( $forum_id, $forum_after->post_parent );
2077 + }
2078 +
2079 + $statuses = bbp_get_countable_forum_statuses();
2080 + $was_counted = ( $post_type === $forum_before->post_type ) && in_array( $forum_before->post_status, $statuses, true );
2081 + $is_counted = ( $post_type === $forum_after->post_type ) && in_array( $forum_after->post_status, $statuses, true );
2082 +
2083 + // Include the previous parent when it formerly contained this subforum
2084 + $parent_ids = $was_counted
2085 + ? array( $forum_before->post_parent )
2086 + : array();
2087 +
2088 + // Include the new parent when it now contains this subforum
2089 + if ( $is_counted ) {
2090 + $parent_ids[] = $forum_after->post_parent;
2091 + }
2092 +
2093 + // Recount each affected parent once
2094 + foreach ( array_filter( array_unique( $parent_ids ) ) as $parent_id ) {
2095 + bbp_update_forum_subforum_count( $parent_id );
2096 + }
2097 +}
2098 +
2099 +/**
2100 + * Adjust the total topic count of a forum.
2101 + *
2102 + * @since 2.0.0 bbPress (r2464)
2103 + * @since 2.6.17 Optionally update ancestor forum totals.
2104 + *
1313 2105 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
1314 2106 * is a topic or a forum. If it's a topic, its parent,
1315 2107 * i.e. the forum is automatically retrieved.
1316 - * @param bool $total_count Optional. To return the total count or normal
1317 - * count?
1318 - * @uses bbp_get_forum_id() To get the forum id
1319 - * @uses bbp_forum_query_subforum_ids() To get the subforum ids
1320 - * @uses bbp_update_forum_topic_count() To update the forum topic count
1321 - * @uses bbp_forum_query_topic_ids() To get the forum topic ids
1322 - * @uses update_post_meta() To update the forum's topic count meta
1323 - * @uses apply_filters() Calls 'bbp_update_forum_topic_count' with the topic
1324 - * count and forum id
1325 - * @return int Forum topic count
2108 + * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2109 + * @return int Forum topic count.
1326 2110 */
1327 -function bbp_update_forum_topic_count( $forum_id = 0 ) {
1328 - $forum_id = bbp_get_forum_id( $forum_id );
2111 +function bbp_update_forum_topic_count( $forum_id = 0, $update_ancestors = false ) {
2112 + $forum_id = bbp_get_forum_id( $forum_id );
2113 + $old_total_topics = ( true === $update_ancestors )
2114 + ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count', true )
2115 + : 0;
1329 2116 $children_topic_count = 0;
2117 + $total_topics = 0;
1330 2118
1331 2119 // Loop through subforums and add together forum topic counts
1332 2120 $children = bbp_forum_query_subforum_ids( $forum_id );
1333 - if ( !empty( $children ) ) {
1334 - foreach ( (array) $children as $child ) {
2121 + if ( ! empty( $children ) ) {
2122 + foreach ( $children as $child ) {
1335 2123 $children_topic_count += bbp_update_forum_topic_count( $child ); // Recursive
1336 2124 }
1337 2125 }
1338 2126
1339 2127 // Get total topics for this forum
1340 - $topics = (int) count( bbp_forum_query_topic_ids( $forum_id ) );
2128 + $topics = bbp_get_public_child_count( $forum_id, bbp_get_topic_post_type() );
1341 2129
1342 2130 // Calculate total topics in this forum
1343 - $total_topics = $topics + $children_topic_count;
2131 + $total_topics = (int) ( $topics + $children_topic_count );
1344 2132
1345 2133 // Update the count
1346 - update_post_meta( $forum_id, '_bbp_topic_count', (int) $topics );
1347 - update_post_meta( $forum_id, '_bbp_total_topic_count', (int) $total_topics );
2134 + update_post_meta( $forum_id, '_bbp_topic_count', $topics );
2135 + update_post_meta( $forum_id, '_bbp_total_topic_count', $total_topics );
1348 2136
1349 - return (int) apply_filters( 'bbp_update_forum_topic_count', (int) $total_topics, $forum_id );
2137 + // Update ancestor total counts by the persisted difference
2138 + if ( true === $update_ancestors ) {
2139 + bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count', $total_topics - $old_total_topics );
2140 + }
2141 +
2142 + // Filter & return
2143 + return (int) apply_filters( 'bbp_update_forum_topic_count', $total_topics, $forum_id );
1350 2144 }
1351 2145
1352 2146 /**
1353 - * Adjust the total hidden topic count of a forum (hidden includes trashed and spammed topics)
2147 + * Adjust the total hidden topic count of a forum (hidden includes trashed,
2148 + * spammed and pending topics).
1354 2149 *
1355 - * @since bbPress (r2888)
2150 + * @since 2.0.0 bbPress (r2888)
2151 + * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
2152 + * @since 2.6.17 Optionally update ancestor forum totals.
1356 2153 *
1357 - * @param int $forum_id Optional. Topic id to update
1358 - * @param int $topic_count Optional. Set the topic count manually
1359 - * @uses bbp_is_topic() To check if the supplied id is a topic
1360 - * @uses bbp_get_topic_id() To get the topic id
1361 - * @uses bbp_get_topic_forum_id() To get the topic forum id
1362 - * @uses bbp_get_forum_id() To get the forum id
1363 - * @uses wpdb::prepare() To prepare our sql query
1364 - * @uses wpdb::get_col() To execute our query and get the column back
1365 - * @uses update_post_meta() To update the forum hidden topic count meta
1366 - * @uses apply_filters() Calls 'bbp_update_forum_topic_count_hidden' with the
1367 - * hidden topic count and forum id
1368 - * @return int Topic hidden topic count
2154 + * @param int $forum_id Optional. Topic id to update.
2155 + * @param int $topic_count Optional. Set the topic count manually.
2156 + * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2157 + *
2158 + * @return int Topic hidden topic count.
1369 2159 */
1370 -function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = 0 ) {
1371 - global $wpdb;
2160 +function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = false, $update_ancestors = false ) {
1372 2161
1373 2162 // If topic_id was passed as $forum_id, then get its forum
1374 2163 if ( bbp_is_topic( $forum_id ) ) {
1375 2164 $topic_id = bbp_get_topic_id( $forum_id );
@@ -1379,52 +2168,94 @@
1379 2168 } else {
1380 2169 $forum_id = bbp_get_forum_id( $forum_id );
1381 2170 }
1382 2171
2172 + $children_topic_count = 0;
2173 + $total_topics = 0;
2174 + $old_total_topics = ( true === $update_ancestors )
2175 + ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count_hidden', true )
2176 + : 0;
2177 +
1383 2178 // Can't update what isn't there
1384 - if ( !empty( $forum_id ) ) {
2179 + if ( ! empty( $forum_id ) ) {
1385 2180
2181 + // Loop through children and add together hidden topic counts
2182 + $children = bbp_forum_query_subforum_ids( $forum_id );
2183 + if ( ! empty( $children ) ) {
2184 + foreach ( (array) $children as $child ) {
2185 + bbp_update_forum_topic_count_hidden( $child );
2186 + $children_topic_count += bbp_get_forum_topic_count_hidden( $child, true, true );
2187 + }
2188 + }
2189 +
1386 2190 // Get topics of forum
1387 - if ( empty( $topic_count ) )
1388 - $topic_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';", $forum_id, bbp_get_topic_post_type() ) );
2191 + if ( ! is_int( $topic_count ) ) {
2192 + $query = new WP_Query(
2193 + array(
2194 + 'fields' => 'ids',
2195 + 'post_parent' => $forum_id,
2196 + 'post_status' => bbp_get_non_public_topic_statuses(),
2197 + 'post_type' => bbp_get_topic_post_type(),
2198 + 'posts_per_page' => -1,
1389 2199
1390 - // Update the count
1391 - update_post_meta( $forum_id, '_bbp_topic_count_hidden', (int) $topic_count );
2200 + // Performance
2201 + 'nopaging' => true,
2202 + 'suppress_filters' => true,
2203 + 'update_post_term_cache' => false,
2204 + 'update_post_meta_cache' => false,
2205 + 'ignore_sticky_posts' => true,
2206 + 'no_found_rows' => true
2207 + )
2208 + );
2209 +
2210 + $topic_count = $query->post_count;
2211 +
2212 + unset( $query );
2213 + }
2214 +
2215 + $topic_count = (int) $topic_count;
2216 + $total_topics = (int) ( $topic_count + $children_topic_count );
2217 +
2218 + // Update the counts
2219 + update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count );
2220 + update_post_meta( $forum_id, '_bbp_total_topic_count_hidden', $total_topics );
2221 +
2222 + // Update ancestor total counts by the persisted difference
2223 + if ( true === $update_ancestors ) {
2224 + bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count_hidden', $total_topics - $old_total_topics );
2225 + }
1392 2226 }
1393 2227
1394 - return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', (int) $topic_count, $forum_id );
2228 + // Filter & return
2229 + return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', $topic_count, $forum_id );
1395 2230 }
1396 2231
1397 2232 /**
1398 - * Adjust the total reply count of a forum
2233 + * Adjust the total reply count of a forum.
1399 2234 *
1400 - * @since bbPress (r2464)
2235 + * @since 2.0.0 bbPress (r2464)
2236 + * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects.
2237 + * @since 2.6.17 Count replies only when their parent topics are public.
2238 + * @since 2.6.17 Optionally update ancestor forum totals.
1401 2239 *
1402 - * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
2240 + * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
1403 2241 * is a topic or a forum. If it's a topic, its parent,
1404 2242 * i.e. the forum is automatically retrieved.
1405 - * @param bool $total_count Optional. To return the total count or normal
1406 - * count?
1407 - * @uses bbp_get_forum_id() To get the forum id
1408 - * @uses bbp_forum_query_subforum_ids() To get the subforum ids
1409 - * @uses bbp_update_forum_reply_count() To update the forum reply count
1410 - * @uses bbp_forum_query_topic_ids() To get the forum topic ids
1411 - * @uses wpdb::prepare() To prepare the sql statement
1412 - * @uses wpdb::get_var() To execute the query and get the var back
1413 - * @uses update_post_meta() To update the forum's reply count meta
1414 - * @uses apply_filters() Calls 'bbp_update_forum_topic_count' with the reply
1415 - * count and forum id
1416 - * @return int Forum reply count
2243 + * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2244 + *
2245 + * @return int Forum reply count.
1417 2246 */
1418 -function bbp_update_forum_reply_count( $forum_id = 0 ) {
1419 - global $wpdb;
2247 +function bbp_update_forum_reply_count( $forum_id = 0, $update_ancestors = false ) {
1420 2248
1421 - $forum_id = bbp_get_forum_id( $forum_id );
2249 + $forum_id = bbp_get_forum_id( $forum_id );
2250 + $old_total_replies = ( true === $update_ancestors )
2251 + ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count', true )
2252 + : 0;
1422 2253 $children_reply_count = 0;
1423 2254
1424 2255 // Loop through children and add together forum reply counts
1425 2256 $children = bbp_forum_query_subforum_ids( $forum_id );
1426 - if ( !empty( $children ) ) {
2257 + if ( ! empty( $children ) ) {
1427 2258 foreach ( (array) $children as $child ) {
1428 2259 $children_reply_count += bbp_update_forum_reply_count( $child );
1429 2260 }
1430 2261 }
@@ -1429,25 +2260,109 @@
1429 2260 }
1430 2261 }
1431 2262
1432 2263 // Don't count replies if the forum is a category
1433 - $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1434 - if ( !empty( $topic_ids ) )
1435 - $reply_count = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent IN ( " . join( ',', $topic_ids ) . " ) AND post_status = '%s' AND post_type = '%s';", bbp_get_public_status_id(), bbp_get_reply_post_type() ) );
1436 - else
2264 + if ( bbp_is_forum_category( $forum_id ) ) {
1437 2265 $reply_count = 0;
1438 2266
2267 + // Count public replies whose parent topics are also public
2268 + } else {
2269 + $bbp_db = bbp_db();
2270 + $reply_statuses = bbp_get_public_reply_statuses();
2271 + $topic_statuses = bbp_get_public_topic_statuses();
2272 +
2273 + if ( empty( $reply_statuses ) || empty( $topic_statuses ) ) {
2274 + $reply_count = 0;
2275 + } else {
2276 + $reply_placeholders = implode( ', ', array_fill( 0, count( $reply_statuses ), '%s' ) );
2277 + $topic_placeholders = implode( ', ', array_fill( 0, count( $topic_statuses ), '%s' ) );
2278 + $sql = "SELECT COUNT(*) FROM {$bbp_db->posts} AS replies
2279 + INNER JOIN {$bbp_db->posts} AS topics ON replies.post_parent = topics.ID
2280 + WHERE topics.post_parent = %d
2281 + AND topics.post_type = %s
2282 + AND topics.post_status IN ({$topic_placeholders})
2283 + AND replies.post_type = %s
2284 + AND replies.post_status IN ({$reply_placeholders})";
2285 + $query = $bbp_db->prepare(
2286 + $sql,
2287 + array_merge(
2288 + array( $forum_id, bbp_get_topic_post_type() ),
2289 + $topic_statuses,
2290 + array( bbp_get_reply_post_type() ),
2291 + $reply_statuses
2292 + )
2293 + );
2294 + $reply_count = bbp_number_not_negative( $bbp_db->get_var( $query ) );
2295 + }
2296 + }
2297 +
1439 2298 // Calculate total replies in this forum
1440 - $total_replies = (int) $reply_count + $children_reply_count;
2299 + $total_replies = (int) ( $reply_count + $children_reply_count );
1441 2300
1442 - // Update the count
1443 - update_post_meta( $forum_id, '_bbp_reply_count', (int) $reply_count );
1444 - update_post_meta( $forum_id, '_bbp_total_reply_count', (int) $total_replies );
2301 + // Update the counts
2302 + update_post_meta( $forum_id, '_bbp_reply_count', $reply_count );
2303 + update_post_meta( $forum_id, '_bbp_total_reply_count', $total_replies );
1445 2304
1446 - return (int) apply_filters( 'bbp_update_forum_reply_count', (int) $total_replies, $forum_id );
2305 + // Update ancestor total counts by the persisted difference
2306 + if ( true === $update_ancestors ) {
2307 + bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count', $total_replies - $old_total_replies );
2308 + }
2309 +
2310 + // Filter & return
2311 + return (int) apply_filters( 'bbp_update_forum_reply_count', $total_replies, $forum_id );
1447 2312 }
1448 2313
1449 2314 /**
2315 + * Adjust the total hidden reply count of a forum.
2316 + *
2317 + * @since 2.6.0 bbPress (r6922)
2318 + * @since 2.6.17 Optionally update ancestor forum totals.
2319 + *
2320 + * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
2321 + * is a topic or a forum. If it's a topic, its parent,
2322 + * i.e. the forum is automatically retrieved.
2323 + * @param bool $update_ancestors Optional. Whether to update ancestor totals.
2324 + *
2325 + * @return int Forum reply count.
2326 + */
2327 +function bbp_update_forum_reply_count_hidden( $forum_id = 0, $update_ancestors = false ) {
2328 +
2329 + $forum_id = bbp_get_forum_id( $forum_id );
2330 + $old_total_replies = ( true === $update_ancestors )
2331 + ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count_hidden', true )
2332 + : 0;
2333 + $children_reply_count = 0;
2334 +
2335 + // Loop through children and add together forum reply counts
2336 + $children = bbp_forum_query_subforum_ids( $forum_id );
2337 + if ( ! empty( $children ) ) {
2338 + foreach ( (array) $children as $child ) {
2339 + $children_reply_count += bbp_update_forum_reply_count_hidden( $child );
2340 + }
2341 + }
2342 +
2343 + // Don't count replies if the forum is a category
2344 + $reply_count = ! bbp_is_forum_category( $forum_id )
2345 + ? bbp_get_non_public_child_count( $forum_id, bbp_get_reply_post_type() )
2346 + : 0;
2347 +
2348 + // Calculate total replies in this forum
2349 + $total_replies = (int) ( $reply_count + $children_reply_count );
2350 +
2351 + // Update the counts
2352 + update_post_meta( $forum_id, '_bbp_reply_count_hidden', $reply_count );
2353 + update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', $total_replies );
2354 +
2355 + // Update ancestor total counts by the persisted difference
2356 + if ( true === $update_ancestors ) {
2357 + bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count_hidden', $total_replies - $old_total_replies );
2358 + }
2359 +
2360 + // Filter & return
2361 + return (int) apply_filters( 'bbp_update_forum_reply_count_hidden', $total_replies, $forum_id );
2362 +}
2363 +
2364 +/**
1450 2365 * Updates the counts of a forum.
1451 2366 *
1452 2367 * This calls a few internal functions that all run manual queries against the
1453 2368 * database to get their results. As such, this function can be costly to run
@@ -1452,69 +2367,221 @@
1452 2367 * This calls a few internal functions that all run manual queries against the
1453 2368 * database to get their results. As such, this function can be costly to run
1454 2369 * but is necessary to keep everything accurate.
1455 2370 *
1456 - * @since bbPress (r2908)
2371 + * @since 2.0.0 bbPress (r2908)
1457 2372 *
1458 - * @param mixed $args Supports these arguments:
2373 + * @param array $args Supports these arguments:
1459 2374 * - forum_id: Forum id
1460 2375 * - last_topic_id: Last topic id
1461 2376 * - last_reply_id: Last reply id
1462 2377 * - last_active_id: Last active post id
1463 2378 * - last_active_time: last active time
1464 - * @uses bbp_update_forum_last_topic_id() To update the forum last topic id
1465 - * @uses bbp_update_forum_last_reply_id() To update the forum last reply id
1466 - * @uses bbp_update_forum_last_active_id() To update the last active post id
1467 - * @uses get_post_field() To get the post date of the last active id
1468 - * @uses bbp_update_forum_last_active_time() To update the last active time
1469 - * @uses bbp_update_forum_subforum_count() To update the subforum count
1470 - * @uses bbp_update_forum_topic_count() To update the forum topic count
1471 - * @uses bbp_update_forum_reply_count() To update the forum reply count
1472 - * @uses bbp_update_forum_topic_count_hidden() To update the hidden topic count
1473 2379 */
1474 -function bbp_update_forum( $args = '' ) {
1475 - $defaults = array(
1476 - 'forum_id' => 0,
1477 - 'post_parent' => 0,
1478 - 'last_topic_id' => 0,
1479 - 'last_reply_id' => 0,
1480 - 'last_active_id' => 0,
1481 - 'last_active_time' => 0,
1482 - 'last_active_status' => bbp_get_public_status_id()
2380 +function bbp_update_forum( $args = array() ) {
2381 +
2382 + // Parse arguments against default values
2383 + $r = bbp_parse_args(
2384 + $args,
2385 + array(
2386 + 'forum_id' => 0,
2387 + 'post_parent' => 0,
2388 + 'last_topic_id' => 0,
2389 + 'last_reply_id' => 0,
2390 + 'last_active_id' => 0,
2391 + 'last_active_time' => 0,
2392 + 'last_active_status' => bbp_get_public_status_id()
2393 + ),
2394 + 'update_forum'
1483 2395 );
1484 - $r = bbp_parse_args( $args, $defaults, 'update_forum' );
1485 - extract( $r );
1486 2396
2397 + // Update the forum parent
2398 + bbp_update_forum_id( $r['forum_id'], $r['post_parent'] );
2399 +
1487 2400 // Last topic and reply ID's
1488 - bbp_update_forum_last_topic_id( $forum_id, $last_topic_id );
1489 - bbp_update_forum_last_reply_id( $forum_id, $last_reply_id );
2401 + bbp_update_forum_last_topic_id( $r['forum_id'], $r['last_topic_id'] );
2402 + bbp_update_forum_last_reply_id( $r['forum_id'], $r['last_reply_id'] );
1490 2403
1491 2404 // Active dance
1492 - $last_active_id = bbp_update_forum_last_active_id( $forum_id, $last_active_id );
2405 + $r['last_active_id'] = bbp_update_forum_last_active_id( $r['forum_id'], $r['last_active_id'] );
1493 2406
1494 2407 // If no active time was passed, get it from the last_active_id
1495 - if ( empty( $last_active_time ) )
1496 - $last_active_time = get_post_field( 'post_date', $last_active_id );
2408 + if ( empty( $r['last_active_time'] ) ) {
2409 + $r['last_active_time'] = get_post_field( 'post_date', $r['last_active_id'] );
2410 + }
1497 2411
1498 - if ( bbp_get_public_status_id() == $last_active_status ) {
1499 - bbp_update_forum_last_active_time( $forum_id, $last_active_time );
2412 + if ( bbp_get_public_status_id() === $r['last_active_status'] ) {
2413 + bbp_update_forum_last_active_time( $r['forum_id'], $r['last_active_time'] );
1500 2414 }
1501 2415
1502 - // Counts
1503 - bbp_update_forum_subforum_count ( $forum_id );
1504 - bbp_update_forum_reply_count ( $forum_id );
1505 - bbp_update_forum_topic_count ( $forum_id );
1506 - bbp_update_forum_topic_count_hidden( $forum_id );
2416 + // Subforum counts are updated on bbp_transition_post_status,
2417 + // bbp_post_updated, and bbp_deleted_forum.
1507 2418
1508 - // Update the parent forum if one was passed
1509 - if ( !empty( $post_parent ) && is_numeric( $post_parent ) ) {
1510 - bbp_update_forum( array(
1511 - 'forum_id' => $post_parent,
1512 - 'post_parent' => get_post_field( 'post_parent', $post_parent )
1513 - ) );
2419 + // Only update topic count if we've deleted a topic
2420 + if ( in_array( current_filter(), array( 'bbp_deleted_topic', 'save_post' ), true ) ) {
2421 + bbp_update_forum_reply_count( $r['forum_id'] );
2422 + bbp_update_forum_topic_count( $r['forum_id'] );
2423 + bbp_update_forum_topic_count_hidden( $r['forum_id'] );
2424 + bbp_update_forum_reply_count_hidden( $r['forum_id'] );
1514 2425 }
2426 +
2427 + // Update parent forums
2428 + bbp_update_forum_walker( $r );
2429 +
2430 + // Bump the custom query cache
2431 + wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
1515 2432 }
1516 2433
2434 +/**
2435 + * Walk up the forum hierarchy and update parent forums.
2436 + *
2437 + * @since 2.6.17
2438 + *
2439 + * @param array $args Parsed arguments from bbp_update_forum().
2440 + * @return false|null False if there is no parent forum, otherwise null.
2441 + */
2442 +function bbp_update_forum_walker( $args = array() ) {
2443 +
2444 + // Bail if this forum has no parent
2445 + if ( empty( $args['post_parent'] ) ) {
2446 + return false;
2447 + }
2448 +
2449 + // Update the parent and continue walking
2450 + $args['forum_id'] = bbp_get_forum_id( $args['post_parent'] );
2451 +
2452 + // Bail if the parent is not a forum
2453 + if ( empty( $args['forum_id'] ) ) {
2454 + return false;
2455 + }
2456 +
2457 + $args['post_parent'] = get_post_field( 'post_parent', $args['forum_id'] );
2458 +
2459 + bbp_update_forum( $args );
2460 +}
2461 +
2462 +/** Helpers *******************************************************************/
2463 +
2464 +/**
2465 + * Return an associative array of available topic statuses
2466 + *
2467 + * Developers note: these statuses are actually stored as meta data, and
2468 + * Visibilities are stored in post_status.
2469 + *
2470 + * @since 2.4.0 bbPress (r5059)
2471 + *
2472 + * @param int $forum_id Optional. Forum id.
2473 + *
2474 + * @return array
2475 + */
2476 +function bbp_get_forum_statuses( $forum_id = 0 ) {
2477 +
2478 + // Filter & return
2479 + return (array) apply_filters(
2480 + 'bbp_get_forum_statuses',
2481 + array(
2482 + 'open' => _x( 'Open', 'Open the forum', 'bbpress' ),
2483 + 'closed' => _x( 'Closed', 'Close the forum', 'bbpress' )
2484 + ),
2485 + $forum_id
2486 + );
2487 +}
2488 +
2489 +/**
2490 + * Return an associative array of forum types
2491 + *
2492 + * @since 2.4.0 bbPress (r5059)
2493 + *
2494 + * @param int $forum_id Optional. Forum id.
2495 + *
2496 + * @return array
2497 + */
2498 +function bbp_get_forum_types( $forum_id = 0 ) {
2499 +
2500 + // Filter & return
2501 + return (array) apply_filters(
2502 + 'bbp_get_forum_types',
2503 + array(
2504 + 'forum' => _x( 'Forum', 'Forum accepts new topics', 'bbpress' ),
2505 + 'category' => _x( 'Category', 'Forum is a category', 'bbpress' )
2506 + ),
2507 + $forum_id
2508 + );
2509 +}
2510 +
2511 +/**
2512 + * Return an associative array of forum visibility
2513 + *
2514 + * Developers note: these visibilities are actually stored in post_status, and
2515 + * Statuses are stored in meta data.
2516 + *
2517 + * @since 2.4.0 bbPress (r5059)
2518 + *
2519 + * @param int $forum_id Optional. Forum id.
2520 + *
2521 + * @return array
2522 + */
2523 +function bbp_get_forum_visibilities( $forum_id = 0 ) {
2524 +
2525 + // Filter & return
2526 + return (array) apply_filters(
2527 + 'bbp_get_forum_visibilities',
2528 + array(
2529 + bbp_get_public_status_id() => _x( 'Public', 'Make forum public', 'bbpress' ),
2530 + bbp_get_private_status_id() => _x( 'Private', 'Make forum private', 'bbpress' ),
2531 + bbp_get_hidden_status_id() => _x( 'Hidden', 'Make forum hidden', 'bbpress' )
2532 + ),
2533 + $forum_id
2534 + );
2535 +}
2536 +
2537 +/**
2538 + * Return array of public forum statuses.
2539 + *
2540 + * @since 2.6.0 bbPress (r6921)
2541 + *
2542 + * @return array
2543 + */
2544 +function bbp_get_public_forum_statuses() {
2545 + $statuses = array(
2546 + bbp_get_public_status_id()
2547 + );
2548 +
2549 + // Filter & return
2550 + return (array) apply_filters( 'bbp_get_public_forum_statuses', $statuses );
2551 +}
2552 +
2553 +/**
2554 + * Return array of non-public forum statuses.
2555 + *
2556 + * @since 2.6.0 bbPress (r6921)
2557 + *
2558 + * @return array
2559 + */
2560 +function bbp_get_non_public_forum_statuses() {
2561 + $statuses = array(
2562 + bbp_get_private_status_id(),
2563 + bbp_get_hidden_status_id()
2564 + );
2565 +
2566 + // Filter & return
2567 + return (array) apply_filters( 'bbp_get_non_public_forum_statuses', $statuses );
2568 +}
2569 +
2570 +/**
2571 + * Return forum statuses included in forum and subforum counts.
2572 + *
2573 + * @since 2.6.17
2574 + *
2575 + * @return array
2576 + */
2577 +function bbp_get_countable_forum_statuses() {
2578 + $statuses = array_values( array_unique( array_merge( bbp_get_public_forum_statuses(), bbp_get_non_public_forum_statuses() ) ) );
2579 +
2580 + // Filter & return
2581 + return (array) apply_filters( 'bbp_get_countable_forum_statuses', $statuses );
2582 +}
2583 +
1517 2584 /** Queries *******************************************************************/
1518 2585
1519 2586 /**
1520 2587 * Returns the hidden forum ids
@@ -1520,18 +2587,18 @@
1520 2587 * Returns the hidden forum ids
1521 2588 *
1522 2589 * Only hidden forum ids are returned. Public and private ids are not.
1523 2590 *
1524 - * @since bbPress (r3007)
1525 - *
1526 - * @uses get_option() Returns the unserialized array of hidden forum ids
1527 - * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
1528 - * and forum id
2591 + * @since 2.0.0 bbPress (r3007)
1529 2592 */
1530 2593 function bbp_get_hidden_forum_ids() {
1531 - $forum_ids = get_option( '_bbp_hidden_forums', array() );
2594 + $forum_ids = get_option( '_bbp_hidden_forums', array() );
2595 + $forum_ids = ! empty( $forum_ids )
2596 + ? wp_parse_id_list( $forum_ids )
2597 + : array();
1532 2598
1533 - return apply_filters( 'bbp_get_hidden_forum_ids', (array) $forum_ids );
2599 + // Filter & return
2600 + return (array) apply_filters( 'bbp_get_hidden_forum_ids', $forum_ids );
1534 2601 }
1535 2602
1536 2603 /**
1537 2604 * Returns the private forum ids
@@ -1537,275 +2604,521 @@
1537 2604 * Returns the private forum ids
1538 2605 *
1539 2606 * Only private forum ids are returned. Public and hidden ids are not.
1540 2607 *
1541 - * @since bbPress (r3007)
1542 - *
1543 - * @uses get_option() Returns the unserialized array of private forum ids
1544 - * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
1545 - * and forum id
2608 + * @since 2.0.0 bbPress (r3007)
1546 2609 */
1547 2610 function bbp_get_private_forum_ids() {
1548 - $forum_ids = get_option( '_bbp_private_forums', array() );
2611 + $forum_ids = get_option( '_bbp_private_forums', array() );
2612 + $forum_ids = ! empty( $forum_ids )
2613 + ? wp_parse_id_list( $forum_ids )
2614 + : array();
1549 2615
1550 - return apply_filters( 'bbp_get_private_forum_ids', (array) $forum_ids );
2616 + // Filter & return
2617 + return (array) apply_filters( 'bbp_get_private_forum_ids', $forum_ids );
1551 2618 }
1552 2619
1553 2620 /**
1554 - * Returns a meta_query that either includes or excludes hidden forum IDs
1555 - * from a query.
2621 + * Returns the forum IDs that should be excluded from various views & queries,
2622 + * based on the current user's capabilities.
1556 2623 *
1557 - * @since bbPress (r3291)
2624 + * These results are automatically filtered by bbp_allow_forums_of_user(), to
2625 + * allow per-forum moderators to see forums that would otherwise be private or
2626 + * hidden to them.
1558 2627 *
1559 - * @param string Optional. The type of value to return. (string|array|meta_query)
2628 + * If you have a need to filter these results based on your own custom
2629 + * engagements API usages, please see: bbp_allow_forums_of_user()
1560 2630 *
1561 - * @uses is_super_admin()
1562 - * @uses bbp_get_hidden_forum_ids()
1563 - * @uses bbp_get_private_forum_ids()
1564 - * @uses apply_filters()
2631 + * @since 2.6.0 bbPress (r6425)
2632 + *
2633 + * @return array Forum IDs to exclude, or an empty array
1565 2634 */
1566 -function bbp_exclude_forum_ids( $type = 'string' ) {
2635 +function bbp_get_excluded_forum_ids() {
1567 2636
1568 - // Setup arrays
1569 - $private = $hidden = $meta_query = $forum_ids = array();
2637 + // Private forums
2638 + $private = ! current_user_can( 'read_private_forums' )
2639 + ? bbp_get_private_forum_ids()
2640 + : array();
1570 2641
1571 - // Default return value
1572 - switch ( $type ) {
1573 - case 'string' :
1574 - $retval = '';
1575 - break;
2642 + // Hidden forums
2643 + $hidden = ! current_user_can( 'read_hidden_forums' )
2644 + ? bbp_get_hidden_forum_ids()
2645 + : array();
1576 2646
1577 - case 'array' :
1578 - $retval = array();
1579 - break;
2647 + // Merge private & hidden forums together, and remove any empties
2648 + $forum_ids = ( ! empty( $private ) || ! empty( $hidden ) )
2649 + ? array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) )
2650 + : array();
1580 2651
1581 - case 'meta_query' :
1582 - $retval = array( array() ) ;
1583 - break;
2652 + // Include descendants of private and hidden forums
2653 + $parents = $forum_ids;
2654 + while ( ! empty( $parents ) ) {
2655 + $parent_id = array_shift( $parents );
2656 +
2657 + foreach ( bbp_forum_query_subforum_ids( $parent_id ) as $forum_id ) {
2658 + if ( ! in_array( $forum_id, $forum_ids, true ) ) {
2659 + $forum_ids[] = $forum_id;
2660 + $parents[] = $forum_id;
2661 + }
2662 + }
1584 2663 }
1585 -
1586 - // Exclude for everyone but super admins
1587 - if ( !is_super_admin() ) {
1588 2664
1589 - // Private forums
1590 - if ( !current_user_can( 'read_private_forums' ) )
1591 - $private = bbp_get_private_forum_ids();
2665 + // Normalize forum IDs after adding descendants
2666 + $forum_ids = wp_parse_id_list( $forum_ids );
1592 2667
1593 - // Hidden forums
1594 - if ( !current_user_can( 'read_hidden_forums' ) )
1595 - $hidden = bbp_get_hidden_forum_ids();
2668 + // Filter & return
2669 + return (array) apply_filters( 'bbp_get_excluded_forum_ids', $forum_ids, $private, $hidden );
2670 +}
1596 2671
1597 - // Merge private and hidden forums together
1598 - $forum_ids = (array) array_filter( array_merge( $private, $hidden ) );
2672 +/**
2673 + * Returns a meta_query that either includes or excludes hidden forum IDs
2674 + * from a query.
2675 + *
2676 + * @since 2.0.0 bbPress (r3291)
2677 + *
2678 + * @param string Optional. The type of value to return. (string|array|meta_query)
2679 + */
2680 +function bbp_exclude_forum_ids( $type = 'string' ) {
1599 2681
1600 - // There are forums that need to be excluded
1601 - if ( !empty( $forum_ids ) ) {
2682 + // Setup arrays
2683 + $forum_ids = array();
1602 2684
1603 - switch ( $type ) {
2685 + // Types
2686 + $types = array(
2687 + 'array' => array(),
2688 + 'string' => '',
2689 + 'meta_query' => array()
2690 + );
1604 2691
1605 - // Separate forum ID's into a comma separated string
1606 - case 'string' :
1607 - $retval = implode( ',', $forum_ids );
1608 - break;
2692 + // Exclude for everyone but keymasters
2693 + if ( ! bbp_is_user_keymaster() ) {
1609 2694
1610 - // Use forum_ids array
1611 - case 'array' :
1612 - $retval = $forum_ids;
1613 - break;
2695 + // Get forum IDs to exclude
2696 + $forum_ids = bbp_get_excluded_forum_ids();
1614 2697
1615 - // Build a meta_query
1616 - case 'meta_query' :
1617 - $retval = array(
1618 - 'key' => '_bbp_forum_id',
1619 - 'value' => implode( ',', $forum_ids ),
1620 - 'type' => 'numeric',
1621 - 'compare' => ( 1 < count( $forum_ids ) ) ? 'NOT IN' : '!='
1622 - );
1623 - break;
1624 - }
2698 + // Store return values in static types array
2699 + if ( ! empty( $forum_ids ) ) {
2700 +
2701 + // Setup types
2702 + $types['array'] = $forum_ids;
2703 + $types['string'] = implode( ',', $forum_ids );
2704 + $types['meta_query'] = array(
2705 + 'key' => '_bbp_forum_id',
2706 + 'value' => $forum_ids,
2707 + 'type' => 'NUMERIC',
2708 + 'compare' => 'NOT IN'
2709 + );
1625 2710 }
1626 2711 }
1627 2712
1628 - // Filter and return the results
2713 + // There are forums that need to be excluded
2714 + $retval = $types[ $type ];
2715 +
2716 + // Filter & return
1629 2717 return apply_filters( 'bbp_exclude_forum_ids', $retval, $forum_ids, $type );
1630 2718 }
1631 2719
1632 2720 /**
1633 - * Adjusts topic and reply queries to exclude items that might be contained
1634 - * inside hidden or private forums that the user does not have the capability
1635 - * to view.
2721 + * Adjusts forum, topic, and reply queries to exclude items that might be
2722 + * contained inside hidden or private forums that the user does not have the
2723 + * capability to view.
1636 2724 *
1637 - * @since bbPress (r3291)
2725 + * Doing it with an action allows us to trap all WP_Query's rather than needing
2726 + * to hardcode this logic into each query. It also protects forum content for
2727 + * plugins that might be doing their own queries.
1638 2728 *
2729 + * @since 2.0.0 bbPress (r3291)
2730 + *
1639 2731 * @param WP_Query $posts_query
1640 2732 *
1641 - * @uses apply_filters()
1642 - * @uses bbp_exclude_forum_ids()
1643 - * @uses bbp_get_topic_post_type()
1644 - * @uses bbp_get_reply_post_type()
1645 2733 * @return WP_Query
1646 2734 */
1647 -function bbp_pre_get_posts_exclude_forums( $posts_query ) {
2735 +function bbp_pre_get_posts_normalize_forum_visibility( $posts_query = null ) {
1648 2736
1649 2737 // Bail if all forums are explicitly allowed
1650 - if ( true === apply_filters( 'bbp_include_all_forums', $posts_query ) )
2738 + if ( true === apply_filters( 'bbp_include_all_forums', false, $posts_query ) ) {
1651 2739 return;
2740 + }
1652 2741
1653 2742 // Bail if $posts_query is not an object or of incorrect class
1654 - if ( !is_object( $posts_query ) || !is_a( $posts_query, 'WP_Query' ) )
2743 + if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
1655 2744 return;
2745 + }
1656 2746
1657 - // Bail if filters are suppressed on this query
1658 - if ( true == $posts_query->get( 'suppress_filters' ) )
2747 + // Bail to prevent unintended wp-admin post_row overrides
2748 + if ( is_admin() && isset( $_REQUEST['post_status'] ) ) {
1659 2749 return;
2750 + }
1660 2751
1661 - // Only exclude forums on bbPress queries
1662 - switch ( $posts_query->get( 'post_type' ) ) {
2752 + // Get the raw query post types.
2753 + $post_type_query_var = $posts_query->get( 'post_type' );
2754 + $post_types = bbp_get_string_array_values( $post_type_query_var );
1663 2755
1664 - // Forums
1665 - case bbp_get_forum_post_type() :
2756 + // Resolve the post types included in "any" and implicit search queries.
2757 + if ( ( 'any' === $post_type_query_var ) || ( empty( $post_types ) && $posts_query->is_search() ) ) {
2758 + $post_types = get_post_types( array( 'exclude_from_search' => false ) );
2759 + }
1666 2760
1667 - // Prevent accidental wp-admin post_row override
1668 - if ( is_admin() && isset( $_REQUEST['post_status'] ) )
1669 - break;
2761 + // Bail if no post types to normalize
2762 + if ( empty( $post_types ) ) {
2763 + return;
2764 + }
1670 2765
1671 - // Define local variable
1672 - $status = array();
2766 + // Compare queried post-types to supported post-types
2767 + $bbp_post_types = array_intersect( $post_types, bbp_get_post_types() );
1673 2768
1674 - // All users can see published forums
1675 - $status[] = bbp_get_public_status_id();
2769 + // Bail if no bbPress post type is being queried
2770 + if ( empty( $bbp_post_types ) ) {
2771 + return;
2772 + }
1676 2773
1677 - // Add bbp_get_private_status_id() if user is capable
1678 - if ( current_user_can( 'read_private_forums' ) ) {
1679 - $status[] = bbp_get_private_status_id();
2774 + // Bail if this query has already been normalized
2775 + if ( $posts_query->get( '_bbp_forum_visibility_normalized' ) ) {
2776 + return;
2777 + }
2778 +
2779 + // Mark this query as normalized
2780 + $posts_query->set( '_bbp_forum_visibility_normalized', true );
2781 +
2782 + // Separate non-bbPress post types from supported bbPress post types.
2783 + $non_bbp_post_types = array_diff( $post_types, $bbp_post_types );
2784 + $content_post_types = array_intersect(
2785 + $bbp_post_types,
2786 + array( bbp_get_topic_post_type(), bbp_get_reply_post_type() )
2787 + );
2788 +
2789 + /**
2790 + * Clause filters do not run when a query suppresses filters. Remove bbPress
2791 + * post types from mixed queries so protected content continues to fail closed
2792 + * without changing the requested non-bbPress post types.
2793 + */
2794 + if ( ! empty( $non_bbp_post_types ) && $posts_query->get( 'suppress_filters' ) ) {
2795 + $posts_query->set( 'post_type', array_values( $non_bbp_post_types ) );
2796 + return;
2797 + }
2798 +
2799 + // Get forums to exclude.
2800 + $forum_ids = bbp_exclude_forum_ids( 'array' );
2801 +
2802 + // Forums
2803 + if ( in_array( bbp_get_forum_post_type(), $post_types, true ) ) {
2804 + $content_post_statuses = array();
2805 +
2806 + /**
2807 + * Preserve the statuses requested for topics and replies before adding
2808 + * forum visibilities to a shared query. Without a post-type-aware status
2809 + * clause, private and hidden content inherits the broader forum statuses.
2810 + */
2811 + if ( ! empty( $content_post_types ) ) {
2812 + $content_post_statuses = bbp_get_string_array_values( $posts_query->get( 'post_status' ) );
2813 +
2814 + if ( empty( $content_post_statuses ) ) {
2815 + $content_post_statuses = bbp_get_public_topic_statuses();
2816 + } elseif ( in_array( 'any', $content_post_statuses, true ) ) {
2817 + // Match WordPress handling of an explicitly requested "any" status.
2818 + $content_post_statuses = get_post_stati( array( 'exclude_from_search' => false ) );
1680 2819 }
1681 2820
1682 - // Add bbp_get_hidden_status_id() if user is capable
1683 - if ( current_user_can( 'read_hidden_forums' ) ) {
1684 - $status[] = bbp_get_hidden_status_id();
2821 + $posts_query->set( '_bbp_forum_visibility_post_types', $content_post_types );
2822 + $posts_query->set( '_bbp_forum_visibility_post_statuses', $content_post_statuses );
2823 + }
2824 +
2825 + // Add all supported forum visibilities to bbPress-only queries.
2826 + if ( empty( $non_bbp_post_types ) ) {
2827 + $posts_query->set(
2828 + 'post_status',
2829 + array_unique(
2830 + array_merge(
2831 + array_keys( bbp_get_forum_visibilities() ),
2832 + $content_post_statuses
2833 + )
2834 + )
2835 + );
2836 + }
2837 +
2838 + // Excluding some forums
2839 + if ( ! empty( $forum_ids ) ) {
2840 +
2841 + /**
2842 + * WordPress ignores post__not_in when an explicit post ID is
2843 + * queried. Replace an inaccessible forum ID with an impossible
2844 + * inclusion so the restricted forum is not loaded into the query.
2845 + */
2846 + $forum_id = absint( $posts_query->get( 'p' ) );
2847 + if ( ! empty( $forum_id ) && in_array( $forum_id, $forum_ids, true ) ) {
2848 + $posts_query->set( 'p', 0 );
2849 + $posts_query->set( 'post__in', array( 0 ) );
1685 2850 }
1686 2851
1687 - // Implode and add the statuses
1688 - $posts_query->set( 'post_status', implode( ',', $status ) );
2852 + // Get any existing not-in queries
2853 + $not_in = (array) $posts_query->get( 'post__not_in', array() );
1689 2854
1690 - break;
2855 + // Add our not-in to existing
2856 + $not_in = wp_parse_id_list( array_merge( $not_in, $forum_ids ) );
1691 2857
1692 - // Topics
1693 - case bbp_get_topic_post_type() :
2858 + // Set the new not-in val
2859 + $posts_query->set( 'post__not_in', $not_in );
2860 + }
2861 + }
1694 2862
1695 - // Replies
1696 - case bbp_get_reply_post_type() :
2863 + // Bail if there are no forums to exclude.
2864 + if ( empty( $forum_ids ) ) {
2865 + return;
2866 + }
1697 2867
1698 - // Get forums to exclude
1699 - $forum_ids = bbp_exclude_forum_ids( 'meta_query' );
2868 + /**
2869 + * Mixed queries need a post-type-aware SQL clause. A meta query would use an
2870 + * inner join and unintentionally remove non-bbPress posts that do not have
2871 + * bbPress forum metadata.
2872 + */
2873 + if ( ! empty( $non_bbp_post_types ) ) {
2874 + $posts_query->set( '_bbp_forum_visibility_post_types', $content_post_types );
2875 + $posts_query->set( '_bbp_forum_visibility_forum_ids', $forum_ids );
2876 + return;
2877 + }
1700 2878
1701 - // Bail if no forums to exclude
1702 - if ( empty( $forum_ids ) )
1703 - return;
2879 + // Get forum meta query.
2880 + $forum_meta_query = bbp_exclude_forum_ids( 'meta_query' );
1704 2881
1705 - // Get any existing meta queries
1706 - $meta_query = $posts_query->get( 'meta_query' );
2882 + // Excluding some forums
2883 + if ( is_array( $forum_meta_query ) && ! empty( $forum_meta_query['key'] ) && ! empty( $forum_meta_query['value'] ) ) {
1707 2884
1708 - // Add our meta query to existing
1709 - $meta_query[] = $forum_ids;
2885 + // Get any existing meta queries
2886 + $meta_query = (array) $posts_query->get( 'meta_query', array() );
1710 2887
1711 - // Set the meta_query var
1712 - $posts_query->set( 'meta_query', $meta_query );
2888 + // Add our meta query to existing
2889 + $meta_query[] = $forum_meta_query;
1713 2890
1714 - break;
2891 + // Set the new meta_query val
2892 + $posts_query->set( 'meta_query', $meta_query );
1715 2893 }
1716 2894 }
1717 2895
1718 2896 /**
2897 + * Excludes protected bbPress content from mixed post-type queries.
2898 + *
2899 + * A normal meta query cannot scope its join to bbPress post types, causing
2900 + * unrelated WordPress posts and third-party post types without `_bbp_forum_id`
2901 + * metadata to be removed. This clause leaves forums and non-bbPress rows
2902 + * untouched while requiring topic and reply rows to have forum metadata that
2903 + * does not reference an excluded forum. Forums are excluded by ID before this
2904 + * clause runs.
2905 + *
2906 + * Queries with `suppress_filters` enabled are handled conservatively in
2907 + * bbp_pre_get_posts_normalize_forum_visibility(), because this filter will not
2908 + * run for those queries.
2909 + *
2910 + * @since 2.6.15 bbPress
2911 + *
2912 + * @param string $where SQL WHERE clause.
2913 + * @param WP_Query $posts_query WordPress posts query.
2914 + * @return string SQL WHERE clause.
2915 + */
2916 +function _bbp_forum_visibility_where( $where = '', $posts_query = null ) {
2917 +
2918 + // Bail if $posts_query is not an object or of incorrect class
2919 + if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
2920 + return $where;
2921 + }
2922 +
2923 + // Get the query-specific visibility constraints.
2924 + $post_types = bbp_get_string_array_values( $posts_query->get( '_bbp_forum_visibility_post_types' ) );
2925 + $post_statuses = bbp_get_string_array_values( $posts_query->get( '_bbp_forum_visibility_post_statuses' ) );
2926 + $forum_ids = wp_parse_id_list( $posts_query->get( '_bbp_forum_visibility_forum_ids' ) );
2927 +
2928 + // Bail if this query does not need a post-type-aware visibility clause.
2929 + if ( empty( $post_types ) || ( empty( $post_statuses ) && empty( $forum_ids ) ) ) {
2930 + return $where;
2931 + }
2932 +
2933 + // Get the database object.
2934 + $bbp_db = bbp_db();
2935 +
2936 + // Prepare post-type placeholders.
2937 + $post_type_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) );
2938 +
2939 + // Restrict topic and reply statuses in mixed forum queries.
2940 + if ( ! empty( $post_statuses ) ) {
2941 + $post_status_placeholders = implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) );
2942 + $status_values = array_merge( $post_types, $post_statuses );
2943 + $where .= $bbp_db->prepare(
2944 + " AND (
2945 + {$bbp_db->posts}.post_type NOT IN ({$post_type_placeholders})
2946 + OR {$bbp_db->posts}.post_status IN ({$post_status_placeholders})
2947 + )",
2948 + $status_values
2949 + );
2950 + }
2951 +
2952 + // Bail if there are no forum IDs to exclude.
2953 + if ( empty( $forum_ids ) ) {
2954 + return $where;
2955 + }
2956 +
2957 + // Prepare forum-ID placeholders and values.
2958 + $forum_id_placeholders = implode( ', ', array_fill( 0, count( $forum_ids ), '%d' ) );
2959 + $values = array_merge( $post_types, $forum_ids );
2960 +
2961 + /**
2962 + * Require topic and reply rows to have forum metadata, and exclude rows with
2963 + * forum metadata pointing at a forum the current user cannot view. All other
2964 + * rows bypass these checks and retain their original query behavior.
2965 + */
2966 + $visibility_where = $bbp_db->prepare(
2967 + " AND (
2968 + {$bbp_db->posts}.post_type NOT IN ({$post_type_placeholders})
2969 + OR (
2970 + EXISTS (
2971 + SELECT 1
2972 + FROM {$bbp_db->postmeta} AS bbp_forum_visibility_exists
2973 + WHERE bbp_forum_visibility_exists.post_id = {$bbp_db->posts}.ID
2974 + AND bbp_forum_visibility_exists.meta_key = '_bbp_forum_id'
2975 + )
2976 + AND NOT EXISTS (
2977 + SELECT 1
2978 + FROM {$bbp_db->postmeta} AS bbp_forum_visibility_excluded
2979 + WHERE bbp_forum_visibility_excluded.post_id = {$bbp_db->posts}.ID
2980 + AND bbp_forum_visibility_excluded.meta_key = '_bbp_forum_id'
2981 + AND CAST( bbp_forum_visibility_excluded.meta_value AS UNSIGNED ) IN ({$forum_id_placeholders})
2982 + )
2983 + )
2984 + )",
2985 + $values
2986 + );
2987 +
2988 + /**
2989 + * Filters the forum visibility SQL appended to mixed post-type queries.
2990 + *
2991 + * @since 2.6.15 bbPress
2992 + *
2993 + * @param string $visibility_where Forum visibility SQL clause.
2994 + * @param WP_Query $posts_query WordPress posts query.
2995 + * @param string[] $post_types bbPress post types protected by the clause.
2996 + * @param int[] $forum_ids Forum IDs excluded from the query.
2997 + */
2998 + $visibility_where = apply_filters(
2999 + 'bbp_forum_visibility_posts_where',
3000 + $visibility_where,
3001 + $posts_query,
3002 + $post_types,
3003 + $forum_ids
3004 + );
3005 +
3006 + // Append the visibility clause.
3007 + return $where . $visibility_where;
3008 +}
3009 +
3010 +/**
1719 3011 * Returns the forum's topic ids
1720 3012 *
1721 3013 * Only topics with published and closed statuses are returned
1722 3014 *
1723 - * @since bbPress (r2908)
3015 + * @since 2.0.0 bbPress (r2908)
1724 3016 *
1725 3017 * @param int $forum_id Forum id
1726 - * @uses bbp_get_topic_post_type() To get the topic post type
1727 - * @uses bbp_get_public_child_ids() To get the topic ids
1728 - * @uses apply_filters() Calls 'bbp_forum_query_topic_ids' with the topic ids
1729 - * and forum id
1730 3018 */
1731 3019 function bbp_forum_query_topic_ids( $forum_id ) {
1732 - $topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );
3020 + $topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );
1733 3021
1734 - return apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
3022 + // Filter & return
3023 + return (array) apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
1735 3024 }
1736 3025
1737 3026 /**
1738 - * Returns the forum's subforum ids
3027 + * Returns the forum's subforum ids.
1739 3028 *
1740 - * Only forums with published status are returned
3029 + * Only forums with countable statuses are returned.
1741 3030 *
1742 - * @since bbPress (r2908)
3031 + * @since 2.0.0 bbPress (r2908)
3032 + * @since 2.6.17 Restrict results to countable statuses instead of using
3033 + * bbp_get_all_child_ids().
1743 3034 *
1744 - * @param int $forum_id Forum id
1745 - * @uses bbp_get_forum_post_type() To get the forum post type
1746 - * @uses bbp_get_public_child_ids() To get the forum ids
1747 - * @uses apply_filters() Calls 'bbp_forum_query_subforum_ids' with the subforum
1748 - * ids and forum id
3035 + * @param int $forum_id Forum id.
1749 3036 */
1750 3037 function bbp_forum_query_subforum_ids( $forum_id ) {
1751 - $subforum_ids = bbp_get_public_child_ids( $forum_id, bbp_get_forum_post_type() );
1752 - //usort( $subforum_ids, '_bbp_forum_query_usort_subforum_ids' );
3038 + $forum_id = bbp_get_forum_id( $forum_id );
3039 + $statuses = bbp_get_countable_forum_statuses();
3040 + $subforum_ids = array();
1753 3041
1754 - return apply_filters( 'bbp_get_forum_subforum_ids', $subforum_ids, $forum_id );
1755 -}
3042 + // Query and cache countable subforums. The public child-ID helper excludes
3043 + // private and hidden forums, while the all-child helper includes trash, so
3044 + // neither existing helper represents the statuses counted here.
3045 + if ( ! empty( $forum_id ) && ! empty( $statuses ) ) {
3046 + $key = md5(
3047 + serialize(
3048 + array(
3049 + 'parent_id' => $forum_id,
3050 + 'post_type' => bbp_get_forum_post_type(),
3051 + 'post_status' => $statuses
3052 + )
3053 + )
3054 + );
3055 + $cache_key = "bbp_child_ids:{$key}:" . wp_cache_get_last_changed( 'bbpress_posts' );
3056 + $subforum_ids = wp_cache_get( $cache_key, 'bbpress_posts' );
1756 3057
1757 -/**
1758 - * Callback to sort forum ID's based on last active time
1759 - *
1760 - * @since bbPress (r3789)
1761 - * @param int $a First forum ID to compare
1762 - * @param int $b Second forum ID to compare
1763 - * @return Position change based on sort
1764 - */
1765 -function _bbp_forum_query_usort_subforum_ids( $a = 0, $b = 0 ) {
1766 - $ta = get_post_meta( $a, '_bbp_last_active_time', true );
1767 - $tb = get_post_meta( $b, '_bbp_last_active_time', true );
1768 - return ( $ta < $tb ) ? -1 : 1;
3058 + if ( false === $subforum_ids ) {
3059 + $bbp_db = bbp_db();
3060 + $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) );
3061 + $query = $bbp_db->prepare(
3062 + "SELECT ID FROM {$bbp_db->posts} WHERE post_parent = %d AND post_type = %s AND post_status IN ({$placeholders}) ORDER BY ID DESC",
3063 + array_merge( array( $forum_id, bbp_get_forum_post_type() ), $statuses )
3064 + );
3065 + $subforum_ids = (array) $bbp_db->get_col( $query );
3066 +
3067 + wp_cache_set( $cache_key, $subforum_ids, 'bbpress_posts' );
3068 + }
3069 + }
3070 +
3071 + // Filter & return
3072 + return (array) apply_filters( 'bbp_forum_query_subforum_ids', $subforum_ids, $forum_id );
1769 3073 }
1770 3074
1771 3075 /**
1772 3076 * Returns the forum's last reply id
1773 3077 *
1774 - * @since bbPress (r2908)
3078 + * @since 2.0.0 bbPress (r2908)
3079 + * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
1775 3080 *
1776 - * @param int $forum_id Forum id
1777 - * @param int $topic_ids Optional. Topic ids
1778 - * @uses wp_cache_get() To check for cache and retrieve it
1779 - * @uses bbp_forum_query_topic_ids() To get the forum's topic ids
1780 - * @uses wpdb::prepare() To prepare the query
1781 - * @uses wpdb::get_var() To execute the query and get the var back
1782 - * @uses bbp_get_reply_post_type() To get the reply post type
1783 - * @uses wp_cache_set() To set the cache for future use
1784 - * @uses apply_filters() Calls 'bbp_forum_query_last_reply_id' with the reply id
1785 - * and forum id
3081 + * @param int $forum_id Forum id.
3082 + * @param int $topic_ids Optional. Topic ids.
1786 3083 */
1787 -function bbp_forum_query_last_reply_id( $forum_id, $topic_ids = 0 ) {
1788 - global $wpdb;
3084 +function bbp_forum_query_last_reply_id( $forum_id = 0, $topic_ids = 0 ) {
1789 3085
1790 - $cache_id = 'bbp_get_forum_' . $forum_id . '_reply_id';
1791 - $reply_id = (int) wp_cache_get( $cache_id, 'bbpress' );
3086 + // Validate forum
3087 + $forum_id = bbp_get_forum_id( $forum_id );
1792 3088
1793 - if ( empty( $reply_id ) ) {
3089 + // Get topic ID's if none were passed
3090 + if ( empty( $topic_ids ) ) {
3091 + $topic_ids = bbp_forum_query_topic_ids( $forum_id );
3092 + }
1794 3093
1795 - if ( empty( $topic_ids ) ) {
1796 - $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1797 - }
3094 + $query = new WP_Query(
3095 + array(
3096 + 'fields' => 'ids',
3097 + 'suppress_filters' => true,
3098 + 'post_parent__in' => $topic_ids,
3099 + 'post_status' => bbp_get_public_status_id(),
3100 + 'post_type' => bbp_get_reply_post_type(),
3101 + 'posts_per_page' => 1,
3102 + 'orderby' => array(
3103 + 'post_date' => 'DESC',
3104 + 'ID' => 'DESC'
3105 + ),
1798 3106
1799 - if ( !empty( $topic_ids ) ) {
1800 - $reply_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent IN ( " . join( ',', $topic_ids ) . " ) AND post_status = '%s' AND post_type = '%s' ORDER BY ID DESC LIMIT 1;", bbp_get_public_status_id(), bbp_get_reply_post_type() ) );
1801 - wp_cache_set( $cache_id, $reply_id, 'bbpress' ); // May be (int) 0
1802 - } else {
1803 - wp_cache_set( $cache_id, '0', 'bbpress' );
1804 - }
1805 - }
3107 + // Performance
3108 + 'update_post_term_cache' => false,
3109 + 'update_post_meta_cache' => false,
3110 + 'ignore_sticky_posts' => true,
3111 + 'no_found_rows' => true
3112 + )
3113 + );
1806 3114
1807 - return (int) apply_filters( 'bbp_get_forum_last_reply_id', (int) $reply_id, $forum_id );
3115 + $reply_id = array_shift( $query->posts );
3116 +
3117 + unset( $query );
3118 +
3119 + // Filter & return
3120 + return (int) apply_filters( 'bbp_forum_query_last_reply_id', $reply_id, $forum_id );
1808 3121 }
1809 3122
1810 3123 /** Listeners *****************************************************************/
1811 3124
@@ -1812,30 +3125,23 @@
1812 3125 /**
1813 3126 * Check if it's a hidden forum or a topic or reply of a hidden forum and if
1814 3127 * the user can't view it, then sets a 404
1815 3128 *
1816 - * @since bbPress (r2996)
1817 - *
1818 - * @uses current_user_can() To check if the current user can read private forums
1819 - * @uses is_singular() To check if it's a singular page
1820 - * @uses bbp_get_forum_post_type() To get the forum post type
1821 - * @uses bbp_get_topic_post_type() To get the topic post type
1822 - * @uses bbp_get_reply_post_type() TO get the reply post type
1823 - * @uses bbp_get_topic_forum_id() To get the topic forum id
1824 - * @uses bbp_get_reply_forum_id() To get the reply forum id
1825 - * @uses bbp_is_forum_hidden() To check if the forum is hidden or not
1826 - * @uses bbp_set_404() To set a 404 status
3129 + * @since 2.0.0 bbPress (r2996)
1827 3130 */
1828 3131 function bbp_forum_enforce_hidden() {
1829 3132
1830 3133 // Bail if not viewing a single item or if user has caps
1831 - if ( !is_singular() || is_super_admin() || current_user_can( 'read_hidden_forums' ) )
3134 + if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_hidden_forums' ) ) {
1832 3135 return;
3136 + }
1833 3137
1834 - global $wp_query;
1835 -
1836 - // Define local variable
3138 + // Define local variables
1837 3139 $forum_id = 0;
3140 + $wp_query = bbp_get_wp_query();
3141 + $post_id = ! empty( $wp_query->post->ID )
3142 + ? $wp_query->post->ID
3143 + : 0;
1838 3144
1839 3145 // Check post type
1840 3146 switch ( $wp_query->get( 'post_type' ) ) {
1841 3147
@@ -1840,26 +3146,26 @@
1840 3146 switch ( $wp_query->get( 'post_type' ) ) {
1841 3147
1842 3148 // Forum
1843 3149 case bbp_get_forum_post_type() :
1844 - $forum_id = bbp_get_forum_id( $wp_query->post->ID );
3150 + $forum_id = bbp_get_forum_id( $post_id );
1845 3151 break;
1846 3152
1847 3153 // Topic
1848 3154 case bbp_get_topic_post_type() :
1849 - $forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
3155 + $forum_id = bbp_get_topic_forum_id( $post_id );
1850 3156 break;
1851 3157
1852 3158 // Reply
1853 3159 case bbp_get_reply_post_type() :
1854 - $forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
3160 + $forum_id = bbp_get_reply_forum_id( $post_id );
1855 3161 break;
1856 -
1857 3162 }
1858 3163
1859 3164 // If forum is explicitly hidden and user not capable, set 404
1860 - if ( !empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && !current_user_can( 'read_hidden_forums' ) )
1861 - bbp_set_404();
3165 + if ( ! empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
3166 + bbp_set_404( $wp_query );
3167 + }
1862 3168 }
1863 3169
1864 3170 /**
1865 3171 * Check if it's a private forum or a topic or reply of a private forum and if
@@ -1864,30 +3170,23 @@
1864 3170 /**
1865 3171 * Check if it's a private forum or a topic or reply of a private forum and if
1866 3172 * the user can't view it, then sets a 404
1867 3173 *
1868 - * @since bbPress (r2996)
1869 - *
1870 - * @uses current_user_can() To check if the current user can read private forums
1871 - * @uses is_singular() To check if it's a singular page
1872 - * @uses bbp_get_forum_post_type() To get the forum post type
1873 - * @uses bbp_get_topic_post_type() To get the topic post type
1874 - * @uses bbp_get_reply_post_type() TO get the reply post type
1875 - * @uses bbp_get_topic_forum_id() To get the topic forum id
1876 - * @uses bbp_get_reply_forum_id() To get the reply forum id
1877 - * @uses bbp_is_forum_private() To check if the forum is private or not
1878 - * @uses bbp_set_404() To set a 404 status
3174 + * @since 2.0.0 bbPress (r2996)
1879 3175 */
1880 3176 function bbp_forum_enforce_private() {
1881 3177
1882 3178 // Bail if not viewing a single item or if user has caps
1883 - if ( !is_singular() || is_super_admin() || current_user_can( 'read_private_forums' ) )
3179 + if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_private_forums' ) ) {
1884 3180 return;
3181 + }
1885 3182
1886 - global $wp_query;
1887 -
1888 - // Define local variable
3183 + // Define local variables
1889 3184 $forum_id = 0;
3185 + $wp_query = bbp_get_wp_query();
3186 + $post_id = ! empty( $wp_query->post->ID )
3187 + ? $wp_query->post->ID
3188 + : 0;
1890 3189
1891 3190 // Check post type
1892 3191 switch ( $wp_query->get( 'post_type' ) ) {
1893 3192
@@ -1892,51 +3191,45 @@
1892 3191 switch ( $wp_query->get( 'post_type' ) ) {
1893 3192
1894 3193 // Forum
1895 3194 case bbp_get_forum_post_type() :
1896 - $forum_id = bbp_get_forum_id( $wp_query->post->ID );
3195 + $forum_id = bbp_get_forum_id( $post_id );
1897 3196 break;
1898 3197
1899 3198 // Topic
1900 3199 case bbp_get_topic_post_type() :
1901 - $forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
3200 + $forum_id = bbp_get_topic_forum_id( $post_id );
1902 3201 break;
1903 3202
1904 3203 // Reply
1905 3204 case bbp_get_reply_post_type() :
1906 - $forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
3205 + $forum_id = bbp_get_reply_forum_id( $post_id );
1907 3206 break;
1908 -
1909 3207 }
1910 3208
1911 3209 // If forum is explicitly hidden and user not capable, set 404
1912 - if ( !empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && !current_user_can( 'read_private_forums' ) )
1913 - bbp_set_404();
3210 + if ( ! empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
3211 + bbp_set_404( $wp_query );
3212 + }
1914 3213 }
1915 3214
1916 3215 /** Permissions ***************************************************************/
1917 3216
1918 3217 /**
1919 - * Redirect if unathorized user is attempting to edit a forum
1920 - *
1921 - * @since bbPress (r3607)
3218 + * Redirect if unauthorized user is attempting to edit a forum
1922 3219 *
1923 - * @uses bbp_is_forum_edit()
1924 - * @uses current_user_can()
1925 - * @uses bbp_get_forum_id()
1926 - * @uses wp_safe_redirect()
1927 - * @uses bbp_get_forum_permalink()
3220 + * @since 2.1.0 bbPress (r3607)
1928 3221 */
1929 3222 function bbp_check_forum_edit() {
1930 3223
1931 3224 // Bail if not editing a topic
1932 - if ( !bbp_is_forum_edit() )
3225 + if ( ! bbp_is_forum_edit() ) {
1933 3226 return;
3227 + }
1934 3228
1935 3229 // User cannot edit topic, so redirect back to reply
1936 - if ( !current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
1937 - wp_safe_redirect( bbp_get_forum_permalink() );
1938 - exit();
3230 + if ( ! current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
3231 + bbp_redirect( bbp_get_forum_permalink() );
1939 3232 }
1940 3233 }
1941 3234
1942 3235 /**
@@ -1941,17 +3234,11 @@
1941 3234
1942 3235 /**
1943 3236 * Delete all topics (and their replies) for a specific forum ID
1944 3237 *
1945 - * @since bbPress (r3668)
3238 + * @since 2.1.0 bbPress (r3668)
1946 3239 *
1947 3240 * @param int $forum_id
1948 - * @uses bbp_get_forum_id() To validate the forum ID
1949 - * @uses bbp_is_forum() To make sure it's a forum
1950 - * @uses bbp_get_topic_post_type() To get the topic post type
1951 - * @uses bbp_topics() To make sure there are topics to loop through
1952 - * @uses wp_trash_post() To trash the post
1953 - * @uses update_post_meta() To update the forum meta of trashed topics
1954 3241 * @return If forum is not valid
1955 3242 */
1956 3243 function bbp_delete_forum_topics( $forum_id = 0 ) {
1957 3244
@@ -1956,21 +3243,35 @@
1956 3243 function bbp_delete_forum_topics( $forum_id = 0 ) {
1957 3244
1958 3245 // Validate forum ID
1959 3246 $forum_id = bbp_get_forum_id( $forum_id );
1960 - if ( empty( $forum_id ) )
3247 + if ( empty( $forum_id ) ) {
1961 3248 return;
3249 + }
1962 3250
1963 - // Forum is being permanently deleted, so its topics gotta go too
1964 - if ( $topics = new WP_Query( array(
1965 - 'suppress_filters' => true,
1966 - 'post_type' => bbp_get_topic_post_type(),
1967 - 'post_parent' => $forum_id,
1968 - 'post_status' => 'any',
1969 - 'posts_per_page' => -1,
1970 - 'nopaging' => true,
1971 - 'fields' => 'id=>parent'
1972 - ) ) ) {
3251 + // Forum is being permanently deleted, so its content has go too
3252 + // Note that we get all post statuses here
3253 + $topics = new WP_Query(
3254 + array(
3255 + 'fields' => 'id=>parent',
3256 + 'post_type' => bbp_get_topic_post_type(),
3257 + 'post_parent' => $forum_id,
3258 + 'post_status' => array_keys( get_post_stati() ),
3259 + 'posts_per_page' => -1,
3260 +
3261 + // Performance
3262 + 'nopaging' => true,
3263 + 'suppress_filters' => true,
3264 + 'update_post_term_cache' => false,
3265 + 'update_post_meta_cache' => false,
3266 + 'ignore_sticky_posts' => true,
3267 + 'no_found_rows' => true
3268 + )
3269 + );
3270 +
3271 + // Loop through and delete child topics. Topic replies will get deleted by
3272 + // the bbp_delete_topic() action.
3273 + if ( ! empty( $topics->posts ) ) {
1973 3274 foreach ( $topics->posts as $topic ) {
1974 3275 wp_delete_post( $topic->ID, true );
1975 3276 }
1976 3277
@@ -1976,24 +3277,19 @@
1976 3277
1977 3278 // Reset the $post global
1978 3279 wp_reset_postdata();
1979 3280 }
3281 +
3282 + // Cleanup
3283 + unset( $topics );
1980 3284 }
1981 3285
1982 3286 /**
1983 3287 * Trash all topics inside a forum
1984 - *
1985 - * @since bbPress (r3668)
1986 3288 *
3289 + * @since 2.1.0 bbPress (r3668)
3290 + *
1987 3291 * @param int $forum_id
1988 - * @uses bbp_get_forum_id() To validate the forum ID
1989 - * @uses bbp_is_forum() To make sure it's a forum
1990 - * @uses bbp_get_public_status_id() To return public post status
1991 - * @uses bbp_get_closed_status_id() To return closed post status
1992 - * @uses bbp_get_pending_status_id() To return pending post status
1993 - * @uses bbp_get_topic_post_type() To get the topic post type
1994 - * @uses wp_trash_post() To trash the post
1995 - * @uses update_post_meta() To update the forum meta of trashed topics
1996 3292 * @return If forum is not valid
1997 3293 */
1998 3294 function bbp_trash_forum_topics( $forum_id = 0 ) {
1999 3295
@@ -1998,29 +3294,42 @@
1998 3294 function bbp_trash_forum_topics( $forum_id = 0 ) {
1999 3295
2000 3296 // Validate forum ID
2001 3297 $forum_id = bbp_get_forum_id( $forum_id );
2002 - if ( empty( $forum_id ) )
3298 + if ( empty( $forum_id ) ) {
2003 3299 return;
3300 + }
2004 3301
2005 3302 // Allowed post statuses to pre-trash
2006 - $post_stati = join( ',', array(
3303 + $post_stati = array(
2007 3304 bbp_get_public_status_id(),
2008 3305 bbp_get_closed_status_id(),
2009 3306 bbp_get_pending_status_id()
2010 - ) );
3307 + );
2011 3308
2012 - // Forum is being trashed, so its topics are trashed too
2013 - if ( $topics = new WP_Query( array(
2014 - 'suppress_filters' => true,
2015 - 'post_type' => bbp_get_topic_post_type(),
2016 - 'post_parent' => $forum_id,
2017 - 'post_status' => $post_stati,
2018 - 'posts_per_page' => -1,
2019 - 'nopaging' => true,
2020 - 'fields' => 'id=>parent'
2021 - ) ) ) {
3309 + // Forum is being trashed, so its topics (and replies) are trashed too
3310 + $topics = new WP_Query(
3311 + array(
3312 + 'fields' => 'id=>parent',
3313 + 'post_type' => bbp_get_topic_post_type(),
3314 + 'post_parent' => $forum_id,
3315 + 'post_status' => $post_stati,
3316 + 'posts_per_page' => -1,
2022 3317
3318 + // Performance
3319 + 'nopaging' => true,
3320 + 'suppress_filters' => true,
3321 + 'update_post_term_cache' => false,
3322 + 'update_post_meta_cache' => false,
3323 + 'ignore_sticky_posts' => true,
3324 + 'no_found_rows' => true
3325 + )
3326 + );
3327 +
3328 + // Loop through and trash child topics. Topic replies will get trashed by
3329 + // the bbp_trash_topic() action.
3330 + if ( ! empty( $topics->posts ) ) {
3331 +
2023 3332 // Prevent debug notices
2024 3333 $pre_trashed_topics = array();
2025 3334
2026 3335 // Loop through topics, trash them, and add them to array
@@ -2036,20 +3345,19 @@
2036 3345
2037 3346 // Reset the $post global
2038 3347 wp_reset_postdata();
2039 3348 }
3349 +
3350 + // Cleanup
3351 + unset( $topics );
2040 3352 }
2041 3353
2042 3354 /**
2043 - * Trash all topics inside a forum
3355 + * Untrash all topics inside a forum
2044 3356 *
2045 - * @since bbPress (r3668)
3357 + * @since 2.1.0 bbPress (r3668)
2046 3358 *
2047 3359 * @param int $forum_id
2048 - * @uses bbp_get_forum_id() To validate the forum ID
2049 - * @uses bbp_is_forum() To make sure it's a forum
2050 - * @uses get_post_meta() To update the forum meta of trashed topics
2051 - * @uses wp_untrash_post() To trash the post
2052 3360 * @return If forum is not valid
2053 3361 */
2054 3362 function bbp_untrash_forum_topics( $forum_id = 0 ) {
2055 3363
@@ -2055,20 +3363,22 @@
2055 3363
2056 3364 // Validate forum ID
2057 3365 $forum_id = bbp_get_forum_id( $forum_id );
2058 3366
2059 - if ( empty( $forum_id ) )
3367 + if ( empty( $forum_id ) ) {
2060 3368 return;
3369 + }
2061 3370
2062 3371 // Get the topics that were not previously trashed
2063 3372 $pre_trashed_topics = get_post_meta( $forum_id, '_bbp_pre_trashed_topics', true );
2064 3373
2065 3374 // There are topics to untrash
2066 - if ( !empty( $pre_trashed_topics ) ) {
3375 + if ( ! empty( $pre_trashed_topics ) ) {
2067 3376
2068 3377 // Maybe reverse the trashed topics array
2069 - if ( is_array( $pre_trashed_topics ) )
3378 + if ( is_array( $pre_trashed_topics ) ) {
2070 3379 $pre_trashed_topics = array_reverse( $pre_trashed_topics );
3380 + }
2071 3381
2072 3382 // Loop through topics
2073 3383 foreach ( (array) $pre_trashed_topics as $topic ) {
2074 3384 wp_untrash_post( $topic );
@@ -2084,18 +3394,16 @@
2084 3394 * This function is supplemental to the actual forum deletion which is
2085 3395 * handled by WordPress core API functions. It is used to clean up after
2086 3396 * a forum that is being deleted.
2087 3397 *
2088 - * @since bbPress (r3668)
2089 - * @uses bbp_get_forum_id() To get the forum id
2090 - * @uses bbp_is_forum() To check if the passed id is a forum
2091 - * @uses do_action() Calls 'bbp_delete_forum' with the forum id
3398 + * @since 2.1.0 bbPress (r3668)
2092 3399 */
2093 3400 function bbp_delete_forum( $forum_id = 0 ) {
2094 3401 $forum_id = bbp_get_forum_id( $forum_id );
2095 3402
2096 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3403 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2097 3404 return false;
3405 + }
2098 3406
2099 3407 do_action( 'bbp_delete_forum', $forum_id );
2100 3408 }
2101 3409
@@ -2105,18 +3413,16 @@
2105 3413 * This function is supplemental to the actual forum being trashed which is
2106 3414 * handled by WordPress core API functions. It is used to clean up after
2107 3415 * a forum that is being trashed.
2108 3416 *
2109 - * @since bbPress (r3668)
2110 - * @uses bbp_get_forum_id() To get the forum id
2111 - * @uses bbp_is_forum() To check if the passed id is a forum
2112 - * @uses do_action() Calls 'bbp_trash_forum' with the forum id
3417 + * @since 2.1.0 bbPress (r3668)
2113 3418 */
2114 3419 function bbp_trash_forum( $forum_id = 0 ) {
2115 3420 $forum_id = bbp_get_forum_id( $forum_id );
2116 3421
2117 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3422 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2118 3423 return false;
3424 + }
2119 3425
2120 3426 do_action( 'bbp_trash_forum', $forum_id );
2121 3427 }
2122 3428
@@ -2122,18 +3428,16 @@
2122 3428
2123 3429 /**
2124 3430 * Called before untrashing a forum
2125 3431 *
2126 - * @since bbPress (r3668)
2127 - * @uses bbp_get_forum_id() To get the forum id
2128 - * @uses bbp_is_forum() To check if the passed id is a forum
2129 - * @uses do_action() Calls 'bbp_untrash_forum' with the forum id
3432 + * @since 2.1.0 bbPress (r3668)
2130 3433 */
2131 3434 function bbp_untrash_forum( $forum_id = 0 ) {
2132 3435 $forum_id = bbp_get_forum_id( $forum_id );
2133 3436
2134 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3437 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2135 3438 return false;
3439 + }
2136 3440
2137 3441 do_action( 'bbp_untrash_forum', $forum_id );
2138 3442 }
2139 3443
@@ -2141,35 +3445,43 @@
2141 3445
2142 3446 /**
2143 3447 * Called after deleting a forum
2144 3448 *
2145 - * @since bbPress (r3668)
2146 - * @uses bbp_get_forum_id() To get the forum id
2147 - * @uses bbp_is_forum() To check if the passed id is a forum
2148 - * @uses do_action() Calls 'bbp_deleted_forum' with the forum id
3449 + * Try not to use this action. All meta & taxonomy terms have already been
3450 + * deleted, making them impossible to use.
3451 + *
3452 + * @since 2.1.0 bbPress (r3668)
3453 + * @since 2.6.0 bbPress (r6526) Not recommend for usage
3454 + * @since 2.6.17 Added the `$forum` parameter and passed it to the action.
3455 + *
3456 + * @param int $forum_id Forum ID.
3457 + * @param WP_Post|bool $forum Optional. Deleted forum post object.
3458 + * @return false|null False if the post is not a forum, otherwise null.
2149 3459 */
2150 -function bbp_deleted_forum( $forum_id = 0 ) {
3460 +function bbp_deleted_forum( $forum_id = 0, $forum = false ) {
2151 3461 $forum_id = bbp_get_forum_id( $forum_id );
3462 + $forum = ( $forum instanceof WP_Post )
3463 + ? $forum
3464 + : get_post( $forum_id );
2152 3465
2153 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3466 + if ( empty( $forum_id ) || ! $forum || ( bbp_get_forum_post_type() !== $forum->post_type ) ) {
2154 3467 return false;
3468 + }
2155 3469
2156 - do_action( 'bbp_deleted_forum', $forum_id );
3470 + do_action( 'bbp_deleted_forum', $forum_id, $forum );
2157 3471 }
2158 3472
2159 3473 /**
2160 3474 * Called after trashing a forum
2161 3475 *
2162 - * @since bbPress (r3668)
2163 - * @uses bbp_get_forum_id() To get the forum id
2164 - * @uses bbp_is_forum() To check if the passed id is a forum
2165 - * @uses do_action() Calls 'bbp_trashed_forum' with the forum id
3476 + * @since 2.1.0 bbPress (r3668)
2166 3477 */
2167 3478 function bbp_trashed_forum( $forum_id = 0 ) {
2168 3479 $forum_id = bbp_get_forum_id( $forum_id );
2169 3480
2170 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3481 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2171 3482 return false;
3483 + }
2172 3484
2173 3485 do_action( 'bbp_trashed_forum', $forum_id );
2174 3486 }
2175 3487
@@ -2175,17 +3487,15 @@
2175 3487
2176 3488 /**
2177 3489 * Called after untrashing a forum
2178 3490 *
2179 - * @since bbPress (r3668)
2180 - * @uses bbp_get_forum_id() To get the forum id
2181 - * @uses bbp_is_forum() To check if the passed id is a forum
2182 - * @uses do_action() Calls 'bbp_untrashed_forum' with the forum id
3491 + * @since 2.1.0 bbPress (r3668)
2183 3492 */
2184 3493 function bbp_untrashed_forum( $forum_id = 0 ) {
2185 3494 $forum_id = bbp_get_forum_id( $forum_id );
2186 3495
2187 - if ( empty( $forum_id ) || !bbp_is_forum( $forum_id ) )
3496 + if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2188 3497 return false;
3498 + }
2189 3499
2190 3500 do_action( 'bbp_untrashed_forum', $forum_id );
2191 3501 }