Changeset 7467
- Timestamp:
- 09/10/2026 12:35:43 AM (12 days ago)
- Location:
- trunk
- Files:
-
- 1 added
- 22 edited
-
CHANGELOG.md (modified) (1 diff)
-
src/bbpress.php (modified) (1 diff)
-
src/includes/admin/tools/repair.php (modified) (1 diff)
-
src/includes/common/engagements.php (modified) (2 diffs)
-
src/includes/common/functions.php (modified) (5 diffs)
-
src/includes/core/abstraction.php (modified) (1 diff)
-
src/includes/core/actions.php (modified) (1 diff)
-
src/includes/forums/functions.php (modified) (23 diffs)
-
src/includes/replies/functions.php (modified) (3 diffs)
-
src/includes/topics/functions.php (modified) (10 diffs)
-
src/includes/users/engagements.php (modified) (2 diffs)
-
src/includes/users/functions.php (modified) (2 diffs)
-
src/includes/users/options.php (modified) (6 diffs)
-
src/readme.txt (modified) (1 diff)
-
tests/phpunit/testcases/admin/tools.php (modified) (5 diffs)
-
tests/phpunit/testcases/common/engagements.php (added)
-
tests/phpunit/testcases/core/abstraction.php (modified) (1 diff)
-
tests/phpunit/testcases/forums/functions/counts.php (modified) (6 diffs)
-
tests/phpunit/testcases/forums/functions/query.php (modified) (1 diff)
-
tests/phpunit/testcases/replies/functions/reply.php (modified) (1 diff)
-
tests/phpunit/testcases/topics/functions/counts.php (modified) (3 diffs)
-
tests/phpunit/testcases/topics/functions/topic.php (modified) (2 diffs)
-
tests/phpunit/testcases/users/functions/counts.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/CHANGELOG.md
r7465 r7467 64 64 - Kept public, hidden, and author contribution counts accurate when topics and 65 65 replies change moderation status or are permanently deleted. 66 - Kept subforum counts accurate across public, private, hidden, trashed, moved, 67 restored, and permanently deleted forums. 66 - Prevented simultaneous topic and reply submissions from overwriting each 67 other's existing stored count changes. 68 - Kept forum, ancestor, contribution, engagement, and voice counts synchronized 69 when moderators move replies or merge and split topics. 70 - Reconciled replacement-user contribution, engagement, and voice counts when 71 a deleted user's posts are reassigned. 72 - Excluded replies beneath non-public topics from forum reply counts during 73 moderation and repair recounts. 74 - Kept subforum counts and recursive forum aggregates accurate across public, 75 private, hidden, trashed, moved, restored, and permanently deleted forums. 68 76 - Corrected count repair tools to clear stale metadata caches, exclude anonymous 69 77 authors from voice counts, honor reply-status filters, rebuild private and 70 78 hidden forums, and preserve similarly named metadata on other post types. 79 - Made topic engagement and voice recounts honor filtered public reply statuses. 80 - Preserved term-backed favorites and subscriptions during engagement recounts. 71 81 72 82 - Cache a distinct count of current-site forum-role holders for forum statistics, -
trunk/src/bbpress.php
r7445 r7467 863 863 // Forum 864 864 $count['object_subtype'] = bbp_get_forum_post_type(); 865 register_meta( 'post', '_bbp_topic_count', $count ); 866 register_meta( 'post', '_bbp_reply_count', $count ); 867 register_meta( 'post', '_bbp_total_topic_count', $count ); 868 register_meta( 'post', '_bbp_total_reply_count', $count ); 869 register_meta( 'post', '_bbp_topic_count_hidden', $count ); 870 register_meta( 'post', '_bbp_reply_count_hidden', $count ); 871 register_meta( 'post', '_bbp_forum_subforum_count', $count ); 865 register_meta( 'post', '_bbp_topic_count', $count ); 866 register_meta( 'post', '_bbp_reply_count', $count ); 867 register_meta( 'post', '_bbp_total_topic_count', $count ); 868 register_meta( 'post', '_bbp_total_reply_count', $count ); 869 register_meta( 'post', '_bbp_topic_count_hidden', $count ); 870 register_meta( 'post', '_bbp_reply_count_hidden', $count ); 871 register_meta( 'post', '_bbp_total_topic_count_hidden', $count ); 872 register_meta( 'post', '_bbp_total_reply_count_hidden', $count ); 873 register_meta( 'post', '_bbp_forum_subforum_count', $count ); 872 874 873 875 // Topic -
trunk/src/includes/admin/tools/repair.php
r7453 r7467 444 444 LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id` 445 445 WHERE `posts`.`post_type` = '{$fpt}' 446 AND `postmeta`.`meta_key` IN ( '_bbp_topic_count', '_bbp_total_topic_count', '_bbp_topic_count_hidden' )";446 AND `postmeta`.`meta_key` IN ( '_bbp_topic_count', '_bbp_total_topic_count', '_bbp_topic_count_hidden', '_bbp_total_topic_count_hidden' )"; 447 447 if ( false === $bbp_db->query( $sql_delete ) ) { 448 448 return array( 1, sprintf( $statement, $result ) ); -
trunk/src/includes/common/engagements.php
r7380 r7467 430 430 * 431 431 * @since 2.6.0 bbPress (r6737) 432 * @since 2.6.16 Limit removal to the requested relationship taxonomy. 432 433 * 433 434 * @param int $object_id The object id. … … 439 440 */ 440 441 public function remove_object_from_all_users( $object_id = 0, $meta_key = '', $meta_type = 'post' ) { 441 return wp_delete_object_term_relationships( $object_id, get_object_taxonomies( 'bbp_user' ) ); 442 $tax_key = "{$meta_key}_{$meta_type}"; 443 $this->jit_taxonomy( $tax_key ); 444 445 return wp_delete_object_term_relationships( $object_id, $tax_key ); 442 446 } 443 447 -
trunk/src/includes/common/functions.php
r7452 r7467 276 276 $was_public = in_array( $old_status, bbp_get_public_topic_statuses(), true ); 277 277 $is_public = in_array( $new_status, bbp_get_public_topic_statuses(), true ); 278 $was_hidden = in_array( $old_status, bbp_get_non_public_topic_statuses(), true ); 279 $is_hidden = in_array( $new_status, bbp_get_non_public_topic_statuses(), true ); 278 280 $public_difference = (int) $is_public - (int) $was_public; 279 $hidden_difference = $is_new 280 ? (int) ! $is_public 281 : - $public_difference; 282 283 // A new topic or public boundary crossing changes at least one count 281 $hidden_difference = (int) $is_hidden - (int) $was_hidden; 282 283 // A new topic or count boundary crossing changes at least one count 284 284 if ( ! empty( $public_difference ) || ! empty( $hidden_difference ) ) { 285 285 $forum_id = $is_new … … 302 302 } 303 303 304 // Topic approval does not change its replies' statuses 305 if ( ! $is_new && in_array( bbp_get_pending_status_id(), array( $old_status, $new_status ), true ) ) { 306 $reply_count = bbp_get_public_child_count( $post->ID, bbp_get_reply_post_type() ); 307 bbp_bump_forum_reply_count( $forum_id, $reply_count * $public_difference ); 304 // Recount replies after their parent topic crosses the public boundary 305 if ( ! $is_new && ! empty( $forum_id ) && ! empty( $public_difference ) ) { 306 bbp_update_forum_reply_count( $forum_id, true ); 308 307 } 309 308 } … … 313 312 $was_public = in_array( $old_status, bbp_get_public_reply_statuses(), true ); 314 313 $is_public = in_array( $new_status, bbp_get_public_reply_statuses(), true ); 314 $was_hidden = in_array( $old_status, bbp_get_non_public_reply_statuses(), true ); 315 $is_hidden = in_array( $new_status, bbp_get_non_public_reply_statuses(), true ); 315 316 $public_difference = (int) $is_public - (int) $was_public; 316 $hidden_difference = $is_new 317 ? (int) ! $is_public 318 : - $public_difference; 319 320 // A new reply or public boundary crossing changes at least one count 317 $hidden_difference = (int) $is_hidden - (int) $was_hidden; 318 319 // A new reply or count boundary crossing changes at least one count 321 320 if ( ! empty( $public_difference ) || ! empty( $hidden_difference ) ) { 322 321 $topic_id = $is_new … … 326 325 ? bbp_get_topic_forum_id( $topic_id ) 327 326 : bbp_get_reply_forum_id( $post->ID ); 327 $forum_public_difference = bbp_is_topic_public( $topic_id ) 328 ? $public_difference 329 : 0; 328 330 329 331 // Update the topic's public reply count … … 338 340 339 341 // Update the forum's public reply count 340 if ( ! empty( $forum_id ) && ! empty( $ public_difference ) ) {341 bbp_bump_forum_reply_count( $forum_id, $ public_difference );342 if ( ! empty( $forum_id ) && ! empty( $forum_public_difference ) ) { 343 bbp_bump_forum_reply_count( $forum_id, $forum_public_difference ); 342 344 } 343 345 -
trunk/src/includes/core/abstraction.php
r7447 r7467 147 147 function bbp_db() { 148 148 return bbp_get_global_object( 'wpdb', 'WPDB' ); 149 } 150 151 /** 152 * Atomically bump a numeric metadata value using compare-and-swap retries. 153 * 154 * Count updates normally require reading a value, changing it in PHP, and 155 * writing it back. Two requests can read the same value and overwrite one 156 * another's changes. This function avoids that lost update by making the write 157 * conditional on the value that was read. If another request changes the value 158 * first, the condition matches no rows, so the current value is read directly 159 * from the database and the calculation is retried. 160 * 161 * The first read uses the WordPress metadata API and its cache. Missing 162 * metadata is added through add_metadata() so its standard lifecycle continues 163 * to run. Existing metadata uses a conditional database update while preserving 164 * the standard update metadata short-circuit filter and before/after actions. 165 * Before actions run for every conditional attempt, while after actions run 166 * only after a successful write. Metadata caches are cleared between attempts 167 * and after successful writes. Values are sanitized through sanitize_meta(), 168 * cast to integers, and prevented from falling below zero. 169 * 170 * Retries are bounded and filterable. This function does not lock rows or hold 171 * a database transaction open, and returns false when there is no change, a 172 * database operation fails, or all attempts lose to concurrent writes. It is 173 * intended for uniquely keyed numeric count metadata; WordPress metadata tables 174 * do not enforce uniqueness during simultaneous first-time inserts. 175 * 176 * @since 2.6.16 177 * 178 * @see https://bbpress.trac.wordpress.org/ticket/3678 179 * 180 * @param string $meta_type Type of object metadata is for. 181 * @param int $object_id ID of the object metadata is for. 182 * @param string $meta_key Metadata key. 183 * @param int $difference Amount to add to the stored value. 184 * @param int $default Existing value to use when metadata is missing. 185 * @return bool True on success, false on failure or no change. 186 */ 187 function bbp_bump_count_meta( $meta_type = '', $object_id = 0, $meta_key = '', $difference = 1, $default = 0 ) { 188 189 $object_id = (int) $object_id; 190 $difference = (int) $difference; 191 $default = (int) $default; 192 193 // Bail if required values are missing 194 if ( empty( $object_id ) || empty( $meta_key ) || empty( $difference ) ) { 195 return false; 196 } 197 198 /** 199 * Short-circuits bumping numeric metadata. 200 * 201 * Returning a non-null value prevents the normal metadata update. 202 * 203 * @since 2.6.16 204 * 205 * @param null|bool $check Whether to short-circuit the metadata update. 206 * @param string $meta_type Type of object metadata is for. 207 * @param int $object_id ID of the object metadata is for. 208 * @param string $meta_key Metadata key. 209 * @param int $difference Amount to add to the stored value. 210 * @param int $default Existing value to use when metadata is missing. 211 */ 212 $check = apply_filters( 'bbp_pre_bump_count_meta', null, $meta_type, $object_id, $meta_key, $difference, $default ); 213 if ( null !== $check ) { 214 return (bool) $check; 215 } 216 217 /** 218 * Filters the metadata types that support atomic count updates. 219 * 220 * @since 2.6.16 221 * 222 * @param array $meta_types Supported metadata types. 223 * @param string $meta_type Requested metadata type. 224 * @param int $object_id ID of the object metadata is for. 225 * @param string $meta_key Metadata key. 226 */ 227 $meta_types = (array) apply_filters( 'bbp_bump_count_meta_types', array( 'post', 'user', 'term', 'comment' ), $meta_type, $object_id, $meta_key ); 228 229 // Bail if the metadata type is unsupported 230 if ( ! in_array( $meta_type, $meta_types, true ) ) { 231 return false; 232 } 233 234 $bbp_db = bbp_db(); 235 $table_name = sanitize_key( $meta_type . 'meta' ); 236 $table = isset( $bbp_db->{$table_name} ) ? $bbp_db->{$table_name} : ''; 237 $column = sanitize_key( $meta_type . '_id' ); 238 $id_column = ( 'user' === $meta_type ) ? 'umeta_id' : 'meta_id'; 239 240 // Bail if the metadata table does not exist 241 if ( empty( $table ) ) { 242 return false; 243 } 244 245 /** 246 * Filters the maximum number of conditional metadata write attempts. 247 * 248 * @since 2.6.16 249 * 250 * @param int $max_attempts Maximum number of attempts. 251 * @param string $meta_type Type of object metadata is for. 252 * @param int $object_id ID of the object metadata is for. 253 * @param string $meta_key Metadata key. 254 * @param int $difference Amount to add to the stored value. 255 * @param int $default Existing value to use when metadata is missing. 256 */ 257 $max_attempts = (int) apply_filters( 'bbp_bump_count_meta_max_attempts', 5, $meta_type, $object_id, $meta_key, $difference, $default ); 258 $max_attempts = max( 1, $max_attempts ); 259 $checked = false; 260 $subtype = get_object_subtype( $meta_type, $object_id ); 261 $count_query = $bbp_db->prepare( "SELECT meta_value FROM {$table} WHERE meta_key = %s AND {$column} = %d LIMIT 1", $meta_key, $object_id ); 262 263 // Retry when another request updates the same value first 264 for ( $attempt = 0; $attempt < $max_attempts; $attempt++ ) { 265 if ( empty( $attempt ) ) { 266 $exists = metadata_exists( $meta_type, $object_id, $meta_key ); 267 $count = $exists 268 ? (int) get_metadata( $meta_type, $object_id, $meta_key, true ) 269 : $default; 270 } else { 271 $stored = $bbp_db->get_var( $count_query ); 272 273 // Bail on a database error 274 if ( ! empty( $bbp_db->last_error ) ) { 275 return false; 276 } 277 278 $exists = null !== $stored; 279 $count = $exists ? (int) $stored : $default; 280 } 281 282 $new_count = sanitize_meta( $meta_key, bbp_number_not_negative( $count + $difference ), $meta_type, $subtype ); 283 $new_count = (int) $new_count; 284 285 // Allow metadata updates to be short-circuited as usual 286 if ( ! $checked ) { 287 $checked = true; 288 $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $new_count, '' ); 289 290 if ( null !== $check ) { 291 return (bool) $check; 292 } 293 } 294 295 // Bail if the count is already at its lower bound 296 if ( $new_count === $count ) { 297 if ( ! empty( $attempt ) ) { 298 return false; 299 } 300 301 $stored = $bbp_db->get_var( $count_query ); 302 303 // Bail on a database error 304 if ( ! empty( $bbp_db->last_error ) ) { 305 return false; 306 } 307 308 $current_exists = null !== $stored; 309 $current_count = $current_exists ? (int) $stored : $default; 310 311 if ( ( $current_exists === $exists ) && ( $current_count === $count ) ) { 312 return false; 313 } 314 315 wp_cache_delete( $object_id, $meta_type . '_meta' ); 316 continue; 317 } 318 319 // Add missing metadata using the standard WordPress lifecycle 320 if ( ! $exists ) { 321 if ( ! empty( add_metadata( $meta_type, $object_id, $meta_key, $new_count, true ) ) ) { 322 return true; 323 } 324 325 $stored = $bbp_db->get_var( $count_query ); 326 327 // Bail if the add failed without a concurrent insert or on a database error 328 if ( ! empty( $bbp_db->last_error ) || ( null === $stored ) ) { 329 return false; 330 } 331 332 wp_cache_delete( $object_id, $meta_type . '_meta' ); 333 continue; 334 } 335 336 $meta_ids = $bbp_db->get_col( $bbp_db->prepare( "SELECT {$id_column} FROM {$table} WHERE meta_key = %s AND {$column} = %d", $meta_key, $object_id ) ); 337 338 // Bail on a database error 339 if ( ! empty( $bbp_db->last_error ) ) { 340 return false; 341 } 342 343 // Retry if metadata was removed after the cached existence check 344 if ( empty( $meta_ids ) ) { 345 wp_cache_delete( $object_id, $meta_type . '_meta' ); 346 continue; 347 } 348 349 // Run the standard actions immediately before the conditional update 350 foreach ( $meta_ids as $meta_id ) { 351 do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $new_count ); 352 353 if ( 'post' === $meta_type ) { 354 do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $new_count ); 355 } 356 } 357 358 // Compare count metadata numerically to normalize stored numeric strings 359 $updated = $bbp_db->update( 360 $table, 361 array( 'meta_value' => $new_count ), 362 array( 363 $column => $object_id, 364 'meta_key' => $meta_key, 365 'meta_value' => $count 366 ), 367 array( '%d' ), 368 array( '%d', '%s', '%d' ) 369 ); 370 371 // Bail on a database error 372 if ( false === $updated ) { 373 return false; 374 } 375 376 wp_cache_delete( $object_id, $meta_type . '_meta' ); 377 378 // Retry when another request updated the count first 379 if ( empty( $updated ) ) { 380 continue; 381 } 382 383 // Run the standard actions immediately after the conditional update 384 foreach ( $meta_ids as $meta_id ) { 385 do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $new_count ); 386 387 if ( 'post' === $meta_type ) { 388 do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $new_count ); 389 } 390 } 391 392 return true; 393 } 394 395 return false; 149 396 } 150 397 -
trunk/src/includes/core/actions.php
r7453 r7467 288 288 add_action( 'bbp_deleted_topic', 'bbp_decrease_user_topic_count' ); 289 289 add_action( 'bbp_deleted_reply', 'bbp_decrease_user_reply_count' ); 290 add_action( 'bbp_post_updated', 'bbp_update_counts_on_post_author_change', 10, 3 ); 291 add_action( 'bbp_post_updated', 'bbp_recalculate_engagements_on_post_author_change', 20, 3 ); 292 293 // Update counts and engagements after WordPress reassigns a deleted user's posts 294 add_action( 'delete_user', 'bbp_update_counts_on_user_reassignment', 10, 2 ); 295 add_action( 'deleted_user', 'bbp_update_counts_on_user_reassignment', 10, 2 ); 290 296 291 297 // Topic status transition helpers for replies -
trunk/src/includes/forums/functions.php
r7455 r7467 1111 1111 * 1112 1112 * @since 2.1.0 bbPress (r3825) 1113 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 1113 1114 * 1114 1115 * @param int $forum_id Optional. Forum id. … … 1132 1133 1133 1134 // Update this forum id 1134 update_post_meta( $forum_id, '_bbp_topic_count', (int) ( $topic_count + $difference ));1135 update_post_meta( $forum_id, '_bbp_total_topic_count', (int) ( $total_topic_count + $difference ));1135 bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count', $difference, $topic_count ); 1136 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count', $difference, $total_topic_count ); 1136 1137 1137 1138 // Check for ancestors … … 1150 1151 1151 1152 $parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, true ); 1152 update_post_meta( $parent_forum_id, '_bbp_topic_count', (int) ( $parent_topic_count + $difference ));1153 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count', $difference, $parent_topic_count ); 1153 1154 } 1154 1155 1155 1156 // Update the total topic count. 1156 1157 $parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true, true ); 1157 update_post_meta( $parent_forum_id, '_bbp_total_topic_count', (int) ( $parent_total_topic_count + $difference ));1158 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count', $difference, $parent_total_topic_count ); 1158 1159 } 1159 1160 } 1160 1161 } 1161 1162 1162 $forum_topic_count = (int)( $total_topic_count + $difference );1163 $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference ); 1163 1164 1164 1165 // Filter & return … … 1230 1231 * 1231 1232 * @since 2.1.0 bbPress (r3825) 1233 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 1232 1234 * 1233 1235 * @param int $forum_id Optional. Forum id. … … 1251 1253 1252 1254 // Update this forum id 1253 update_post_meta( $forum_id, '_bbp_topic_count_hidden', (int) ( $reply_count + $difference ));1254 update_post_meta( $forum_id, '_bbp_total_topic_count_hidden', (int) ( $total_topic_count + $difference ));1255 bbp_bump_count_meta( 'post', $forum_id, '_bbp_topic_count_hidden', $difference, $reply_count ); 1256 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_topic_count_hidden', $difference, $total_topic_count ); 1255 1257 1256 1258 // Check for ancestors … … 1269 1271 1270 1272 $parent_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, false, true ); 1271 update_post_meta( $parent_forum_id, '_bbp_topic_count_hidden', (int) ( $parent_topic_count + $difference ));1273 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_topic_count_hidden', $difference, $parent_topic_count ); 1272 1274 } 1273 1275 1274 1276 // Update the total topic count. 1275 1277 $parent_total_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, true, true ); 1276 update_post_meta( $parent_forum_id, '_bbp_total_topic_count_hidden', (int) ( $parent_total_topic_count + $difference ));1278 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_topic_count_hidden', $difference, $parent_total_topic_count ); 1277 1279 } 1278 1280 } 1279 1281 } 1280 1282 1281 $forum_topic_count = (int)( $total_topic_count + $difference );1283 $forum_topic_count = bbp_number_not_negative( $total_topic_count + $difference ); 1282 1284 1283 1285 // Filter & return … … 1349 1351 * 1350 1352 * @since 2.1.0 bbPress (r3825) 1353 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 1351 1354 * 1352 1355 * @param int $forum_id Optional. Forum id. … … 1370 1373 1371 1374 // Update this forum id 1372 update_post_meta( $forum_id, '_bbp_reply_count', (int) ( $reply_count + $difference ));1373 update_post_meta( $forum_id, '_bbp_total_reply_count', (int) ( $total_reply_count + $difference ));1375 bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count', $difference, $reply_count ); 1376 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count', $difference, $total_reply_count ); 1374 1377 1375 1378 // Check for ancestors … … 1388 1391 1389 1392 $parent_reply_count = bbp_get_forum_reply_count( $parent_forum_id, false, true ); 1390 update_post_meta( $parent_forum_id, '_bbp_reply_count', (int) ( $parent_reply_count + $difference ));1393 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count', $difference, $parent_reply_count ); 1391 1394 } 1392 1395 1393 1396 // Update the total reply count. 1394 1397 $parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true, true ); 1395 update_post_meta( $parent_forum_id, '_bbp_total_reply_count', (int) ( $parent_total_reply_count + $difference ));1398 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count', $difference, $parent_total_reply_count ); 1396 1399 } 1397 1400 } 1398 1401 } 1399 1402 1400 $forum_reply_count = (int)( $total_reply_count + $difference );1403 $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference ); 1401 1404 1402 1405 // Filter & return … … 1408 1411 * 1409 1412 * @since 2.6.0 bbPress (r6922) 1413 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 1410 1414 * 1411 1415 * @param int $forum_id Optional. Forum id. … … 1429 1433 1430 1434 // Update this forum id 1431 update_post_meta( $forum_id, '_bbp_reply_count_hidden', (int) ( $reply_count + $difference ));1432 update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', (int) ( $total_reply_count + $difference ));1435 bbp_bump_count_meta( 'post', $forum_id, '_bbp_reply_count_hidden', $difference, $reply_count ); 1436 bbp_bump_count_meta( 'post', $forum_id, '_bbp_total_reply_count_hidden', $difference, $total_reply_count ); 1433 1437 1434 1438 // Check for ancestors … … 1447 1451 1448 1452 $parent_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, false, true ); 1449 update_post_meta( $parent_forum_id, '_bbp_reply_count_hidden', (int) ( $parent_reply_count + $difference ));1453 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_reply_count_hidden', $difference, $parent_reply_count ); 1450 1454 } 1451 1455 1452 1456 // Update the total reply count. 1453 1457 $parent_total_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, true, true ); 1454 update_post_meta( $parent_forum_id, '_bbp_total_reply_count_hidden', (int) ( $parent_total_reply_count + $difference ));1458 bbp_bump_count_meta( 'post', $parent_forum_id, '_bbp_total_reply_count_hidden', $difference, $parent_total_reply_count ); 1455 1459 } 1456 1460 } 1457 1461 } 1458 1462 1459 $forum_reply_count = (int)( $total_reply_count + $difference );1463 $forum_reply_count = bbp_number_not_negative( $total_reply_count + $difference ); 1460 1464 1461 1465 // Filter & return 1462 1466 return (int) apply_filters( 'bbp_bump_forum_reply_count_hidden', $forum_reply_count, $forum_id, $difference, $update_ancestors ); 1467 } 1468 1469 /** 1470 * Bump one total count through a forum's ancestors. 1471 * 1472 * This is used after recounting a forum that may be nested as a subforum. The 1473 * starting forum's total has already been updated, so only its parent forums 1474 * receive the difference between the old and new totals. The supplied metadata 1475 * key identifies which total topic or reply count is propagated. 1476 * 1477 * Forum hierarchy is stored in `post_parent`, making get_post_ancestors() the 1478 * canonical, cache-aware way to walk from a subforum toward its root forum. 1479 * Only parent forums are traversed: topics and replies are never ancestors in 1480 * a valid forum hierarchy, even when the metadata key stores their totals. The 1481 * walk stops if a malformed parent relationship leaves the forum post type. 1482 * 1483 * @since 2.6.16 1484 * 1485 * @param int $forum_id Starting forum ID. Its own count is not changed. 1486 * @param string $meta_key Topic or reply total count metadata key. 1487 * @param int $difference Amount to add to the stored value. 1488 * @return bool True when all ancestor counts were updated, false otherwise. 1489 */ 1490 function bbp_bump_forum_ancestor_count( $forum_id = 0, $meta_key = '', $difference = 0 ) { 1491 $forum_id = bbp_get_forum_id( $forum_id ); 1492 $difference = (int) $difference; 1493 1494 // Bail if nothing can change 1495 if ( empty( $forum_id ) || empty( $meta_key ) || empty( $difference ) ) { 1496 return false; 1497 } 1498 1499 $updated = true; 1500 $ancestor_ids = get_post_ancestors( $forum_id ); 1501 1502 // Return if this forum has no ancestors 1503 if ( empty( $ancestor_ids ) ) { 1504 return $updated; 1505 } 1506 1507 // Update only total counts on ancestor forums 1508 foreach ( $ancestor_ids as $ancestor_id ) { 1509 1510 // Stop if malformed data leaves the subforum hierarchy 1511 if ( ! bbp_is_forum( $ancestor_id ) ) { 1512 break; 1513 } 1514 1515 $count = (int) get_post_meta( $ancestor_id, $meta_key, true ); 1516 1517 if ( ! bbp_bump_count_meta( 'post', $ancestor_id, $meta_key, $difference, $count ) ) { 1518 $updated = false; 1519 } 1520 } 1521 1522 return $updated; 1463 1523 } 1464 1524 … … 1978 2038 * 1979 2039 * @since 2.0.0 bbPress (r2464) 2040 * @since 2.6.16 Optionally update ancestor forum totals. 1980 2041 * 1981 2042 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it 1982 2043 * is a topic or a forum. If it's a topic, its parent, 1983 2044 * i.e. the forum is automatically retrieved. 1984 * @param bool $ total_count Optional. To return the total count or normal count.2045 * @param bool $update_ancestors Optional. Whether to update ancestor totals. 1985 2046 * @return int Forum topic count. 1986 2047 */ 1987 function bbp_update_forum_topic_count( $forum_id = 0 ) { 1988 $forum_id = bbp_get_forum_id( $forum_id ); 2048 function bbp_update_forum_topic_count( $forum_id = 0, $update_ancestors = false ) { 2049 $forum_id = bbp_get_forum_id( $forum_id ); 2050 $old_total_topics = ( true === $update_ancestors ) 2051 ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count', true ) 2052 : 0; 1989 2053 $children_topic_count = 0; 2054 $total_topics = 0; 1990 2055 1991 2056 // Loop through subforums and add together forum topic counts … … 2007 2072 update_post_meta( $forum_id, '_bbp_total_topic_count', $total_topics ); 2008 2073 2074 // Update ancestor total counts by the persisted difference 2075 if ( true === $update_ancestors ) { 2076 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count', $total_topics - $old_total_topics ); 2077 } 2078 2009 2079 // Filter & return 2010 2080 return (int) apply_filters( 'bbp_update_forum_topic_count', $total_topics, $forum_id ); … … 2017 2087 * @since 2.0.0 bbPress (r2888) 2018 2088 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects 2089 * @since 2.6.16 Optionally update ancestor forum totals. 2019 2090 * 2020 2091 * @param int $forum_id Optional. Topic id to update. 2021 2092 * @param int $topic_count Optional. Set the topic count manually. 2093 * @param bool $update_ancestors Optional. Whether to update ancestor totals. 2022 2094 * 2023 2095 * @return int Topic hidden topic count. 2024 2096 */ 2025 function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = false ) {2097 function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = false, $update_ancestors = false ) { 2026 2098 2027 2099 // If topic_id was passed as $forum_id, then get its forum … … 2035 2107 } 2036 2108 2109 $children_topic_count = 0; 2110 $total_topics = 0; 2111 $old_total_topics = ( true === $update_ancestors ) 2112 ? (int) get_post_meta( $forum_id, '_bbp_total_topic_count_hidden', true ) 2113 : 0; 2114 2037 2115 // Can't update what isn't there 2038 2116 if ( ! empty( $forum_id ) ) { 2117 2118 // Loop through children and add together hidden topic counts 2119 $children = bbp_forum_query_subforum_ids( $forum_id ); 2120 if ( ! empty( $children ) ) { 2121 foreach ( (array) $children as $child ) { 2122 bbp_update_forum_topic_count_hidden( $child ); 2123 $children_topic_count += bbp_get_forum_topic_count_hidden( $child, true, true ); 2124 } 2125 } 2039 2126 2040 2127 // Get topics of forum … … 2063 2150 } 2064 2151 2065 $topic_count = (int) $topic_count; 2066 2067 // Update the count 2068 update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count ); 2152 $topic_count = (int) $topic_count; 2153 $total_topics = (int) ( $topic_count + $children_topic_count ); 2154 2155 // Update the counts 2156 update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count ); 2157 update_post_meta( $forum_id, '_bbp_total_topic_count_hidden', $total_topics ); 2158 2159 // Update ancestor total counts by the persisted difference 2160 if ( true === $update_ancestors ) { 2161 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_topic_count_hidden', $total_topics - $old_total_topics ); 2162 } 2069 2163 } 2070 2164 … … 2078 2172 * @since 2.0.0 bbPress (r2464) 2079 2173 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects. 2174 * @since 2.6.16 Count replies only when their parent topics are public. 2175 * @since 2.6.16 Optionally update ancestor forum totals. 2080 2176 * 2081 2177 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it 2082 2178 * is a topic or a forum. If it's a topic, its parent, 2083 2179 * i.e. the forum is automatically retrieved. 2180 * @param bool $update_ancestors Optional. Whether to update ancestor totals. 2084 2181 * 2085 2182 * @return int Forum reply count. 2086 2183 */ 2087 function bbp_update_forum_reply_count( $forum_id = 0 ) { 2088 2089 $forum_id = bbp_get_forum_id( $forum_id ); 2184 function bbp_update_forum_reply_count( $forum_id = 0, $update_ancestors = false ) { 2185 2186 $forum_id = bbp_get_forum_id( $forum_id ); 2187 $old_total_replies = ( true === $update_ancestors ) 2188 ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count', true ) 2189 : 0; 2090 2190 $children_reply_count = 0; 2091 2191 … … 2099 2199 2100 2200 // Don't count replies if the forum is a category 2101 $reply_count = ! bbp_is_forum_category( $forum_id ) 2102 ? bbp_get_public_child_count( $forum_id, bbp_get_reply_post_type() ) 2103 : 0; 2201 if ( bbp_is_forum_category( $forum_id ) ) { 2202 $reply_count = 0; 2203 2204 // Count public replies whose parent topics are also public 2205 } else { 2206 $bbp_db = bbp_db(); 2207 $reply_statuses = bbp_get_public_reply_statuses(); 2208 $topic_statuses = bbp_get_public_topic_statuses(); 2209 2210 if ( empty( $reply_statuses ) || empty( $topic_statuses ) ) { 2211 $reply_count = 0; 2212 } else { 2213 $reply_placeholders = implode( ', ', array_fill( 0, count( $reply_statuses ), '%s' ) ); 2214 $topic_placeholders = implode( ', ', array_fill( 0, count( $topic_statuses ), '%s' ) ); 2215 $sql = "SELECT COUNT(*) FROM {$bbp_db->posts} AS replies 2216 INNER JOIN {$bbp_db->posts} AS topics ON replies.post_parent = topics.ID 2217 WHERE topics.post_parent = %d 2218 AND topics.post_type = %s 2219 AND topics.post_status IN ({$topic_placeholders}) 2220 AND replies.post_type = %s 2221 AND replies.post_status IN ({$reply_placeholders})"; 2222 $query = $bbp_db->prepare( 2223 $sql, 2224 array_merge( 2225 array( $forum_id, bbp_get_topic_post_type() ), 2226 $topic_statuses, 2227 array( bbp_get_reply_post_type() ), 2228 $reply_statuses 2229 ) 2230 ); 2231 $reply_count = bbp_number_not_negative( $bbp_db->get_var( $query ) ); 2232 } 2233 } 2104 2234 2105 2235 // Calculate total replies in this forum … … 2110 2240 update_post_meta( $forum_id, '_bbp_total_reply_count', $total_replies ); 2111 2241 2242 // Update ancestor total counts by the persisted difference 2243 if ( true === $update_ancestors ) { 2244 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count', $total_replies - $old_total_replies ); 2245 } 2246 2112 2247 // Filter & return 2113 2248 return (int) apply_filters( 'bbp_update_forum_reply_count', $total_replies, $forum_id ); … … 2118 2253 * 2119 2254 * @since 2.6.0 bbPress (r6922) 2255 * @since 2.6.16 Optionally update ancestor forum totals. 2120 2256 * 2121 2257 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it 2122 2258 * is a topic or a forum. If it's a topic, its parent, 2123 2259 * i.e. the forum is automatically retrieved. 2260 * @param bool $update_ancestors Optional. Whether to update ancestor totals. 2124 2261 * 2125 2262 * @return int Forum reply count. 2126 2263 */ 2127 function bbp_update_forum_reply_count_hidden( $forum_id = 0 ) { 2128 2129 $forum_id = bbp_get_forum_id( $forum_id ); 2264 function bbp_update_forum_reply_count_hidden( $forum_id = 0, $update_ancestors = false ) { 2265 2266 $forum_id = bbp_get_forum_id( $forum_id ); 2267 $old_total_replies = ( true === $update_ancestors ) 2268 ? (int) get_post_meta( $forum_id, '_bbp_total_reply_count_hidden', true ) 2269 : 0; 2130 2270 $children_reply_count = 0; 2131 2271 … … 2149 2289 update_post_meta( $forum_id, '_bbp_reply_count_hidden', $reply_count ); 2150 2290 update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', $total_replies ); 2291 2292 // Update ancestor total counts by the persisted difference 2293 if ( true === $update_ancestors ) { 2294 bbp_bump_forum_ancestor_count( $forum_id, '_bbp_total_reply_count_hidden', $total_replies - $old_total_replies ); 2295 } 2151 2296 2152 2297 // Filter & return … … 2739 2884 * Returns the forum's subforum ids. 2740 2885 * 2741 * Only forums with published status are returned.2886 * Only forums with countable statuses are returned. 2742 2887 * 2743 2888 * @since 2.0.0 bbPress (r2908) 2889 * @since 2.6.16 Exclude forums with uncountable statuses. 2744 2890 * 2745 2891 * @param int $forum_id Forum id. 2746 2892 */ 2747 2893 function bbp_forum_query_subforum_ids( $forum_id ) { 2748 $subforum_ids = bbp_get_all_child_ids( $forum_id, bbp_get_forum_post_type() ); 2894 $forum_id = bbp_get_forum_id( $forum_id ); 2895 $statuses = bbp_get_countable_forum_statuses(); 2896 $subforum_ids = array(); 2897 2898 // Query and cache countable subforums. The public child-ID helper excludes 2899 // private and hidden forums, while the all-child helper includes trash, so 2900 // neither existing helper represents the statuses counted here. 2901 if ( ! empty( $forum_id ) && ! empty( $statuses ) ) { 2902 $key = md5( 2903 serialize( 2904 array( 2905 'parent_id' => $forum_id, 2906 'post_type' => bbp_get_forum_post_type(), 2907 'post_status' => $statuses 2908 ) 2909 ) 2910 ); 2911 $cache_key = "bbp_child_ids:{$key}:" . wp_cache_get_last_changed( 'bbpress_posts' ); 2912 $subforum_ids = wp_cache_get( $cache_key, 'bbpress_posts' ); 2913 2914 if ( false === $subforum_ids ) { 2915 $bbp_db = bbp_db(); 2916 $placeholders = implode( ', ', array_fill( 0, count( $statuses ), '%s' ) ); 2917 $query = $bbp_db->prepare( 2918 "SELECT ID FROM {$bbp_db->posts} WHERE post_parent = %d AND post_type = %s AND post_status IN ({$placeholders}) ORDER BY ID DESC", 2919 array_merge( array( $forum_id, bbp_get_forum_post_type() ), $statuses ) 2920 ); 2921 $subforum_ids = (array) $bbp_db->get_col( $query ); 2922 2923 wp_cache_set( $cache_key, $subforum_ids, 'bbpress_posts' ); 2924 } 2925 } 2749 2926 2750 2927 // Filter & return -
trunk/src/includes/replies/functions.php
r7449 r7467 1526 1526 * 1527 1527 * @since 2.3.0 bbPress (r4521) 1528 * @since 2.6.16 Recount both forums and topic engagements. 1528 1529 * 1529 1530 * @param int $move_reply_id Move reply id. … … 1532 1533 */ 1533 1534 function bbp_move_reply_count( $move_reply_id, $source_topic_id, $destination_topic_id ) { 1534 1535 // Forum topic counts 1536 bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1537 1538 // Forum reply counts 1539 bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1535 $source_forum_id = bbp_get_topic_forum_id( $source_topic_id ); 1536 $destination_forum_id = bbp_get_topic_forum_id( $destination_topic_id ); 1537 1538 // A reply converted into a topic changes its forum's topic counts 1539 if ( bbp_is_topic( $move_reply_id ) ) { 1540 bbp_update_forum_topic_count( $destination_forum_id, true ); 1541 bbp_update_forum_topic_count_hidden( $destination_forum_id, false, true ); 1542 1543 // Transfer the public contribution between count types 1544 if ( bbp_is_topic_published( $move_reply_id ) ) { 1545 $user_id = bbp_get_topic_author_id( $move_reply_id ); 1546 bbp_bump_user_reply_count( $user_id, -1 ); 1547 bbp_bump_user_topic_count( $user_id, 1 ); 1548 } 1549 } 1550 1551 // Recount replies in both forums 1552 foreach ( bbp_get_unique_array_values( array( $source_forum_id, $destination_forum_id ) ) as $forum_id ) { 1553 bbp_update_forum_reply_count( $forum_id, true ); 1554 bbp_update_forum_reply_count_hidden( $forum_id, true ); 1555 } 1540 1556 1541 1557 // Topic reply counts … … 1547 1563 bbp_update_topic_reply_count_hidden( $destination_topic_id ); 1548 1564 1549 // Topic voice counts 1565 // Topic engagement and voice counts 1566 bbp_recalculate_topic_engagements( $source_topic_id ); 1567 bbp_recalculate_topic_engagements( $destination_topic_id ); 1550 1568 bbp_update_topic_voice_count( $source_topic_id ); 1551 1569 bbp_update_topic_voice_count( $destination_topic_id ); -
trunk/src/includes/topics/functions.php
r7455 r7467 1368 1368 * 1369 1369 * @since 2.0.0 bbPress (r2756) 1370 * @since 2.6.16 Recount both forums and topic engagements. 1370 1371 * 1371 1372 * @param int $destination_topic_id Destination topic id. … … 1374 1375 */ 1375 1376 function bbp_merge_topic_count( $destination_topic_id, $source_topic_id, $source_topic_forum_id ) { 1377 $destination_forum_id = bbp_get_topic_forum_id( $destination_topic_id ); 1376 1378 1377 1379 /** Source Topic **********************************************************/ 1378 1380 1379 1381 // Forum Topic Counts 1380 bbp_update_forum_topic_count( $source_topic_forum_id ); 1382 bbp_update_forum_topic_count( $source_topic_forum_id, true ); 1383 bbp_update_forum_topic_count_hidden( $source_topic_forum_id, false, true ); 1381 1384 1382 1385 // Forum Reply Counts 1383 bbp_update_forum_reply_count( $source_topic_forum_id ); 1386 foreach ( bbp_get_unique_array_values( array( $source_topic_forum_id, $destination_forum_id ) ) as $forum_id ) { 1387 bbp_update_forum_reply_count( $forum_id, true ); 1388 bbp_update_forum_reply_count_hidden( $forum_id, true ); 1389 } 1384 1390 1385 1391 /** Destination Topic *****************************************************/ … … 1391 1397 bbp_update_topic_reply_count_hidden( $destination_topic_id ); 1392 1398 1393 // Topic Voice Counts 1399 // Topic Engagement and Voice Counts 1400 bbp_recalculate_topic_engagements( $destination_topic_id ); 1394 1401 bbp_update_topic_voice_count( $destination_topic_id ); 1402 1403 // Transfer the converted source topic author's contribution to replies 1404 if ( bbp_is_reply_published( $source_topic_id ) ) { 1405 $user_id = bbp_get_reply_author_id( $source_topic_id ); 1406 bbp_bump_user_topic_count( $user_id, -1 ); 1407 bbp_bump_user_reply_count( $user_id, 1 ); 1408 } 1395 1409 1396 1410 do_action( 'bbp_merge_topic_count', $destination_topic_id, $source_topic_id, $source_topic_forum_id ); … … 1718 1732 * 1719 1733 * @since 2.0.0 bbPress (r2756) 1734 * @since 2.6.16 Recount both forums and topic engagements. 1720 1735 * 1721 1736 * @param int $from_reply_id From reply id. … … 1724 1739 */ 1725 1740 function bbp_split_topic_count( $from_reply_id, $source_topic_id, $destination_topic_id ) { 1726 1727 // Forum Topic Counts 1728 bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1729 1730 // Forum Reply Counts 1731 bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) ); 1741 $source_forum_id = bbp_get_topic_forum_id( $source_topic_id ); 1742 $destination_forum_id = bbp_get_topic_forum_id( $destination_topic_id ); 1743 1744 // A reply converted into a topic changes its forum's topic counts 1745 if ( bbp_is_topic( $from_reply_id ) ) { 1746 bbp_update_forum_topic_count( $destination_forum_id, true ); 1747 bbp_update_forum_topic_count_hidden( $destination_forum_id, false, true ); 1748 1749 // Transfer the public contribution between count types 1750 if ( bbp_is_topic_published( $from_reply_id ) ) { 1751 $user_id = bbp_get_topic_author_id( $from_reply_id ); 1752 bbp_bump_user_reply_count( $user_id, -1 ); 1753 bbp_bump_user_topic_count( $user_id, 1 ); 1754 } 1755 } 1756 1757 // Recount replies in both forums 1758 foreach ( bbp_get_unique_array_values( array( $source_forum_id, $destination_forum_id ) ) as $forum_id ) { 1759 bbp_update_forum_reply_count( $forum_id, true ); 1760 bbp_update_forum_reply_count_hidden( $forum_id, true ); 1761 } 1732 1762 1733 1763 // Topic Reply Counts … … 1739 1769 bbp_update_topic_reply_count_hidden( $destination_topic_id ); 1740 1770 1741 // Topic Voice Counts 1771 // Topic Engagement and Voice Counts 1772 bbp_recalculate_topic_engagements( $source_topic_id ); 1773 bbp_recalculate_topic_engagements( $destination_topic_id ); 1742 1774 bbp_update_topic_voice_count( $source_topic_id ); 1743 1775 bbp_update_topic_voice_count( $destination_topic_id ); … … 2405 2437 * 2406 2438 * @since 2.1.0 bbPress (r3825) 2439 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 2407 2440 * 2408 2441 * @param int $topic_id Optional. Topic id. … … 2422 2455 $reply_count = bbp_get_topic_reply_count( $topic_id, true ); 2423 2456 $difference = (int) $difference; 2424 $new_count = (int)( $reply_count + $difference );2457 $new_count = bbp_number_not_negative( $reply_count + $difference ); 2425 2458 2426 2459 // Update this topic id's reply count 2427 update_post_meta( $topic_id, '_bbp_reply_count', $new_count );2460 bbp_bump_count_meta( 'post', $topic_id, '_bbp_reply_count', $difference, $reply_count ); 2428 2461 2429 2462 // Filter & return … … 2495 2528 * 2496 2529 * @since 2.1.0 bbPress (r3825) 2530 * @since 2.6.16 Use atomic metadata writes and non-negative counts. 2497 2531 * 2498 2532 * @param int $topic_id Optional. Topic id. … … 2512 2546 $reply_count = bbp_get_topic_reply_count_hidden( $topic_id, true ); 2513 2547 $difference = (int) $difference; 2514 $new_count = (int)( $reply_count + $difference );2548 $new_count = bbp_number_not_negative( $reply_count + $difference ); 2515 2549 2516 2550 // Update this topic id's hidden reply count 2517 update_post_meta( $topic_id, '_bbp_reply_count_hidden', $new_count );2551 bbp_bump_count_meta( 'post', $topic_id, '_bbp_reply_count_hidden', $difference, $reply_count ); 2518 2552 2519 2553 // Filter & return -
trunk/src/includes/users/engagements.php
r7380 r7467 195 195 * 196 196 * @since 2.6.0 bbPress (r6522) 197 * @since 2.6.16 Honor filtered public reply statuses. 197 198 * 198 199 * @param int $topic_id Optional. Topic id. … … 203 204 204 205 // Default variables 205 $topic_id = bbp_get_topic_id( $topic_id ); 206 $bbp_db = bbp_db(); 207 $statii = "'" . implode( "', '", bbp_get_public_topic_statuses() ) . "'"; 208 209 // A cool UNION query! 210 $sql = " 211 SELECT DISTINCT( post_author ) FROM ( 212 SELECT post_author FROM {$bbp_db->posts} 213 WHERE ( ID = %d AND post_status IN ({$statii}) AND post_type = %s ) 214 UNION 215 SELECT post_author FROM {$bbp_db->posts} 216 WHERE ( post_parent = %d AND post_status = %s AND post_type = %s ) 217 ) as u1"; 218 219 // Prepare & get results 220 $query = $bbp_db->prepare( $sql, $topic_id, bbp_get_topic_post_type(), $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type() ); 221 $results = $bbp_db->get_col( $query ); 206 $topic_id = bbp_get_topic_id( $topic_id ); 207 $bbp_db = bbp_db(); 208 $topic_type = bbp_get_topic_post_type(); 209 $reply_type = bbp_get_reply_post_type(); 210 $topic_statuses = array_unique( array_filter( bbp_get_public_topic_statuses() ) ); 211 $reply_statuses = array_unique( array_filter( bbp_get_public_reply_statuses() ) ); 212 $sql = array(); 213 $values = array(); 214 215 // Add the topic author for countable topic statuses 216 if ( ! empty( $topic_statuses ) ) { 217 $placeholders = implode( ', ', array_fill( 0, count( $topic_statuses ), '%s' ) ); 218 $sql[] = "SELECT post_author FROM {$bbp_db->posts} WHERE ID = %d AND post_status IN ( {$placeholders} ) AND post_type = %s"; 219 $values = array_merge( $values, array( $topic_id ), $topic_statuses, array( $topic_type ) ); 220 } 221 222 // Add reply authors for countable reply statuses 223 if ( ! empty( $reply_statuses ) ) { 224 $placeholders = implode( ', ', array_fill( 0, count( $reply_statuses ), '%s' ) ); 225 $sql[] = "SELECT post_author FROM {$bbp_db->posts} WHERE post_parent = %d AND post_status IN ( {$placeholders} ) AND post_type = %s"; 226 $values = array_merge( $values, array( $topic_id ), $reply_statuses, array( $reply_type ) ); 227 } 228 229 // Query unique topic and reply authors 230 $results = ! empty( $sql ) 231 ? $bbp_db->get_col( $bbp_db->prepare( implode( ' UNION ', $sql ), $values ) ) 232 : array(); 222 233 223 234 // Parse results into voices 224 $engagements = ! is_wp_error( $results ) 225 ? wp_parse_id_list( array_filter( $results ) ) 226 : array(); 235 $engagements = wp_parse_id_list( array_filter( $results ) ); 227 236 228 237 // Filter & return -
trunk/src/includes/users/functions.php
r7452 r7467 720 720 : bbp_get_user_topic_count( $user_id, true ); 721 721 722 $user_topic_count = bbp_number_not_negative( $count + $difference );722 $user_topic_count = (int) bbp_number_not_negative( $count + $difference ); 723 723 724 724 // Add them up and filter them 725 725 $new_count = (int) apply_filters( 'bbp_bump_user_topic_count', $user_topic_count, $user_id, $difference, $count ); 726 726 727 return bbp_update_user_topic_count( $user_id, $new_count ); 727 // Preserve absolute count filters before using the atomic difference 728 $difference = ( $new_count === $user_topic_count ) 729 ? $new_count - $count 730 : false; 731 732 return bbp_update_user_topic_count( $user_id, $new_count, $difference ); 728 733 } 729 734 … … 756 761 : bbp_get_user_reply_count( $user_id, true ); 757 762 758 $user_reply_count = bbp_number_not_negative( $count + $difference );763 $user_reply_count = (int) bbp_number_not_negative( $count + $difference ); 759 764 760 765 // Add them up and filter them 761 766 $new_count = (int) apply_filters( 'bbp_bump_user_reply_count', $user_reply_count, $user_id, $difference, $count ); 762 767 763 return bbp_update_user_reply_count( $user_id, $new_count ); 768 // Preserve absolute count filters before using the atomic difference 769 $difference = ( $new_count === $user_reply_count ) 770 ? $new_count - $count 771 : false; 772 773 return bbp_update_user_reply_count( $user_id, $new_count, $difference ); 774 } 775 776 /** 777 * Update user counts when a topic or reply changes authors. 778 * 779 * @since 2.6.16 780 * 781 * @param int $post_id Post ID. 782 * @param WP_Post $post_after Post object following the update. 783 * @param WP_Post $post_before Post object before the update. 784 */ 785 function bbp_update_counts_on_post_author_change( $post_id = 0, $post_after = false, $post_before = false ) { 786 787 // Bail if the author or post type did not change as expected 788 if ( ( $post_after->post_author === $post_before->post_author ) || ( $post_after->post_type !== $post_before->post_type ) ) { 789 return; 790 } 791 792 // Set topic public membership 793 if ( bbp_get_topic_post_type() === $post_after->post_type ) { 794 $public_statuses = bbp_get_public_topic_statuses(); 795 $was_public = in_array( $post_before->post_status, $public_statuses, true ); 796 $is_public = in_array( $post_after->post_status, $public_statuses, true ); 797 $is_topic = true; 798 799 // Set reply public membership 800 } elseif ( bbp_get_reply_post_type() === $post_after->post_type ) { 801 $public_statuses = bbp_get_public_reply_statuses(); 802 $was_public = in_array( $post_before->post_status, $public_statuses, true ); 803 $is_public = in_array( $post_after->post_status, $public_statuses, true ); 804 $is_topic = false; 805 806 // Bail if this is not a topic or reply 807 } else { 808 return; 809 } 810 811 // The transition callback already handles posts that were not public 812 if ( ! $was_public ) { 813 return; 814 } 815 816 // Transfer a public contribution between authors 817 if ( $is_public ) { 818 if ( $is_topic ) { 819 bbp_bump_user_topic_count( $post_before->post_author, -1 ); 820 bbp_bump_user_topic_count( $post_after->post_author, 1 ); 821 } else { 822 bbp_bump_user_reply_count( $post_before->post_author, -1 ); 823 bbp_bump_user_reply_count( $post_after->post_author, 1 ); 824 } 825 826 // Repair both authors after the transition callback targeted the new author 827 } else { 828 foreach ( bbp_get_unique_array_values( array( $post_before->post_author, $post_after->post_author ) ) as $user_id ) { 829 if ( $is_topic ) { 830 bbp_update_user_topic_count( $user_id, bbp_get_user_topic_count_raw( $user_id ) ); 831 } else { 832 bbp_update_user_reply_count( $user_id, bbp_get_user_reply_count_raw( $user_id ) ); 833 } 834 } 835 } 836 } 837 838 /** 839 * Update topic engagements when a topic or reply changes authors. 840 * 841 * @since 2.6.16 842 * 843 * @param int $post_id Post ID. 844 * @param WP_Post $post_after Post object following the update. 845 * @param WP_Post $post_before Post object before the update. 846 */ 847 function bbp_recalculate_engagements_on_post_author_change( $post_id = 0, $post_after = false, $post_before = false ) { 848 849 // Bail if the author did not change 850 if ( $post_after->post_author === $post_before->post_author ) { 851 return; 852 } 853 854 // Get the topic ID from a topic or reply 855 if ( bbp_get_topic_post_type() === $post_after->post_type ) { 856 $topic_id = $post_id; 857 } elseif ( bbp_get_reply_post_type() === $post_after->post_type ) { 858 $topic_id = bbp_get_reply_topic_id( $post_id ); 859 } else { 860 return; 861 } 862 863 // Recalculate engagements and their count 864 bbp_recalculate_topic_engagements( $topic_id ); 865 bbp_update_topic_voice_count( $topic_id ); 866 } 867 868 /** 869 * Update counts and engagements when a deleted user's posts are reassigned. 870 * 871 * WordPress reassigns post authors directly in the database, bypassing the 872 * normal post update actions. Record affected topics before that write, then 873 * repair the replacement user's counts and those topics after it completes. 874 * 875 * @since 2.6.16 876 * 877 * @param int $user_id ID of the user being deleted. 878 * @param int|null $reassign ID of the user receiving the posts. 879 */ 880 function bbp_update_counts_on_user_reassignment( $user_id = 0, $reassign = null ) { 881 static $topic_ids = array(); 882 883 $user_id = (int) $user_id; 884 $reassign = (int) $reassign; 885 886 // Bail if posts are not being reassigned to another user 887 if ( empty( $user_id ) || empty( $reassign ) || ( $user_id === $reassign ) ) { 888 return; 889 } 890 891 $key = get_current_blog_id() . ':' . $user_id . ':' . $reassign; 892 893 // Record affected topics before WordPress changes their authors directly 894 if ( 'delete_user' === current_filter() ) { 895 $bbp_db = bbp_db(); 896 $topic_type = bbp_get_topic_post_type(); 897 $reply_type = bbp_get_reply_post_type(); 898 $query = $bbp_db->prepare( 899 "SELECT DISTINCT CASE WHEN post_type = %s THEN ID ELSE post_parent END FROM {$bbp_db->posts} WHERE post_author = %d AND post_type IN ( %s, %s )", 900 $topic_type, 901 $user_id, 902 $topic_type, 903 $reply_type 904 ); 905 906 $topic_ids[ $key ] = wp_parse_id_list( array_filter( $bbp_db->get_col( $query ) ) ); 907 return; 908 } 909 910 // Bail unless WordPress completed the reassignment recorded above 911 if ( ( 'deleted_user' !== current_filter() ) || ! isset( $topic_ids[ $key ] ) ) { 912 return; 913 } 914 915 $affected_topic_ids = $topic_ids[ $key ]; 916 unset( $topic_ids[ $key ] ); 917 918 // Bail if the deleted user did not author any topics or replies 919 if ( empty( $affected_topic_ids ) ) { 920 return; 921 } 922 923 // Recount contributions for the replacement user 924 bbp_update_user_topic_count( $reassign, bbp_get_user_topic_count_raw( $reassign ) ); 925 bbp_update_user_reply_count( $reassign, bbp_get_user_reply_count_raw( $reassign ) ); 926 927 // Rebuild engagements and voices for each affected topic 928 foreach ( $affected_topic_ids as $topic_id ) { 929 bbp_recalculate_topic_engagements( $topic_id, true ); 930 bbp_update_topic_voice_count( $topic_id ); 931 } 764 932 } 765 933 -
trunk/src/includes/users/options.php
r7380 r7467 124 124 * 125 125 * @since 2.6.0 bbPress (r5309) 126 * 127 * @param int $user_id 128 * @param mixed $count 126 * @since 2.6.16 Support atomic count differences. 127 * 128 * @param int $user_id User ID. 129 * @param mixed $count New topic count. 130 * @param int|false $difference Optional. Difference from the previous count. 129 131 * @return boolean 130 132 */ 131 function bbp_update_user_topic_count( $user_id = 0, $count = false ) {133 function bbp_update_user_topic_count( $user_id = 0, $count = false, $difference = false ) { 132 134 133 135 // Validate user id … … 138 140 139 141 // Just in time filtering of the user's topic count 142 $unfiltered_count = $count; 140 143 $count = apply_filters( 'bbp_update_user_topic_count', $count, $user_id ); 141 144 … … 145 148 } 146 149 150 // Atomically bump an unfiltered user option 151 if ( ( false !== $difference ) && ( $count === $unfiltered_count ) ) { 152 $default = (int) $unfiltered_count - (int) $difference; 153 $meta_key = bbp_db()->get_blog_prefix() . '_bbp_topic_count'; 154 $result = bbp_bump_count_meta( 'user', $user_id, $meta_key, $difference, $default ); 155 156 return $result; 157 } 158 147 159 // Return the updated user option 148 160 return update_user_option( $user_id, '_bbp_topic_count', $count ); … … 153 165 * 154 166 * @since 2.6.0 bbPress (r5309) 155 * 156 * @param int $user_id User id. 157 * @param mixed $count 167 * @since 2.6.16 Support atomic count differences. 168 * 169 * @param int $user_id User ID. 170 * @param mixed $count New reply count. 171 * @param int|false $difference Optional. Difference from the previous count. 158 172 * @return boolean 159 173 */ 160 function bbp_update_user_reply_count( $user_id = 0, $count = false ) {174 function bbp_update_user_reply_count( $user_id = 0, $count = false, $difference = false ) { 161 175 162 176 // Validate user id … … 167 181 168 182 // Just in time filtering of the user's reply count 183 $unfiltered_count = $count; 169 184 $count = apply_filters( 'bbp_update_user_reply_count', $count, $user_id ); 170 185 … … 172 187 if ( false === $count ) { 173 188 return false; 189 } 190 191 // Atomically bump an unfiltered user option 192 if ( ( false !== $difference ) && ( $count === $unfiltered_count ) ) { 193 $default = (int) $unfiltered_count - (int) $difference; 194 $meta_key = bbp_db()->get_blog_prefix() . '_bbp_reply_count'; 195 $result = bbp_bump_count_meta( 'user', $user_id, $meta_key, $difference, $default ); 196 197 return $result; 174 198 } 175 199 -
trunk/src/readme.txt
r7453 r7467 56 56 Permanent deletion does not produce a post-status transition. Its count maintenance continues through the existing `bbp_deleted_topic` and `bbp_deleted_reply` actions. 57 57 58 Count bump functions now use conditional metadata writes and bounded retries so simultaneous requests do not overwrite each other's existing count changes. Existing bbPress count filters and the standard WordPress metadata filters and actions continue to run. WordPress metadata tables do not enforce unique object-and-key pairs, so simultaneous first-time inserts retain the same limitation as the core metadata API. The `bbp_pre_bump_count_meta` filter can short-circuit an update, the `bbp_bump_count_meta_max_attempts` filter controls the default limit of five write attempts, and the `bbp_bump_count_meta_types` filter controls the post, user, term, and comment metadata types supported by default. `bbp_update_user_topic_count()` and `bbp_update_user_reply_count()` accept an optional third `$difference` argument for this internal bump lifecycle; existing calls remain compatible. 59 60 Post-author changes and user deletion with post reassignment now reconcile affected user contribution, topic engagement, and voice counts. Moderator move, merge, and split operations also reconcile source, destination, and ancestor forum counts. Forum count updater functions accept an optional final argument for propagating a recount's difference through ancestor totals; existing calls remain compatible. Forum reply recounts include public replies only when their parent topics are also public. A public reply beneath a non-public topic is excluded from the public forum total without being included in the pending, spammed, and trashed reply count. Topic engagement recounts honor filtered public topic and reply statuses, and preserve other term-backed relationships. 61 58 62 = Subforum counts in 2.6.16 = 59 63 60 bbPress now maintains subforum counts when forums are trashed, restored, permanently deleted, or moved between parents. The new `bbp_post_updated` action receives the post ID, the updated `WP_Post` object, and the previous `WP_Post` object after any bbPress post type is updated.64 bbPress now maintains subforum counts when forums are trashed, restored, permanently deleted, or moved between parents. Recursive forum counts include public, private, and hidden subforums while excluding subforums with uncountable statuses. The new `bbp_post_updated` action receives the post ID, the updated `WP_Post` object, and the previous `WP_Post` object after any bbPress post type is updated. 61 65 62 66 == Screenshots == -
trunk/tests/phpunit/testcases/admin/tools.php
r7453 r7467 371 371 $this->assertSame( 0, $count ); 372 372 373 // Category total topic count hidden. 374 $count = bbp_get_forum_topic_count_hidden( $c, true, true ); 375 $this->assertSame( 2, $count ); 376 373 377 // Forum topic count. 374 378 $count = bbp_get_forum_topic_count( $f, false, true ); … … 383 387 $this->assertSame( 2, $count ); 384 388 385 // Delete the _bbp_to tal_topic_countmeta key.389 // Delete the _bbp_topic_count_hidden meta key. 386 390 $this->assertTrue( delete_post_meta_by_key( '_bbp_topic_count_hidden' ) ); 391 392 // Delete the _bbp_total_topic_count_hidden meta key. 393 $this->assertTrue( delete_post_meta_by_key( '_bbp_total_topic_count_hidden' ) ); 387 394 388 395 // Delete the _bbp_total_topic_count meta key. … … 404 411 $this->assertSame( 0, $count ); 405 412 413 // Category total topic count hidden. 414 $count = bbp_get_forum_topic_count_hidden( $c, true, true ); 415 $this->assertSame( 0, $count ); 416 406 417 // Forum topic count. 407 418 $count = bbp_get_forum_topic_count( $f, false, true ); … … 431 442 $this->assertSame( 0, $count ); 432 443 444 // Category total topic count hidden. 445 $count = bbp_get_forum_topic_count_hidden( $c, true, true ); 446 $this->assertSame( 2, $count ); 447 433 448 // Forum topic count. 434 449 $count = bbp_get_forum_topic_count( $f, false, true ); … … 442 457 $count = bbp_get_forum_topic_count_hidden( $f, true, true ); 443 458 $this->assertSame( 2, $count ); 459 } 460 461 /** 462 * @covers ::bbp_admin_repair_forum_hidden_reply_count 463 */ 464 public function test_bbp_admin_repair_forum_hidden_reply_count() { 465 $c = $this->factory->forum->create( array( 466 'forum_meta' => array( 'forum_type' => 'category' ), 467 ) ); 468 $f = $this->factory->forum->create( array( 469 'post_parent' => $c, 470 'forum_meta' => array( 'forum_id' => $c ), 471 ) ); 472 $t = $this->factory->topic->create( array( 473 'post_parent' => $f, 474 'topic_meta' => array( 'forum_id' => $f ), 475 ) ); 476 477 $this->factory->reply->create( array( 478 'post_parent' => $t, 479 'post_status' => bbp_get_pending_status_id(), 480 'reply_meta' => array( 481 'forum_id' => $f, 482 'topic_id' => $t, 483 ), 484 ) ); 485 486 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $c, false, true ) ); 487 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $c, true, true ) ); 488 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $f, false, true ) ); 489 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $f, true, true ) ); 490 491 $this->assertTrue( delete_post_meta_by_key( '_bbp_reply_count_hidden' ) ); 492 $this->assertTrue( delete_post_meta_by_key( '_bbp_total_reply_count_hidden' ) ); 493 494 bbp_admin_repair_forum_hidden_reply_count(); 495 496 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $c, false, true ) ); 497 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $c, true, true ) ); 498 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $f, false, true ) ); 499 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $f, true, true ) ); 444 500 } 445 501 -
trunk/tests/phpunit/testcases/core/abstraction.php
r5898 r7467 32 32 33 33 /** 34 * @covers ::bbp_bump_count_meta 35 */ 36 public function test_bbp_bump_count_meta_handles_missing_and_non_negative_values() { 37 $post_id = self::factory()->post->create(); 38 39 $this->assertTrue( bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', 2, 3 ) ); 40 $this->assertSame( 5, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 41 $this->assertTrue( bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', -10 ) ); 42 $this->assertSame( 0, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 43 $this->assertFalse( bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', -1 ) ); 44 } 45 46 /** 47 * @covers ::bbp_bump_count_meta 48 */ 49 public function test_bbp_bump_count_meta_validates_required_values_before_filters() { 50 $filtered = 0; 51 $callback = function( $check ) use ( &$filtered ) { 52 $filtered++; 53 return $check; 54 }; 55 56 add_filter( 'bbp_pre_bump_count_meta', $callback ); 57 $this->assertFalse( bbp_bump_count_meta( 'post', 0, '_bbp_test_count' ) ); 58 $this->assertFalse( bbp_bump_count_meta( 'post', 1, '' ) ); 59 $this->assertFalse( bbp_bump_count_meta( 'post', 1, '_bbp_test_count', 0 ) ); 60 remove_filter( 'bbp_pre_bump_count_meta', $callback, 10 ); 61 62 $this->assertSame( 0, $filtered ); 63 } 64 65 /** 66 * @covers ::bbp_bump_count_meta 67 */ 68 public function test_bbp_bump_count_meta_can_be_short_circuited_before_type_validation() { 69 $meta_types_filtered = 0; 70 $received = array(); 71 $pre_callback = function( $check, $meta_type, $object_id, $meta_key, $difference, $default ) use ( &$received ) { 72 $received = func_get_args(); 73 return false; 74 }; 75 $types_callback = function( $meta_types ) use ( &$meta_types_filtered ) { 76 $meta_types_filtered++; 77 return $meta_types; 78 }; 79 80 add_filter( 'bbp_pre_bump_count_meta', $pre_callback, 10, 6 ); 81 add_filter( 'bbp_bump_count_meta_types', $types_callback ); 82 $result = bbp_bump_count_meta( 'invalid', 1, '_bbp_test_count' ); 83 remove_filter( 'bbp_bump_count_meta_types', $types_callback, 10 ); 84 remove_filter( 'bbp_pre_bump_count_meta', $pre_callback, 10 ); 85 86 $this->assertFalse( $result ); 87 $this->assertSame( array( null, 'invalid', 1, '_bbp_test_count', 1, 0 ), $received ); 88 $this->assertSame( 0, $meta_types_filtered ); 89 90 $pre_callback = function() { 91 return true; 92 }; 93 94 add_filter( 'bbp_pre_bump_count_meta', $pre_callback ); 95 $result = bbp_bump_count_meta( 'invalid', 1, '_bbp_test_count' ); 96 remove_filter( 'bbp_pre_bump_count_meta', $pre_callback, 10 ); 97 98 $this->assertTrue( $result ); 99 } 100 101 /** 102 * @covers ::bbp_bump_count_meta 103 */ 104 public function test_bbp_bump_count_meta_supports_user_term_and_comment_metadata() { 105 $post_id = self::factory()->post->create(); 106 $user_id = self::factory()->user->create(); 107 $term_id = self::factory()->term->create(); 108 $comment_id = self::factory()->comment->create( array( 'comment_post_ID' => $post_id ) ); 109 110 $this->assertTrue( bbp_bump_count_meta( 'user', $user_id, '_bbp_test_count', 1 ) ); 111 $this->assertSame( 1, (int) get_user_meta( $user_id, '_bbp_test_count', true ) ); 112 $this->assertTrue( bbp_bump_count_meta( 'term', $term_id, '_bbp_test_count', 2 ) ); 113 $this->assertSame( 2, (int) get_term_meta( $term_id, '_bbp_test_count', true ) ); 114 $this->assertTrue( bbp_bump_count_meta( 'comment', $comment_id, '_bbp_test_count', 3 ) ); 115 $this->assertSame( 3, (int) get_comment_meta( $comment_id, '_bbp_test_count', true ) ); 116 } 117 118 /** 119 * @covers ::bbp_bump_count_meta 120 */ 121 public function test_bbp_bump_count_meta_types_are_filterable() { 122 $term_id = self::factory()->term->create(); 123 $callback = function() { 124 return array( 'post' ); 125 }; 126 127 add_filter( 'bbp_bump_count_meta_types', $callback ); 128 $result = bbp_bump_count_meta( 'term', $term_id, '_bbp_test_count' ); 129 remove_filter( 'bbp_bump_count_meta_types', $callback, 10 ); 130 131 $this->assertFalse( $result ); 132 $this->assertSame( '', get_term_meta( $term_id, '_bbp_test_count', true ) ); 133 } 134 135 /** 136 * @covers ::bbp_bump_count_meta 137 */ 138 public function test_bbp_bump_count_meta_does_not_retry_a_filtered_update() { 139 $post_id = self::factory()->post->create(); 140 $updates = 0; 141 $callback = function() use ( &$updates ) { 142 $updates++; 143 return false; 144 }; 145 146 update_post_meta( $post_id, '_bbp_test_count', 5 ); 147 add_filter( 'update_post_metadata', $callback ); 148 $result = bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 149 remove_filter( 'update_post_metadata', $callback, 10 ); 150 151 $this->assertFalse( $result ); 152 $this->assertSame( 1, $updates ); 153 $this->assertSame( 5, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 154 } 155 156 /** 157 * @covers ::bbp_bump_count_meta 158 */ 159 public function test_bbp_bump_count_meta_filters_an_update_before_adding_metadata() { 160 $post_id = self::factory()->post->create(); 161 $previous = null; 162 $callback = function( $check, $filtered_post_id, $meta_key, $meta_value, $prev_value ) use ( &$previous ) { 163 $previous = $prev_value; 164 return false; 165 }; 166 167 add_filter( 'update_post_metadata', $callback, 10, 5 ); 168 $result = bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 169 remove_filter( 'update_post_metadata', $callback, 10 ); 170 171 $this->assertFalse( $result ); 172 $this->assertSame( '', $previous ); 173 $this->assertSame( '', get_post_meta( $post_id, '_bbp_test_count', true ) ); 174 } 175 176 /** 177 * @covers ::bbp_bump_count_meta 178 * @ticket BBP3678 179 */ 180 public function test_bbp_bump_count_meta_uses_the_database_after_a_filtered_read() { 181 $post_id = self::factory()->post->create(); 182 $callback = function( $value, $filtered_post_id, $meta_key ) use ( $post_id ) { 183 return ( ( $post_id === $filtered_post_id ) && ( '_bbp_test_count' === $meta_key ) ) 184 ? 100 185 : $value; 186 }; 187 188 update_post_meta( $post_id, '_bbp_test_count', 5 ); 189 add_filter( 'get_post_metadata', $callback, 10, 3 ); 190 $result = bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 191 remove_filter( 'get_post_metadata', $callback, 10 ); 192 193 $this->assertTrue( $result ); 194 $this->assertSame( 6, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 195 } 196 197 /** 198 * @covers ::bbp_bump_count_meta 199 */ 200 public function test_bbp_bump_count_meta_returns_false_when_adding_metadata_fails() { 201 $post_id = self::factory()->post->create(); 202 $callback = function() { 203 return false; 204 }; 205 206 add_filter( 'add_post_metadata', $callback ); 207 $result = bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 208 remove_filter( 'add_post_metadata', $callback, 10 ); 209 210 $this->assertFalse( $result ); 211 $this->assertSame( '', get_post_meta( $post_id, '_bbp_test_count', true ) ); 212 } 213 214 /** 215 * @covers ::bbp_bump_count_meta 216 * @ticket BBP3678 217 */ 218 public function test_bbp_bump_count_meta_preserves_an_interleaved_update_from_zero() { 219 $post_id = self::factory()->post->create(); 220 $interleaved = false; 221 $callback = function( $check, $filtered_post_id, $meta_key ) use ( $post_id, &$interleaved ) { 222 if ( ( $post_id === $filtered_post_id ) && ( '_bbp_test_count' === $meta_key ) && ! $interleaved ) { 223 $interleaved = true; 224 bbp_bump_count_meta( 'post', $post_id, $meta_key ); 225 } 226 227 return $check; 228 }; 229 230 update_post_meta( $post_id, '_bbp_test_count', 0 ); 231 add_filter( 'update_post_metadata', $callback, 10, 3 ); 232 bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 233 remove_filter( 'update_post_metadata', $callback, 10 ); 234 235 $this->assertSame( 2, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 236 } 237 238 /** 239 * @covers ::bbp_bump_count_meta 240 * @ticket BBP3678 241 */ 242 public function test_bbp_bump_count_meta_preserves_interleaved_decrements() { 243 $post_id = self::factory()->post->create(); 244 $interleaved = false; 245 $filter_calls = 0; 246 $callback = function( $check, $filtered_post_id, $meta_key ) use ( $post_id, &$interleaved, &$filter_calls ) { 247 $filter_calls++; 248 249 if ( ( $post_id === $filtered_post_id ) && ( '_bbp_test_count' === $meta_key ) && ! $interleaved ) { 250 $interleaved = true; 251 bbp_bump_count_meta( 'post', $post_id, $meta_key, -1 ); 252 } 253 254 return $check; 255 }; 256 257 update_post_meta( $post_id, '_bbp_test_count', 3 ); 258 add_filter( 'update_post_metadata', $callback, 10, 3 ); 259 bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', -1 ); 260 remove_filter( 'update_post_metadata', $callback, 10 ); 261 262 $this->assertSame( 1, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 263 $this->assertSame( 2, $filter_calls ); 264 } 265 266 /** 267 * @covers ::bbp_bump_count_meta 268 * @ticket BBP3678 269 */ 270 public function test_bbp_bump_count_meta_refreshes_a_stale_zero_before_decrementing() { 271 global $wpdb; 272 273 $post_id = self::factory()->post->create(); 274 275 update_post_meta( $post_id, '_bbp_test_count', 0 ); 276 get_post_meta( $post_id, '_bbp_test_count', true ); 277 278 $wpdb->update( 279 $wpdb->postmeta, 280 array( 'meta_value' => 1 ), 281 array( 282 'post_id' => $post_id, 283 'meta_key' => '_bbp_test_count' 284 ), 285 array( '%d' ), 286 array( '%d', '%s' ) 287 ); 288 289 $this->assertTrue( bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', -1 ) ); 290 $this->assertSame( 0, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 291 } 292 293 /** 294 * @covers ::bbp_bump_count_meta 295 * @ticket BBP3678 296 */ 297 public function test_bbp_bump_count_meta_max_attempts_is_filterable() { 298 $post_id = self::factory()->post->create(); 299 $interleaved = false; 300 $callback = function( $check, $filtered_post_id, $meta_key ) use ( $post_id, &$interleaved ) { 301 if ( ( $post_id === $filtered_post_id ) && ( '_bbp_test_count' === $meta_key ) && ! $interleaved ) { 302 $interleaved = true; 303 bbp_bump_count_meta( 'post', $post_id, $meta_key, -1 ); 304 } 305 306 return $check; 307 }; 308 $max_attempts = function() { 309 return 1; 310 }; 311 312 update_post_meta( $post_id, '_bbp_test_count', 3 ); 313 add_filter( 'update_post_metadata', $callback, 10, 3 ); 314 add_filter( 'bbp_bump_count_meta_max_attempts', $max_attempts ); 315 $result = bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count', -1 ); 316 remove_filter( 'bbp_bump_count_meta_max_attempts', $max_attempts, 10 ); 317 remove_filter( 'update_post_metadata', $callback, 10 ); 318 319 $this->assertFalse( $result ); 320 $this->assertSame( 2, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 321 } 322 323 /** 324 * @covers ::bbp_bump_count_meta 325 * @ticket BBP3678 326 */ 327 public function test_bbp_bump_count_meta_preserves_an_interleaved_add() { 328 $post_id = self::factory()->post->create(); 329 $interleaved = false; 330 $callback = function( $check, $filtered_post_id, $meta_key ) use ( $post_id, &$interleaved ) { 331 if ( ( $post_id === $filtered_post_id ) && ( '_bbp_test_count' === $meta_key ) && ! $interleaved ) { 332 $interleaved = true; 333 bbp_bump_count_meta( 'post', $post_id, $meta_key ); 334 } 335 336 return $check; 337 }; 338 339 add_filter( 'add_post_metadata', $callback, 10, 3 ); 340 bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 341 remove_filter( 'add_post_metadata', $callback, 10 ); 342 343 $this->assertSame( 2, (int) get_post_meta( $post_id, '_bbp_test_count', true ) ); 344 } 345 346 /** 347 * @covers ::bbp_bump_count_meta 348 */ 349 public function test_bbp_bump_count_meta_runs_standard_metadata_actions() { 350 $post_id = self::factory()->post->create(); 351 $updated = 0; 352 $legacy_updated = 0; 353 $callback = function( $meta_id, $updated_post_id, $meta_key, $meta_value ) use ( $post_id, &$updated ) { 354 if ( ( $post_id === $updated_post_id ) && ( '_bbp_test_count' === $meta_key ) && ( 2 === $meta_value ) ) { 355 $updated++; 356 } 357 }; 358 $legacy_callback = function( $meta_id, $updated_post_id, $meta_key, $meta_value ) use ( $post_id, &$legacy_updated ) { 359 if ( ( $post_id === $updated_post_id ) && ( '_bbp_test_count' === $meta_key ) && ( 2 === $meta_value ) ) { 360 $legacy_updated++; 361 } 362 }; 363 364 update_post_meta( $post_id, '_bbp_test_count', 1 ); 365 add_action( 'updated_post_meta', $callback, 10, 4 ); 366 add_action( 'updated_postmeta', $legacy_callback, 10, 4 ); 367 bbp_bump_count_meta( 'post', $post_id, '_bbp_test_count' ); 368 remove_action( 'updated_post_meta', $callback, 10 ); 369 remove_action( 'updated_postmeta', $legacy_callback, 10 ); 370 371 $this->assertSame( 1, $updated ); 372 $this->assertSame( 1, $legacy_updated ); 373 } 374 375 /** 34 376 * @covers ::bbp_rewrite 35 377 * @todo Implement test_bbp_rewrite(). -
trunk/tests/phpunit/testcases/forums/functions/counts.php
r7453 r7467 11 11 12 12 /** 13 * @covers BBPress::register_meta 14 */ 15 public function test_hidden_total_count_meta_is_registered() { 16 bbpress()->register_meta(); 17 18 $registered = get_registered_meta_keys( 'post', bbp_get_forum_post_type() ); 19 20 $this->assertArrayHasKey( '_bbp_total_topic_count_hidden', $registered ); 21 $this->assertArrayHasKey( '_bbp_total_reply_count_hidden', $registered ); 22 } 23 24 /** 13 25 * @covers ::bbp_get_countable_forum_statuses 14 26 */ … … 34 46 35 47 /** 48 * @covers ::bbp_update_forum_topic_count_hidden 49 * @covers ::bbp_forum_query_subforum_ids 50 * @ticket BBP3678 51 */ 52 public function test_hidden_topic_counts_exclude_trashed_subforums() { 53 $parent_id = $this->factory->forum->create( array( 54 'forum_meta' => array( 'forum_type' => 'category' ), 55 ) ); 56 $forum_id = $this->factory->forum->create( array( 57 'post_parent' => $parent_id, 58 'forum_meta' => array( 'forum_id' => $parent_id ), 59 ) ); 60 $this->factory->topic->create( array( 61 'post_parent' => $forum_id, 62 'post_status' => bbp_get_spam_status_id(), 63 'topic_meta' => array( 'forum_id' => $forum_id ), 64 ) ); 65 66 $this->assertSame( 0, bbp_update_forum_topic_count_hidden( $parent_id ) ); 67 $this->assertSame( 1, bbp_get_forum_topic_count_hidden( $parent_id, true, true ) ); 68 69 wp_trash_post( $forum_id ); 70 71 $this->assertSame( 0, bbp_update_forum_topic_count_hidden( $parent_id ) ); 72 } 73 74 /** 75 * @covers ::bbp_bump_forum_ancestor_count 76 * @ticket BBP3678 77 */ 78 public function test_bbp_bump_forum_ancestor_count_stops_outside_forum_hierarchy() { 79 $forum_id = $this->factory->forum->create(); 80 $topic_id = $this->factory->topic->create( array( 81 'post_parent' => $forum_id, 82 'topic_meta' => array( 'forum_id' => $forum_id ), 83 ) ); 84 $subforum_id = $this->factory->forum->create( array( 85 'post_parent' => $topic_id, 86 'forum_meta' => array( 'forum_id' => $topic_id ), 87 ) ); 88 89 update_post_meta( $forum_id, '_bbp_total_topic_count', 2 ); 90 update_post_meta( $topic_id, '_bbp_total_topic_count', 3 ); 91 92 bbp_bump_forum_ancestor_count( $subforum_id, '_bbp_total_topic_count', 1 ); 93 94 $this->assertSame( 2, (int) get_post_meta( $forum_id, '_bbp_total_topic_count', true ) ); 95 $this->assertSame( 3, (int) get_post_meta( $topic_id, '_bbp_total_topic_count', true ) ); 96 } 97 98 /** 36 99 * Generic function to test the forum counts with a new topic 37 100 * … … 90 153 91 154 /** 155 * @covers ::bbp_update_counts_on_transition_post_status 156 */ 157 public function test_bbp_forum_draft_topic_is_not_counted_as_hidden() { 158 $user_id = $this->factory->user->create(); 159 $forum_id = $this->factory->forum->create(); 160 $topic_id = $this->factory->topic->create( array( 161 'post_author' => $user_id, 162 'post_parent' => $forum_id, 163 'post_status' => 'draft', 164 'topic_meta' => array( 'forum_id' => $forum_id ), 165 ) ); 166 167 $this->assertSame( 0, bbp_get_forum_topic_count( $forum_id, false, true ) ); 168 $this->assertSame( 0, bbp_get_forum_topic_count_hidden( $forum_id, false, true ) ); 169 170 wp_update_post( array( 171 'ID' => $topic_id, 172 'post_status' => bbp_get_pending_status_id(), 173 ) ); 174 $this->assertSame( 1, bbp_get_forum_topic_count_hidden( $forum_id, false, true ) ); 175 176 wp_update_post( array( 177 'ID' => $topic_id, 178 'post_status' => 'draft', 179 ) ); 180 $this->assertSame( 0, bbp_get_forum_topic_count_hidden( $forum_id, false, true ) ); 181 } 182 183 /** 92 184 * Generic function to test the forum counts on a trashed/untrashed topic 93 185 */ … … 266 358 267 359 /** 360 * @covers ::bbp_update_counts_on_transition_post_status 361 */ 362 public function test_bbp_forum_reply_count_stays_excluded_when_pending_topic_is_trashed_and_restored() { 363 $forum_id = $this->factory->forum->create(); 364 $topic_id = $this->factory->topic->create( array( 365 'post_parent' => $forum_id, 366 'topic_meta' => array( 'forum_id' => $forum_id ), 367 ) ); 368 369 $this->factory->reply->create( array( 370 'post_parent' => $topic_id, 371 'post_status' => bbp_get_public_status_id(), 372 'reply_meta' => array( 373 'forum_id' => $forum_id, 374 'topic_id' => $topic_id, 375 ), 376 ) ); 377 378 bbp_unapprove_topic( $topic_id ); 379 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 380 381 wp_trash_post( $topic_id ); 382 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 383 384 wp_untrash_post( $topic_id ); 385 $this->assertSame( bbp_get_pending_status_id(), bbp_get_topic_status( $topic_id ) ); 386 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 387 } 388 389 /** 390 * @covers ::bbp_update_counts_on_transition_post_status 391 * @ticket BBP3678 392 */ 393 public function test_topic_status_transition_updates_ancestor_forum_reply_counts() { 394 $parent_id = $this->factory->forum->create( array( 395 'forum_meta' => array( 'forum_type' => 'category' ), 396 ) ); 397 $forum_id = $this->factory->forum->create( array( 398 'post_parent' => $parent_id, 399 'forum_meta' => array( 'forum_id' => $parent_id ), 400 ) ); 401 $topic_id = $this->factory->topic->create( array( 402 'post_parent' => $forum_id, 403 'topic_meta' => array( 'forum_id' => $forum_id ), 404 ) ); 405 $this->factory->reply->create( array( 406 'post_parent' => $topic_id, 407 'reply_meta' => array( 408 'forum_id' => $forum_id, 409 'topic_id' => $topic_id, 410 ), 411 ) ); 412 413 $this->assertSame( 1, bbp_get_forum_reply_count( $parent_id, true, true ) ); 414 415 bbp_unapprove_topic( $topic_id ); 416 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 417 $this->assertSame( 0, bbp_get_forum_reply_count( $parent_id, true, true ) ); 418 419 bbp_approve_topic( $topic_id ); 420 $this->assertSame( 1, bbp_get_forum_reply_count( $forum_id, true, true ) ); 421 $this->assertSame( 1, bbp_get_forum_reply_count( $parent_id, true, true ) ); 422 } 423 424 /** 425 * @covers ::bbp_update_counts_on_transition_post_status 426 */ 427 public function test_bbp_forum_reply_count_excludes_new_public_reply_in_pending_topic() { 428 $forum_id = $this->factory->forum->create(); 429 $topic_id = $this->factory->topic->create( array( 430 'post_parent' => $forum_id, 431 'post_status' => bbp_get_pending_status_id(), 432 'topic_meta' => array( 'forum_id' => $forum_id ), 433 ) ); 434 435 $this->factory->reply->create( array( 436 'post_parent' => $topic_id, 437 'post_status' => bbp_get_public_status_id(), 438 'reply_meta' => array( 439 'forum_id' => $forum_id, 440 'topic_id' => $topic_id, 441 ), 442 ) ); 443 444 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 445 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $forum_id, true, true ) ); 446 $this->assertSame( 1, bbp_get_topic_reply_count( $topic_id, true ) ); 447 $this->assertSame( 0, bbp_update_forum_reply_count( $forum_id ) ); 448 } 449 450 /** 268 451 * @covers ::bbp_bump_forum_topic_count 269 452 */ … … 278 461 $count = bbp_get_forum_topic_count( $f ); 279 462 $this->assertSame( '1', $count ); 463 } 464 465 /** 466 * @covers ::bbp_bump_forum_topic_count 467 * @ticket BBP3678 468 */ 469 public function test_bbp_bump_forum_topic_count_preserves_an_interleaved_update() { 470 $forum_id = $this->factory->forum->create(); 471 $interleaved = false; 472 $callback = function( $count, $filtered_forum_id ) use ( &$interleaved ) { 473 if ( ! $interleaved ) { 474 $interleaved = true; 475 bbp_bump_forum_topic_count( $filtered_forum_id ); 476 } 477 478 return $count; 479 }; 480 481 add_filter( 'bbp_get_forum_topic_count_int', $callback, 10, 2 ); 482 bbp_bump_forum_topic_count( $forum_id ); 483 remove_filter( 'bbp_get_forum_topic_count_int', $callback, 10 ); 484 485 $this->assertSame( 2, bbp_get_forum_topic_count( $forum_id, false, true ) ); 486 $this->assertSame( 2, bbp_get_forum_topic_count( $forum_id, true, true ) ); 280 487 } 281 488 … … 702 909 703 910 /** 911 * @covers ::bbp_update_forum_topic_count_hidden 912 */ 913 public function test_bbp_update_forum_topic_count_hidden_rebuilds_total_counts() { 914 $parent_id = $this->factory->forum->create(); 915 $child_id = $this->factory->forum->create( array( 'post_parent' => $parent_id ) ); 916 917 $this->factory->topic->create( array( 918 'post_parent' => $child_id, 919 'post_status' => bbp_get_pending_status_id(), 920 'topic_meta' => array( 'forum_id' => $child_id ), 921 ) ); 922 923 update_post_meta( $parent_id, '_bbp_total_topic_count_hidden', 99 ); 924 update_post_meta( $child_id, '_bbp_total_topic_count_hidden', 99 ); 925 926 $this->assertSame( 0, bbp_update_forum_topic_count_hidden( $parent_id ) ); 927 $this->assertSame( 0, bbp_get_forum_topic_count_hidden( $parent_id, false, true ) ); 928 $this->assertSame( 1, bbp_get_forum_topic_count_hidden( $parent_id, true, true ) ); 929 $this->assertSame( 1, bbp_get_forum_topic_count_hidden( $child_id, true, true ) ); 930 } 931 932 /** 704 933 * @covers ::bbp_update_forum_reply_count 705 934 */ -
trunk/tests/phpunit/testcases/forums/functions/query.php
r6077 r7467 69 69 70 70 /** 71 * @covers ::bbp_forum_query_subforum_ids 72 * @ticket BBP3678 73 */ 74 public function test_bbp_forum_query_subforum_ids_excludes_uncountable_statuses() { 75 $this->assertSame( array(), bbp_forum_query_subforum_ids( 0 ) ); 76 77 $parent_id = $this->factory->forum->create(); 78 $public_id = $this->factory->forum->create( array( 79 'post_parent' => $parent_id, 80 ) ); 81 $hidden_id = $this->factory->forum->create( array( 82 'post_parent' => $parent_id, 83 'post_status' => bbp_get_hidden_status_id(), 84 ) ); 85 $private_id = $this->factory->forum->create( array( 86 'post_parent' => $parent_id, 87 'post_status' => bbp_get_private_status_id(), 88 ) ); 89 $trash_id = $this->factory->forum->create( array( 90 'post_parent' => $parent_id, 91 ) ); 92 wp_update_post( array( 93 'ID' => $trash_id, 94 'post_status' => bbp_get_trash_status_id(), 95 ) ); 96 97 $this->assertEqualSets( array( $public_id, $private_id, $hidden_id ), bbp_forum_query_subforum_ids( $parent_id ) ); 98 } 99 100 /** 71 101 * @covers ::bbp_forum_query_last_reply_id 72 102 */ -
trunk/tests/phpunit/testcases/replies/functions/reply.php
r7455 r7467 250 250 /** 251 251 * @covers ::bbp_move_reply_count 252 * @todo Implement test_bbp_move_reply_count().253 252 */ 254 253 public function test_bbp_move_reply_count() { 255 // Remove the following lines when you implement this test. 256 $this->markTestIncomplete( 257 'This test has not been implemented yet.' 258 ); 254 $topic_author_id = $this->factory->user->create(); 255 $reply_author_id = $this->factory->user->create(); 256 $destination_author_id = $this->factory->user->create(); 257 $source_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 258 $destination_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 259 $source_forum_id = $this->factory->forum->create( array( 'post_parent' => $source_parent_id ) ); 260 $destination_forum_id = $this->factory->forum->create( array( 'post_parent' => $destination_parent_id ) ); 261 $source_topic_id = $this->factory->topic->create( array( 262 'post_author' => $topic_author_id, 263 'post_parent' => $source_forum_id, 264 'topic_meta' => array( 'forum_id' => $source_forum_id ), 265 ) ); 266 $destination_topic_id = $this->factory->topic->create( array( 267 'post_author' => $destination_author_id, 268 'post_parent' => $destination_forum_id, 269 'topic_meta' => array( 'forum_id' => $destination_forum_id ), 270 ) ); 271 $reply_id = $this->factory->reply->create( array( 272 'post_author' => $reply_author_id, 273 'post_parent' => $source_topic_id, 274 'reply_meta' => array( 275 'forum_id' => $source_forum_id, 276 'topic_id' => $source_topic_id, 277 ), 278 ) ); 279 280 wp_update_post( array( 281 'ID' => $reply_id, 282 'post_parent' => $destination_topic_id, 283 ) ); 284 bbp_update_reply_topic_id( $reply_id, $destination_topic_id ); 285 bbp_update_reply_forum_id( $reply_id, $destination_forum_id ); 286 bbp_move_reply_count( $reply_id, $source_topic_id, $destination_topic_id ); 287 288 $this->assertSame( 0, bbp_get_forum_reply_count( $source_forum_id, true, true ) ); 289 $this->assertSame( 1, bbp_get_forum_reply_count( $destination_forum_id, true, true ) ); 290 $this->assertSame( 0, bbp_get_forum_reply_count( $source_parent_id, true, true ) ); 291 $this->assertSame( 1, bbp_get_forum_reply_count( $destination_parent_id, true, true ) ); 292 $this->assertSame( 0, bbp_get_topic_reply_count( $source_topic_id, true ) ); 293 $this->assertSame( 1, bbp_get_topic_reply_count( $destination_topic_id, true ) ); 294 $this->assertEqualSets( array( $topic_author_id ), bbp_get_topic_engagements( $source_topic_id ) ); 295 $this->assertEqualSets( array( $reply_author_id, $destination_author_id ), bbp_get_topic_engagements( $destination_topic_id ) ); 296 $this->assertSame( 1, bbp_get_topic_voice_count( $source_topic_id, true ) ); 297 $this->assertSame( 2, bbp_get_topic_voice_count( $destination_topic_id, true ) ); 298 } 299 300 /** 301 * @covers ::bbp_move_reply_count 302 */ 303 public function test_bbp_move_reply_count_updates_hidden_counts() { 304 $source_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 305 $destination_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 306 $source_forum_id = $this->factory->forum->create( array( 'post_parent' => $source_parent_id ) ); 307 $destination_forum_id = $this->factory->forum->create( array( 'post_parent' => $destination_parent_id ) ); 308 $source_topic_id = $this->factory->topic->create( array( 309 'post_parent' => $source_forum_id, 310 'topic_meta' => array( 'forum_id' => $source_forum_id ), 311 ) ); 312 $destination_topic_id = $this->factory->topic->create( array( 313 'post_parent' => $destination_forum_id, 314 'topic_meta' => array( 'forum_id' => $destination_forum_id ), 315 ) ); 316 $reply_id = $this->factory->reply->create( array( 317 'post_parent' => $source_topic_id, 318 'post_status' => bbp_get_pending_status_id(), 319 'reply_meta' => array( 320 'forum_id' => $source_forum_id, 321 'topic_id' => $source_topic_id, 322 ), 323 ) ); 324 325 wp_update_post( array( 326 'ID' => $reply_id, 327 'post_parent' => $destination_topic_id, 328 ) ); 329 bbp_update_reply_topic_id( $reply_id, $destination_topic_id ); 330 bbp_update_reply_forum_id( $reply_id, $destination_forum_id ); 331 bbp_move_reply_count( $reply_id, $source_topic_id, $destination_topic_id ); 332 333 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $source_forum_id, true, true ) ); 334 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $destination_forum_id, true, true ) ); 335 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $source_parent_id, true, true ) ); 336 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $destination_parent_id, true, true ) ); 337 $this->assertSame( 0, bbp_get_topic_reply_count_hidden( $source_topic_id, true ) ); 338 $this->assertSame( 1, bbp_get_topic_reply_count_hidden( $destination_topic_id, true ) ); 339 } 340 341 /** 342 * @covers ::bbp_move_reply_count 343 */ 344 public function test_bbp_move_reply_count_transfers_contribution_when_converted_to_topic() { 345 $user_id = $this->factory->user->create(); 346 $forum_id = $this->factory->forum->create(); 347 $topic_id = $this->factory->topic->create( array( 348 'post_parent' => $forum_id, 349 'topic_meta' => array( 'forum_id' => $forum_id ), 350 ) ); 351 $reply_id = $this->factory->reply->create( array( 352 'post_author' => $user_id, 353 'post_parent' => $topic_id, 354 'reply_meta' => array( 355 'forum_id' => $forum_id, 356 'topic_id' => $topic_id, 357 ), 358 ) ); 359 360 wp_update_post( array( 361 'ID' => $reply_id, 362 'post_parent' => $forum_id, 363 'post_type' => bbp_get_topic_post_type(), 364 ) ); 365 bbp_update_topic_forum_id( $reply_id, $forum_id ); 366 bbp_update_topic_topic_id( $reply_id ); 367 bbp_move_reply_count( $reply_id, $topic_id, $reply_id ); 368 369 $this->assertSame( 0, bbp_get_user_reply_count( $user_id, true ) ); 370 $this->assertSame( 1, bbp_get_user_topic_count( $user_id, true ) ); 371 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 372 $this->assertSame( 2, bbp_get_forum_topic_count( $forum_id, true, true ) ); 259 373 } 260 374 -
trunk/tests/phpunit/testcases/topics/functions/counts.php
r7449 r7467 92 92 93 93 /** 94 * @covers ::bbp_update_counts_on_transition_post_status 95 */ 96 public function test_bbp_topic_draft_reply_is_not_counted_as_hidden() { 97 $forum_id = $this->factory->forum->create(); 98 $topic_id = $this->factory->topic->create( array( 99 'post_parent' => $forum_id, 100 'topic_meta' => array( 'forum_id' => $forum_id ), 101 ) ); 102 $reply_id = $this->factory->reply->create( array( 103 'post_parent' => $topic_id, 104 'post_status' => 'draft', 105 'reply_meta' => array( 106 'forum_id' => $forum_id, 107 'topic_id' => $topic_id, 108 ), 109 ) ); 110 111 $this->assertSame( 0, bbp_get_topic_reply_count_hidden( $topic_id, true ) ); 112 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $forum_id, false, true ) ); 113 114 wp_update_post( array( 115 'ID' => $reply_id, 116 'post_status' => bbp_get_pending_status_id(), 117 ) ); 118 $this->assertSame( 1, bbp_get_topic_reply_count_hidden( $topic_id, true ) ); 119 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $forum_id, false, true ) ); 120 121 wp_update_post( array( 122 'ID' => $reply_id, 123 'post_status' => 'draft', 124 ) ); 125 $this->assertSame( 0, bbp_get_topic_reply_count_hidden( $topic_id, true ) ); 126 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $forum_id, false, true ) ); 127 } 128 129 /** 94 130 * Generic function to test the topic counts on a deleted reply 95 131 */ … … 380 416 381 417 /** 418 * @covers ::bbp_bump_topic_reply_count 419 * @ticket BBP3678 420 */ 421 public function test_bbp_bump_topic_reply_count_preserves_an_interleaved_update() { 422 $topic_id = $this->factory->topic->create(); 423 $interleaved = false; 424 $callback = function( $count, $filtered_topic_id ) use ( &$interleaved ) { 425 if ( ! $interleaved ) { 426 $interleaved = true; 427 bbp_bump_topic_reply_count( $filtered_topic_id ); 428 } 429 430 return $count; 431 }; 432 433 add_filter( 'bbp_get_topic_reply_count_int', $callback, 10, 2 ); 434 bbp_bump_topic_reply_count( $topic_id ); 435 remove_filter( 'bbp_get_topic_reply_count_int', $callback, 10 ); 436 437 $this->assertSame( 2, bbp_get_topic_reply_count( $topic_id, true ) ); 438 } 439 440 /** 382 441 * @covers ::bbp_decrease_topic_reply_count 383 442 */ … … 589 648 $count = bbp_get_topic_voice_count( $t ); 590 649 $this->assertSame( '2', $count ); 650 } 651 652 /** 653 * @covers ::bbp_get_topic_engagements_raw 654 * @covers ::bbp_recalculate_topic_engagements 655 * @covers ::bbp_update_topic_voice_count 656 * @ticket BBP3678 657 */ 658 public function test_topic_voice_count_honors_filtered_public_reply_statuses() { 659 $topic_author_id = $this->factory->user->create(); 660 $reply_author_id = $this->factory->user->create(); 661 $forum_id = $this->factory->forum->create(); 662 $topic_id = $this->factory->topic->create( array( 663 'post_author' => $topic_author_id, 664 'post_parent' => $forum_id, 665 'topic_meta' => array( 'forum_id' => $forum_id ), 666 ) ); 667 $public_statuses = function( $statuses ) { 668 $statuses[] = 'private'; 669 return $statuses; 670 }; 671 672 add_filter( 'bbp_get_public_reply_statuses', $public_statuses ); 673 674 try { 675 $this->factory->reply->create( array( 676 'post_author' => $reply_author_id, 677 'post_parent' => $topic_id, 678 'post_status' => 'private', 679 'reply_meta' => array( 680 'forum_id' => $forum_id, 681 'topic_id' => $topic_id, 682 ), 683 ) ); 684 685 bbp_recalculate_topic_engagements( $topic_id, true ); 686 bbp_update_topic_voice_count( $topic_id ); 687 } finally { 688 remove_filter( 'bbp_get_public_reply_statuses', $public_statuses, 10 ); 689 } 690 691 $this->assertSame( array( $topic_author_id, $reply_author_id ), bbp_get_topic_engagements( $topic_id ) ); 692 $this->assertSame( 2, bbp_get_topic_voice_count( $topic_id, true ) ); 591 693 } 592 694 -
trunk/tests/phpunit/testcases/topics/functions/topic.php
r7455 r7467 274 274 /** 275 275 * @covers ::bbp_merge_topic_count 276 * @todo Implement test_bbp_merge_topic_count().277 276 */ 278 277 public function test_bbp_merge_topic_count() { 279 // Remove the following lines when you implement this test. 280 $this->markTestIncomplete( 281 'This test has not been implemented yet.' 282 ); 278 $source_author_id = $this->factory->user->create(); 279 $reply_author_id = $this->factory->user->create(); 280 $destination_author_id = $this->factory->user->create(); 281 $source_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 282 $destination_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 283 $source_forum_id = $this->factory->forum->create( array( 'post_parent' => $source_parent_id ) ); 284 $destination_forum_id = $this->factory->forum->create( array( 'post_parent' => $destination_parent_id ) ); 285 $source_topic_id = $this->factory->topic->create( array( 286 'post_author' => $source_author_id, 287 'post_parent' => $source_forum_id, 288 'topic_meta' => array( 'forum_id' => $source_forum_id ), 289 ) ); 290 $destination_topic_id = $this->factory->topic->create( array( 291 'post_author' => $destination_author_id, 292 'post_parent' => $destination_forum_id, 293 'topic_meta' => array( 'forum_id' => $destination_forum_id ), 294 ) ); 295 $reply_id = $this->factory->reply->create( array( 296 'post_author' => $reply_author_id, 297 'post_parent' => $source_topic_id, 298 'reply_meta' => array( 299 'forum_id' => $source_forum_id, 300 'topic_id' => $source_topic_id, 301 ), 302 ) ); 303 304 wp_update_post( array( 305 'ID' => $reply_id, 306 'post_parent' => $destination_topic_id, 307 ) ); 308 bbp_update_reply_topic_id( $reply_id, $destination_topic_id ); 309 bbp_update_reply_forum_id( $reply_id, $destination_forum_id ); 310 wp_update_post( array( 311 'ID' => $source_topic_id, 312 'post_parent' => $destination_topic_id, 313 'post_type' => bbp_get_reply_post_type(), 314 ) ); 315 bbp_update_reply_topic_id( $source_topic_id, $destination_topic_id ); 316 bbp_update_reply_forum_id( $source_topic_id, $destination_forum_id ); 317 bbp_merge_topic_count( $destination_topic_id, $source_topic_id, $source_forum_id ); 318 319 $this->assertSame( 0, bbp_get_forum_topic_count( $source_forum_id, true, true ) ); 320 $this->assertSame( 0, bbp_get_forum_reply_count( $source_forum_id, true, true ) ); 321 $this->assertSame( 2, bbp_get_forum_reply_count( $destination_forum_id, true, true ) ); 322 $this->assertSame( 0, bbp_get_forum_topic_count( $source_parent_id, true, true ) ); 323 $this->assertSame( 0, bbp_get_forum_reply_count( $source_parent_id, true, true ) ); 324 $this->assertSame( 2, bbp_get_forum_reply_count( $destination_parent_id, true, true ) ); 325 $this->assertSame( 2, bbp_get_topic_reply_count( $destination_topic_id, true ) ); 326 $this->assertSame( 0, bbp_get_user_topic_count( $source_author_id, true ) ); 327 $this->assertSame( 1, bbp_get_user_reply_count( $source_author_id, true ) ); 328 $this->assertEqualSets( array( $source_author_id, $reply_author_id, $destination_author_id ), bbp_get_topic_engagements( $destination_topic_id ) ); 329 $this->assertSame( 3, bbp_get_topic_voice_count( $destination_topic_id, true ) ); 283 330 } 284 331 … … 296 343 /** 297 344 * @covers ::bbp_split_topic_count 298 * @todo Implement test_bbp_split_topic_count().299 345 */ 300 346 public function test_bbp_split_topic_count() { 301 // Remove the following lines when you implement this test. 302 $this->markTestIncomplete( 303 'This test has not been implemented yet.' 304 ); 347 $source_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 348 $destination_parent_id = $this->factory->forum->create( array( 'forum_meta' => array( 'forum_type' => 'category' ) ) ); 349 $source_forum_id = $this->factory->forum->create( array( 'post_parent' => $source_parent_id ) ); 350 $destination_forum_id = $this->factory->forum->create( array( 'post_parent' => $destination_parent_id ) ); 351 $source_topic_id = $this->factory->topic->create( array( 352 'post_parent' => $source_forum_id, 353 'topic_meta' => array( 'forum_id' => $source_forum_id ), 354 ) ); 355 $destination_topic_id = $this->factory->topic->create( array( 356 'post_parent' => $destination_forum_id, 357 'topic_meta' => array( 'forum_id' => $destination_forum_id ), 358 ) ); 359 $reply_id = $this->factory->reply->create( array( 360 'post_parent' => $source_topic_id, 361 'reply_meta' => array( 362 'forum_id' => $source_forum_id, 363 'topic_id' => $source_topic_id, 364 ), 365 ) ); 366 367 wp_update_post( array( 368 'ID' => $reply_id, 369 'post_parent' => $destination_topic_id, 370 ) ); 371 bbp_update_reply_topic_id( $reply_id, $destination_topic_id ); 372 bbp_update_reply_forum_id( $reply_id, $destination_forum_id ); 373 bbp_split_topic_count( $reply_id, $source_topic_id, $destination_topic_id ); 374 375 $this->assertSame( 0, bbp_get_forum_reply_count( $source_forum_id, true, true ) ); 376 $this->assertSame( 1, bbp_get_forum_reply_count( $destination_forum_id, true, true ) ); 377 $this->assertSame( 0, bbp_get_forum_reply_count( $source_parent_id, true, true ) ); 378 $this->assertSame( 1, bbp_get_forum_reply_count( $destination_parent_id, true, true ) ); 379 $this->assertSame( 0, bbp_get_topic_reply_count( $source_topic_id, true ) ); 380 $this->assertSame( 1, bbp_get_topic_reply_count( $destination_topic_id, true ) ); 381 } 382 383 /** 384 * @covers ::bbp_split_topic_count 385 * @ticket BBP3678 386 */ 387 public function test_bbp_split_topic_count_updates_converted_reply_counts_and_engagements() { 388 $source_author_id = $this->factory->user->create(); 389 $reply_author_id = $this->factory->user->create(); 390 $forum_id = $this->factory->forum->create(); 391 $source_topic_id = $this->factory->topic->create( array( 392 'post_author' => $source_author_id, 393 'post_parent' => $forum_id, 394 'topic_meta' => array( 'forum_id' => $forum_id ), 395 ) ); 396 $from_reply_id = $this->factory->reply->create( array( 397 'post_author' => $reply_author_id, 398 'post_parent' => $source_topic_id, 399 'reply_meta' => array( 400 'forum_id' => $forum_id, 401 'topic_id' => $source_topic_id, 402 ), 403 ) ); 404 405 wp_update_post( array( 406 'ID' => $from_reply_id, 407 'post_parent' => $forum_id, 408 'post_type' => bbp_get_topic_post_type(), 409 ) ); 410 bbp_update_topic_topic_id( $from_reply_id ); 411 bbp_update_topic_forum_id( $from_reply_id, $forum_id ); 412 413 bbp_split_topic_count( $from_reply_id, $source_topic_id, $from_reply_id ); 414 415 $this->assertSame( 2, bbp_get_forum_topic_count( $forum_id, true, true ) ); 416 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, true, true ) ); 417 $this->assertSame( 1, bbp_get_user_topic_count( $source_author_id, true ) ); 418 $this->assertSame( 1, bbp_get_user_topic_count( $reply_author_id, true ) ); 419 $this->assertSame( 0, bbp_get_user_reply_count( $reply_author_id, true ) ); 420 $this->assertSame( array( $source_author_id ), bbp_get_topic_engagements( $source_topic_id ) ); 421 $this->assertSame( array( $reply_author_id ), bbp_get_topic_engagements( $from_reply_id ) ); 422 $this->assertSame( 1, bbp_get_topic_voice_count( $source_topic_id, true ) ); 423 $this->assertSame( 1, bbp_get_topic_voice_count( $from_reply_id, true ) ); 305 424 } 306 425 -
trunk/tests/phpunit/testcases/users/functions/counts.php
r7449 r7467 247 247 $count = bbp_get_user_topic_count( $u, $integer ); 248 248 $this->assertSame( $int_value + 1, $count ); 249 } 250 251 /** 252 * @covers ::bbp_bump_user_topic_count 253 * @covers ::bbp_update_user_topic_count 254 * @ticket BBP3678 255 */ 256 public function test_bbp_bump_user_topic_count_preserves_an_interleaved_update() { 257 $user_id = $this->factory->user->create(); 258 $interleaved = false; 259 $callback = function( $count, $filtered_user_id ) use ( &$interleaved ) { 260 if ( ! $interleaved ) { 261 $interleaved = true; 262 bbp_bump_user_topic_count( $filtered_user_id ); 263 } 264 265 return $count; 266 }; 267 268 bbp_update_user_topic_count( $user_id, 0 ); 269 add_filter( 'bbp_get_user_topic_count_int', $callback, 10, 2 ); 270 bbp_bump_user_topic_count( $user_id ); 271 remove_filter( 'bbp_get_user_topic_count_int', $callback, 10 ); 272 273 $this->assertSame( 2, bbp_get_user_topic_count( $user_id, true ) ); 274 } 275 276 /** 277 * @covers ::bbp_bump_user_topic_count 278 * @covers ::bbp_update_user_topic_count 279 */ 280 public function test_bbp_bump_user_topic_count_preserves_count_filters() { 281 $user_id = $this->factory->user->create(); 282 $atomic_calls = 0; 283 $bump = function( $count ) { 284 return $count + 4; 285 }; 286 $update = function( $count ) { 287 return $count + 3; 288 }; 289 $atomic = function( $check ) use ( &$atomic_calls ) { 290 $atomic_calls++; 291 return $check; 292 }; 293 294 bbp_update_user_topic_count( $user_id, 5 ); 295 add_filter( 'bbp_bump_user_topic_count', $bump ); 296 add_filter( 'bbp_update_user_topic_count', $update ); 297 add_filter( 'bbp_pre_bump_count_meta', $atomic ); 298 bbp_bump_user_topic_count( $user_id ); 299 remove_filter( 'bbp_bump_user_topic_count', $bump, 10 ); 300 remove_filter( 'bbp_update_user_topic_count', $update, 10 ); 301 remove_filter( 'bbp_pre_bump_count_meta', $atomic, 10 ); 302 303 $this->assertSame( 13, bbp_get_user_topic_count( $user_id, true ) ); 304 $this->assertSame( 0, $atomic_calls ); 305 } 306 307 /** 308 * @covers ::bbp_bump_user_reply_count 309 * @covers ::bbp_update_user_reply_count 310 */ 311 public function test_bbp_bump_user_reply_count_preserves_an_absolute_update_filter() { 312 $user_id = $this->factory->user->create(); 313 $atomic_calls = 0; 314 $update = function() { 315 return 100; 316 }; 317 $atomic = function( $check ) use ( &$atomic_calls ) { 318 $atomic_calls++; 319 return $check; 320 }; 321 322 bbp_update_user_reply_count( $user_id, 5 ); 323 add_filter( 'bbp_update_user_reply_count', $update ); 324 add_filter( 'bbp_pre_bump_count_meta', $atomic ); 325 bbp_bump_user_reply_count( $user_id ); 326 remove_filter( 'bbp_update_user_reply_count', $update, 10 ); 327 remove_filter( 'bbp_pre_bump_count_meta', $atomic, 10 ); 328 329 $this->assertSame( 100, bbp_get_user_reply_count( $user_id, true ) ); 330 $this->assertSame( 0, $atomic_calls ); 331 } 332 333 /** 334 * @covers ::bbp_bump_user_topic_count 335 * @covers ::bbp_update_user_topic_count 336 * @ticket BBP3678 337 */ 338 public function test_bbp_bump_user_topic_count_uses_the_current_site_option() { 339 if ( ! is_multisite() ) { 340 $this->markTestSkipped( 'Requires multisite.' ); 341 } 342 343 $user_id = $this->factory->user->create(); 344 $site_id = $this->factory->blog->create(); 345 346 bbp_update_user_topic_count( $user_id, 5 ); 347 switch_to_blog( $site_id ); 348 349 try { 350 bbp_update_user_topic_count( $user_id, 7 ); 351 bbp_bump_user_topic_count( $user_id ); 352 $this->assertSame( 8, bbp_get_user_topic_count( $user_id, true ) ); 353 $this->assertSame( 8, (int) get_user_meta( $user_id, bbp_db()->get_blog_prefix() . '_bbp_topic_count', true ) ); 354 } finally { 355 restore_current_blog(); 356 } 357 358 $this->assertSame( 5, bbp_get_user_topic_count( $user_id, true ) ); 249 359 } 250 360 … … 402 512 403 513 /** 514 * @covers ::bbp_update_counts_on_user_reassignment 515 * @ticket BBP3678 516 */ 517 public function test_deleting_user_with_reassignment_updates_counts_and_engagements() { 518 $deleted_user_id = $this->factory->user->create(); 519 $reassign_user_id = $this->factory->user->create(); 520 $forum_id = $this->factory->forum->create(); 521 $topic_id = $this->factory->topic->create( array( 522 'post_author' => $deleted_user_id, 523 'post_parent' => $forum_id, 524 'topic_meta' => array( 'forum_id' => $forum_id ), 525 ) ); 526 $deleted_user_reply_id = $this->factory->reply->create( array( 527 'post_author' => $deleted_user_id, 528 'post_parent' => $topic_id, 529 'reply_meta' => array( 530 'forum_id' => $forum_id, 531 'topic_id' => $topic_id, 532 ), 533 ) ); 534 $this->factory->reply->create( array( 535 'post_author' => $reassign_user_id, 536 'post_parent' => $topic_id, 537 'reply_meta' => array( 538 'forum_id' => $forum_id, 539 'topic_id' => $topic_id, 540 ), 541 ) ); 542 $reply_only_topic_id = $this->factory->topic->create( array( 543 'post_author' => $reassign_user_id, 544 'post_parent' => $forum_id, 545 'topic_meta' => array( 'forum_id' => $forum_id ), 546 ) ); 547 $this->factory->reply->create( array( 548 'post_author' => $deleted_user_id, 549 'post_parent' => $reply_only_topic_id, 550 'reply_meta' => array( 551 'forum_id' => $forum_id, 552 'topic_id' => $reply_only_topic_id, 553 ), 554 ) ); 555 556 $this->assertSame( 1, bbp_get_user_topic_count( $deleted_user_id, true ) ); 557 $this->assertSame( 2, bbp_get_user_reply_count( $deleted_user_id, true ) ); 558 $this->assertSame( 1, bbp_get_user_topic_count( $reassign_user_id, true ) ); 559 $this->assertSame( 1, bbp_get_user_reply_count( $reassign_user_id, true ) ); 560 $this->assertSame( 2, bbp_get_topic_voice_count( $topic_id, true ) ); 561 $this->assertSame( 2, bbp_get_topic_voice_count( $reply_only_topic_id, true ) ); 562 563 wp_delete_user( $deleted_user_id, $reassign_user_id ); 564 565 $this->assertSame( $reassign_user_id, (int) get_post_field( 'post_author', $topic_id ) ); 566 $this->assertSame( $reassign_user_id, (int) get_post_field( 'post_author', $deleted_user_reply_id ) ); 567 $this->assertSame( 2, bbp_get_user_topic_count( $reassign_user_id, true ) ); 568 $this->assertSame( 3, bbp_get_user_reply_count( $reassign_user_id, true ) ); 569 $this->assertSame( array( $reassign_user_id ), bbp_get_topic_engagements( $topic_id ) ); 570 $this->assertSame( array( $reassign_user_id ), bbp_get_topic_engagements( $reply_only_topic_id ) ); 571 $this->assertSame( 1, bbp_get_topic_voice_count( $topic_id, true ) ); 572 $this->assertSame( 1, bbp_get_topic_voice_count( $reply_only_topic_id, true ) ); 573 } 574 575 /** 576 * @covers ::bbp_update_counts_on_user_reassignment 577 * @ticket BBP3678 578 */ 579 public function test_deleting_user_with_reassignment_updates_current_multisite_counts() { 580 if ( ! is_multisite() ) { 581 $this->markTestSkipped( 'Requires multisite.' ); 582 } 583 584 $deleted_user_id = $this->factory->user->create(); 585 $reassign_user_id = $this->factory->user->create(); 586 $site_id = $this->factory->blog->create(); 587 588 add_user_to_blog( $site_id, $deleted_user_id, 'subscriber' ); 589 add_user_to_blog( $site_id, $reassign_user_id, 'subscriber' ); 590 switch_to_blog( $site_id ); 591 592 try { 593 $forum_id = $this->factory->forum->create(); 594 $this->factory->topic->create( array( 595 'post_author' => $deleted_user_id, 596 'post_parent' => $forum_id, 597 'topic_meta' => array( 'forum_id' => $forum_id ), 598 ) ); 599 600 wp_delete_user( $deleted_user_id, $reassign_user_id ); 601 602 $meta_key = bbp_db()->get_blog_prefix() . '_bbp_topic_count'; 603 $this->assertSame( 1, bbp_get_user_topic_count( $reassign_user_id, true ) ); 604 $this->assertSame( 1, (int) get_user_meta( $reassign_user_id, $meta_key, true ) ); 605 } finally { 606 restore_current_blog(); 607 } 608 } 609 610 /** 611 * @covers ::bbp_make_spam_user 612 * @covers ::bbp_make_ham_user 613 * @covers ::bbp_update_counts_on_transition_post_status 614 * @ticket BBP3678 615 */ 616 public function test_bbp_make_spam_and_ham_user_updates_counts() { 617 $user_id = $this->factory->user->create(); 618 $forum_id = $this->factory->forum->create(); 619 $topic_id = $this->factory->topic->create( array( 620 'post_author' => $user_id, 621 'post_parent' => $forum_id, 622 'topic_meta' => array( 'forum_id' => $forum_id ), 623 ) ); 624 $this->factory->reply->create( array( 625 'post_author' => $user_id, 626 'post_parent' => $topic_id, 627 'reply_meta' => array( 628 'forum_id' => $forum_id, 629 'topic_id' => $topic_id, 630 ), 631 ) ); 632 633 $this->assertTrue( bbp_make_spam_user( $user_id ) ); 634 $this->assertSame( 0, bbp_get_user_topic_count( $user_id, true ) ); 635 $this->assertSame( 0, bbp_get_user_reply_count( $user_id, true ) ); 636 $this->assertSame( 0, bbp_get_forum_topic_count( $forum_id, false, true ) ); 637 $this->assertSame( 0, bbp_get_forum_reply_count( $forum_id, false, true ) ); 638 $this->assertSame( 1, bbp_get_forum_topic_count_hidden( $forum_id, false, true ) ); 639 $this->assertSame( 1, bbp_get_forum_reply_count_hidden( $forum_id, false, true ) ); 640 641 $this->assertTrue( bbp_make_ham_user( $user_id ) ); 642 $this->assertSame( 1, bbp_get_user_topic_count( $user_id, true ) ); 643 $this->assertSame( 1, bbp_get_user_reply_count( $user_id, true ) ); 644 $this->assertSame( 1, bbp_get_forum_topic_count( $forum_id, false, true ) ); 645 $this->assertSame( 1, bbp_get_forum_reply_count( $forum_id, false, true ) ); 646 $this->assertSame( 0, bbp_get_forum_topic_count_hidden( $forum_id, false, true ) ); 647 $this->assertSame( 0, bbp_get_forum_reply_count_hidden( $forum_id, false, true ) ); 648 } 649 650 /** 651 * @covers ::bbp_update_counts_on_post_author_change 652 */ 653 public function test_changing_post_authors_updates_user_counts() { 654 $old_user_id = $this->factory->user->create(); 655 $new_user_id = $this->factory->user->create(); 656 $forum_id = $this->factory->forum->create(); 657 $topic_id = $this->factory->topic->create( array( 658 'post_author' => $old_user_id, 659 'post_parent' => $forum_id, 660 'topic_meta' => array( 'forum_id' => $forum_id ), 661 ) ); 662 $reply_id = $this->factory->reply->create( array( 663 'post_author' => $old_user_id, 664 'post_parent' => $topic_id, 665 'reply_meta' => array( 666 'forum_id' => $forum_id, 667 'topic_id' => $topic_id, 668 ), 669 ) ); 670 671 wp_update_post( array( 'ID' => $topic_id, 'post_author' => $new_user_id ) ); 672 $this->assertSame( 2, bbp_get_topic_voice_count( $topic_id, true ) ); 673 674 wp_update_post( array( 'ID' => $reply_id, 'post_author' => $new_user_id ) ); 675 $this->assertSame( 1, bbp_get_topic_voice_count( $topic_id, true ) ); 676 677 $this->assertSame( 0, bbp_get_user_topic_count( $old_user_id, true ) ); 678 $this->assertSame( 0, bbp_get_user_reply_count( $old_user_id, true ) ); 679 $this->assertSame( 1, bbp_get_user_topic_count( $new_user_id, true ) ); 680 $this->assertSame( 1, bbp_get_user_reply_count( $new_user_id, true ) ); 681 } 682 683 /** 684 * @covers ::bbp_update_counts_on_post_author_change 685 */ 686 public function test_changing_post_author_and_status_rebuilds_user_counts() { 687 $old_user_id = $this->factory->user->create(); 688 $new_user_id = $this->factory->user->create(); 689 $forum_id = $this->factory->forum->create(); 690 $topic_id = $this->factory->topic->create( array( 691 'post_author' => $old_user_id, 692 'post_parent' => $forum_id, 693 'topic_meta' => array( 'forum_id' => $forum_id ), 694 ) ); 695 696 wp_update_post( array( 697 'ID' => $topic_id, 698 'post_author' => $new_user_id, 699 'post_status' => bbp_get_pending_status_id(), 700 ) ); 701 702 $this->assertSame( 0, bbp_get_user_topic_count( $old_user_id, true ) ); 703 $this->assertSame( 0, bbp_get_user_topic_count( $new_user_id, true ) ); 704 } 705 706 /** 404 707 * @covers ::bbp_increase_user_topic_count 405 708 */
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)