PluginProbe
bbPress / 2.6.15
bbPress v2.6.15
trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.2.2 All 71 releases
bbpress / includes / admin / tools / repair.php

repair.php in bbPress 2.6.15, at includes/admin/tools/repair.php

1,322 lines 46.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * bbPress Admin Repair Page
5 *
6 * @package bbPress
7 * @subpackage Administration
8 */
9
10 // Exit if accessed directly
11 defined( 'ABSPATH' ) || exit;
12
13 /**
14 * Admin repair page
15 *
16 * @since 2.0.0 bbPress (r2613) Converted from bbPress 1.2
17 * @since 2.6.0 bbPress (r5885) Upgraded to list-table UI
18 *
19 * @todo Use a real list table
20 *
21 */
22 function bbp_admin_repair_page() {
23
24 // Get the registered repair tools
25 $tools = bbp_admin_repair_list();
26
27 // Orderby
28 $orderby = ! empty( $_GET['orderby'] )
29 ? sanitize_key( $_GET['orderby'] )
30 : 'priority';
31
32 // Order
33 $order = ! empty( $_GET['order'] ) && in_array( strtolower( $_GET['order'] ), array( 'asc', 'desc' ), true )
34 ? strtolower( $_GET['order'] )
35 : 'asc';
36
37 // New order
38 $new_order = ( 'desc' === $order )
39 ? 'asc'
40 : 'desc'; ?>
41
42 <div class="wrap">
43 <h1 class="wp-heading-inline"><?php esc_html_e( 'Forum Tools', 'bbpress' ); ?></h1>
44 <hr class="wp-header-end">
45 <h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( 'bbp-repair' ); ?></h2>
46
47 <p><?php esc_html_e( 'bbPress keeps track of relationships between forums, topics, replies, topic-tags, favorites, subscriptions, and users. Occasionally these relationships become out of sync, most often after an import or migration. Use the tools below to manually recalculate these relationships.', 'bbpress' ); ?></p>
48 <p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Use caution when running more than 1 repair at a time.', 'bbpress' ); ?></p>
49
50 <?php bbp_admin_repair_tool_status_filters(); ?>
51
52 <form class="settings" method="get" action="">
53
54 <?php bbp_admin_repair_list_search_form(); ?>
55
56 <input type="hidden" name="page" value="bbp-repair" />
57 <?php wp_nonce_field( 'bbpress-do-counts' ); ?>
58
59 <div class="tablenav top">
60 <div class="alignleft actions bulkactions">
61 <label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
62 <select name="action" id="bulk-action-selector-top">
63 <option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
64 <option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
65 </select>
66 <input type="submit" id="doaction" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
67 </div>
68 <div class="alignleft actions">
69
70 <?php bbp_admin_repair_list_components_filter(); ?>
71
72 <input type="submit" name="filter_action" id="components-submit" class="button" value="<?php esc_html_e( 'Filter', 'bbpress' ); ?>">
73 </div>
74 <br class="clear">
75 </div>
76 <table class="wp-list-table widefat striped posts">
77 <thead>
78 <tr>
79 <td id="cb" class="manage-column column-cb check-column">
80 <label class="screen-reader-text" for="cb-select-all-1">
81 <?php esc_html_e( 'Select All', 'bbpress' ); ?>
82 </label>
83 <input id="cb-select-all-1" type="checkbox">
84 </td>
85 <th scope="col" id="description" class="manage-column column-primary column-description sortable <?php echo ( 'priority' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
86 <a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
87 'orderby' => 'priority',
88 'order' => $new_order
89 ) ) ); ?>"><span><?php esc_html_e( 'Description', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
90 </a>
91 </th>
92 <th scope="col" id="components" class="manage-column column-components">
93 <span><?php esc_html_e( 'Components', 'bbpress' ); ?></span>
94 </th>
95 <th scope="col" id="overhead" class="manage-column column-overhead sortable <?php echo ( 'overhead' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
96 <a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
97 'orderby' => 'overhead',
98 'order' => $new_order
99 ) ) ); ?>"><span><?php esc_html_e( 'Overhead', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
100 </a>
101 </th>
102 </tr>
103 </thead>
104
105 <tbody id="the-list">
106
107 <?php if ( ! empty( $tools ) ) : ?>
108
109 <?php foreach ( $tools as $item ) : ?>
110
111 <tr id="bbp-repair-tools" class="inactive">
112 <th scope="row" class="check-column">
113 <label class="screen-reader-text" for="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>"></label>
114 <input type="checkbox" name="checked[]" value="<?php echo esc_attr( $item['id'] ); ?>" id="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>">
115 </th>
116 <td class="bbp-tool-title column-primary column-description" data-colname="<?php esc_html_e( 'Description', 'bbpress' ); ?>">
117 <strong><?php echo esc_html( $item['title'] ); ?></strong><?php
118
119 // Optional description
120 if ( ! empty( $item['description'] ) ) :
121 echo '<p class="description">' . esc_html( $item['description'] ) . '</p>';
122 endif;
123
124 ?><div class="row-actions hide-if-no-js">
125 <span class="run">
126 <a href="<?php bbp_admin_repair_tool_run_url( $item ); ?>" aria-label="<?php printf( esc_html__( 'Run %s', 'bbpress' ), $item['title'] ); ?>" id="<?php echo esc_attr( $item['id'] ); ?>" ><?php esc_html_e( 'Run', 'bbpress' ); ?></a>
127 </span>
128 </div>
129 <button type="button" class="toggle-row">
130 <span class="screen-reader-text"><?php esc_html_e( 'Show more details', 'bbpress' ); ?></span>
131 </button>
132 </td>
133 <td class="column-components desc" data-colname="<?php esc_html_e( 'Components', 'bbpress' ); ?>">
134 <div class="bbp-tool-overhead">
135
136 <?php echo implode( ', ', bbp_get_admin_repair_tool_components( $item ) ); ?>
137
138 </div>
139 </td>
140 <td class="column-overhead desc" data-colname="<?php esc_html_e( 'Overhead', 'bbpress' ); ?>">
141 <div class="bbp-tool-overhead">
142
143 <?php echo implode( ', ', bbp_get_admin_repair_tool_overhead( $item ) ); ?>
144
145 </div>
146 </td>
147 </tr>
148
149 <?php endforeach; ?>
150
151 <?php else : ?>
152
153 <tr>
154 <td colspan="4">
155 <?php esc_html_e( 'No repair tools match this criteria.', 'bbpress' ); ?>
156 </td>
157 </tr>
158
159 <?php endif; ?>
160
161 </tbody>
162 <tfoot>
163 <tr>
164 <td class="manage-column column-cb check-column">
165 <label class="screen-reader-text" for="cb-select-all-2">
166 <?php esc_html_e( 'Select All', 'bbpress' ); ?>
167 </label>
168 <input id="cb-select-all-2" type="checkbox">
169 </td>
170 <th scope="col" class="manage-column column-primary column-description"><?php esc_html_e( 'Description', 'bbpress' ); ?></th>
171 <th scope="col" class="manage-column column-components"><?php esc_html_e( 'Components', 'bbpress' ); ?></th>
172 <th scope="col" class="manage-column column-overhead"><?php esc_html_e( 'Overhead', 'bbpress' ); ?></th>
173 </tr>
174 </tfoot>
175 </table>
176 <div class="tablenav bottom">
177 <div class="alignleft actions bulkactions">
178 <label for="bulk-action-selector-bottom" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
179 <select name="action2" id="bulk-action-selector-bottom">
180 <option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
181 <option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
182 </select>
183 <input type="submit" id="doaction2" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
184 </div>
185 </div>
186 </form>
187 </div>
188
189 <?php
190 }
191
192 /**
193 * Recount topic replies
194 *
195 * @since 2.0.0 bbPress (r2613)
196 *
197 * @return array An array of the status code and the message
198 */
199 function bbp_admin_repair_topic_reply_count() {
200
201 // Define variables
202 $bbp_db = bbp_db();
203 $statement = esc_html__( 'Counting the number of replies in each topic&hellip; %s', 'bbpress' );
204 $result = esc_html__( 'Failed!', 'bbpress' );
205
206 // Post types and status
207 $tpt = bbp_get_topic_post_type();
208 $rpt = bbp_get_reply_post_type();
209 $pps = bbp_get_public_status_id();
210 $cps = bbp_get_closed_status_id();
211
212 // Delete the meta key _bbp_reply_count for each topic
213 $sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
214 LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
215 WHERE `posts`.`post_type` = '{$tpt}'
216 AND `postmeta`.`meta_key` = '_bbp_reply_count'";
217
218 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
219 return array( 1, sprintf( $statement, $result ) );
220 }
221
222 // Recalculate the meta key _bbp_reply_count for each topic
223 $sql = "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`) (
224 SELECT `topics`.`ID` AS `post_id`, '_bbp_reply_count' AS `meta_key`, COUNT(`replies`.`ID`) As `meta_value`
225 FROM `{$bbp_db->posts}` AS `topics`
226 LEFT JOIN `{$bbp_db->posts}` as `replies`
227 ON `replies`.`post_parent` = `topics`.`ID`
228 AND `replies`.`post_status` = '{$pps}'
229 AND `replies`.`post_type` = '{$rpt}'
230 WHERE `topics`.`post_type` = '{$tpt}'
231 AND `topics`.`post_status` IN ( '{$pps}', '{$cps}' )
232 GROUP BY `topics`.`ID`)";
233
234 if ( is_wp_error( $bbp_db->query( $sql ) ) ) {
235 return array( 2, sprintf( $statement, $result ) );
236 }
237
238 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
239 }
240
241 /**
242 * Recount topic voices
243 *
244 * @since 2.0.0 bbPress (r2613)
245 *
246 * @return array An array of the status code and the message
247 */
248 function bbp_admin_repair_topic_voice_count() {
249
250 // Define variables
251 $bbp_db = bbp_db();
252 $statement = esc_html__( 'Counting the number of voices in each topic&hellip; %s', 'bbpress' );
253 $result = esc_html__( 'Failed!', 'bbpress' );
254
255 $sql_delete = "DELETE FROM {$bbp_db->postmeta} WHERE meta_key IN ('_bbp_voice_count', '_bbp_engagement')";
256 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
257 return array( 1, sprintf( $statement, $result ) );
258 }
259
260 // Post types and status
261 $tpt = bbp_get_topic_post_type();
262 $rpt = bbp_get_reply_post_type();
263 $pps = bbp_get_public_status_id();
264 $cps = bbp_get_closed_status_id();
265
266 $engagements_sql = $bbp_db->prepare( "INSERT INTO {$bbp_db->postmeta} (post_id, meta_key, meta_value) (
267 SELECT postmeta.meta_value, '_bbp_engagement', posts.post_author
268 FROM {$bbp_db->posts} AS posts
269 LEFT JOIN {$bbp_db->postmeta} AS postmeta
270 ON posts.ID = postmeta.post_id
271 AND postmeta.meta_key = '_bbp_topic_id'
272 WHERE posts.post_type IN (%s, %s)
273 AND posts.post_status IN (%s, %s)
274 GROUP BY postmeta.meta_value, posts.post_author)", $tpt, $rpt, $pps, $cps );
275
276 if ( is_wp_error( $bbp_db->query( $engagements_sql ) ) ) {
277 return array( 2, sprintf( $statement, $result ) );
278 }
279
280 $voice_count_sql = "INSERT INTO {$bbp_db->postmeta} (post_id, meta_key, meta_value) (
281 SELECT post_id, '_bbp_voice_count', COUNT(DISTINCT meta_value)
282 FROM {$bbp_db->postmeta}
283 WHERE meta_key = '_bbp_engagement'
284 GROUP BY post_id)";
285
286 if ( is_wp_error( $bbp_db->query( $voice_count_sql ) ) ) {
287 return array( 3, sprintf( $statement, $result ) );
288 }
289
290 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
291 }
292
293 /**
294 * Recount non-public replies per topic (pending/spammed/trashed)
295 *
296 * @since 2.0.0 bbPress (r2747)
297 *
298 * @return array An array of the status code and the message
299 */
300 function bbp_admin_repair_topic_hidden_reply_count() {
301
302 // Define variables
303 $bbp_db = bbp_db();
304 $statement = esc_html__( 'Counting the number of pending, spammed, and trashed replies in each topic&hellip; %s', 'bbpress' );
305 $result = esc_html__( 'Failed!', 'bbpress' );
306
307 $sql_delete = "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_reply_count_hidden'";
308 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
309 return array( 1, sprintf( $statement, $result ) );
310 }
311
312 // Post types and status
313 $rpt = bbp_get_reply_post_type();
314 $sta = bbp_get_non_public_topic_statuses();
315
316 // SQL
317 $sql_status = "'" . implode( "','", $sta ) . "'";
318
319 $sql = "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`) (SELECT `post_parent`, '_bbp_reply_count_hidden', COUNT(`post_status`) as `meta_value` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$rpt}' AND `post_status` IN ({$sql_status}) GROUP BY `post_parent`)";
320 if ( is_wp_error( $bbp_db->query( $sql ) ) ) {
321 return array( 2, sprintf( $statement, $result ) );
322 }
323
324 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
325 }
326
327 /**
328 * Recount forum topics
329 *
330 * @since 2.0.0 bbPress (r2613)
331 *
332 * @return array An array of the status code and the message
333 */
334 function bbp_admin_repair_forum_topic_count() {
335
336 // Define variables
337 $bbp_db = bbp_db();
338 $statement = esc_html__( 'Counting the number of topics in each forum&hellip; %s', 'bbpress' );
339 $result = esc_html__( 'Failed!', 'bbpress' );
340
341 $sql_delete = "DELETE FROM {$bbp_db->postmeta} WHERE meta_key IN ( '_bbp_topic_count', '_bbp_total_topic_count', '_bbp_topic_count_hidden' )";
342 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
343 return array( 1, sprintf( $statement, $result ) );
344 }
345
346 $forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
347 if ( ! empty( $forums ) ) {
348 foreach ( $forums as $forum ) {
349 bbp_update_forum_topic_count( $forum->ID );
350 bbp_update_forum_topic_count_hidden( $forum->ID );
351 }
352 } else {
353 return array( 2, sprintf( $statement, $result ) );
354 }
355
356 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
357 }
358
359 /**
360 * Recount topic in each topic-tag
361 *
362 * @since 2.6.0 bbPress (r6256)
363 *
364 * @return array An array of the status code and the message
365 */
366 function bbp_admin_repair_topic_tag_count() {
367
368 // Define variables
369 $statement = esc_html__( 'Counting the number of topics in each topic-tag&hellip; %s', 'bbpress' );
370 $result = esc_html__( 'Failed!', 'bbpress' );
371 $tax_id = bbp_get_topic_tag_tax_id();
372 $terms = get_terms( $tax_id, array( 'hide_empty' => false ) );
373 $tt_ids = wp_list_pluck( $terms, 'term_taxonomy_id' );
374 $ints = array_map( 'intval', $tt_ids );
375 $taxonomy = get_taxonomy( $tax_id );
376
377 // Bail if taxonomy does not exist
378 if ( empty( $taxonomy ) ) {
379 return array( 1, sprintf( $statement, $result ) );
380 }
381
382 // Custom callback
383 if ( ! empty( $taxonomy->update_count_callback ) ) {
384
385 // Bail if callback is not callable
386 if ( ! is_callable( $taxonomy->update_count_callback ) ) {
387 return array( 1, sprintf( $statement, $result ) );
388 }
389
390 call_user_func( $taxonomy->update_count_callback, $ints, $taxonomy );
391
392 // Generic callback fallback
393 } else {
394 _update_post_term_count( $ints, $taxonomy );
395 }
396
397 // Bust the cache
398 clean_term_cache( $ints, '', false );
399
400 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
401 }
402
403 /**
404 * Recount forum replies
405 *
406 * @since 2.0.0 bbPress (r2613)
407 *
408 * @return array An array of the status code and the message
409 */
410 function bbp_admin_repair_forum_reply_count() {
411
412 // Define variables
413 $bbp_db = bbp_db();
414 $statement = esc_html__( 'Counting the number of replies in each forum&hellip; %s', 'bbpress' );
415 $result = esc_html__( 'Failed!', 'bbpress' );
416
417 // Post type
418 $fpt = bbp_get_forum_post_type();
419
420 // Delete the meta keys _bbp_reply_count and _bbp_total_reply_count for each forum
421 $sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
422 LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
423 WHERE `posts`.`post_type` = '{$fpt}'
424 AND `postmeta`.`meta_key` = '_bbp_reply_count'
425 OR `postmeta`.`meta_key` = '_bbp_total_reply_count'";
426
427 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
428 return array( 1, sprintf( $statement, $result ) );
429 }
430
431 // Recalculate the metas key _bbp_reply_count and _bbp_total_reply_count for each forum
432 $forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
433 if ( ! empty( $forums ) ) {
434 foreach ( $forums as $forum ) {
435 bbp_update_forum_reply_count( $forum->ID );
436 }
437 } else {
438 return array( 2, sprintf( $statement, $result ) );
439 }
440
441 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
442 }
443
444 /**
445 * Recount non-public forum replies
446 *
447 * @since 2.6.0 bbPress (r6922)
448 * @since 2.6.0 bbPress (r6932) Rename to match the topic reply recount function
449 *
450 * @return array An array of the status code and the message
451 */
452 function bbp_admin_repair_forum_hidden_reply_count() {
453
454 // Define variables
455 $bbp_db = bbp_db();
456 $statement = esc_html__( 'Counting the number of pending, spammed, and trashed replies in each forum&hellip; %s', 'bbpress' );
457 $result = esc_html__( 'Failed!', 'bbpress' );
458
459 // Post type
460 $fpt = bbp_get_forum_post_type();
461
462 // Delete the meta keys _bbp_reply_count and _bbp_total_reply_count for each forum
463 $sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
464 LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
465 WHERE `posts`.`post_type` = '{$fpt}'
466 AND `postmeta`.`meta_key` = '_bbp_reply_count_hidden'
467 OR `postmeta`.`meta_key` = '_bbp_total_reply_count_hidden'";
468
469 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
470 return array( 1, sprintf( $statement, $result ) );
471 }
472
473 // Recalculate the metas key _bbp_reply_count and _bbp_total_reply_count for each forum
474 $forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
475 if ( ! empty( $forums ) ) {
476 foreach ( $forums as $forum ) {
477 bbp_update_forum_reply_count_hidden( $forum->ID );
478 }
479 } else {
480 return array( 2, sprintf( $statement, $result ) );
481 }
482
483 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
484 }
485
486 /**
487 * Recount topics by the users
488 *
489 * @since 2.1.0 bbPress (r3889)
490 *
491 * @return array An array of the status code and the message
492 */
493 function bbp_admin_repair_user_topic_count() {
494
495 // Define variables
496 $bbp_db = bbp_db();
497 $statement = esc_html__( 'Counting the number of topics each user has created&hellip; %s', 'bbpress' );
498 $result = esc_html__( 'Failed!', 'bbpress' );
499
500 $sql_type = bbp_get_topic_post_type();
501 $sql_status = "'" . implode( "','", bbp_get_public_topic_statuses() ) . "'";
502 $sql_select = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$sql_type}' AND `post_status` IN ({$sql_status}) GROUP BY `post_author`";
503 $insert_rows = $bbp_db->get_results( $sql_select );
504
505 if ( is_wp_error( $insert_rows ) ) {
506 return array( 1, sprintf( $statement, $result ) );
507 }
508
509 $key = $bbp_db->prefix . '_bbp_topic_count';
510 $insert_values = array();
511 foreach ( $insert_rows as $insert_row ) {
512 $insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
513 }
514
515 if ( !count( $insert_values ) ) {
516 return array( 2, sprintf( $statement, $result ) );
517 }
518
519 $sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
520 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
521 return array( 3, sprintf( $statement, $result ) );
522 }
523
524 foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
525 $chunk = "\n" . implode( ",\n", $chunk );
526 $sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
527
528 if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
529 return array( 4, sprintf( $statement, $result ) );
530 }
531 }
532
533 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
534 }
535
536 /**
537 * Recount topic replied by the users
538 *
539 * @since 2.0.0 bbPress (r2613)
540 *
541 * @return array An array of the status code and the message
542 */
543 function bbp_admin_repair_user_reply_count() {
544
545 // Define variables
546 $bbp_db = bbp_db();
547 $statement = esc_html__( 'Counting the number of topics to which each user has replied&hellip; %s', 'bbpress' );
548 $result = esc_html__( 'Failed!', 'bbpress' );
549
550 $sql_type = bbp_get_reply_post_type();
551 $sql_status = "'" . implode( "','", bbp_get_public_reply_statuses() ) . "'";
552 $sql_select = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$sql_type}' AND `post_status` IN ({$sql_status}) GROUP BY `post_author`";
553 $insert_rows = $bbp_db->get_results( $sql_select );
554
555 if ( is_wp_error( $insert_rows ) ) {
556 return array( 1, sprintf( $statement, $result ) );
557 }
558
559 $key = $bbp_db->prefix . '_bbp_reply_count';
560 $insert_values = array();
561 foreach ( $insert_rows as $insert_row ) {
562 $insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
563 }
564
565 if ( !count( $insert_values ) ) {
566 return array( 2, sprintf( $statement, $result ) );
567 }
568
569 $sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
570 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
571 return array( 3, sprintf( $statement, $result ) );
572 }
573
574 foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
575 $chunk = "\n" . implode( ",\n", $chunk );
576 $sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
577
578 if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
579 return array( 4, sprintf( $statement, $result ) );
580 }
581 }
582
583 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
584 }
585
586 /**
587 * Repair user favorites
588 *
589 * @since 2.0.0 bbPress (r2613)
590 *
591 * @return array An array of the status code and the message
592 */
593 function bbp_admin_repair_user_favorites() {
594
595 // Define variables
596 $bbp_db = bbp_db();
597 $statement = esc_html__( 'Removing unpublished topics from user favorites&hellip; %s', 'bbpress' );
598 $result = esc_html__( 'Failed!', 'bbpress' );
599
600 // Query for users with favorites
601 $key = $bbp_db->prefix . '_bbp_favorites';
602 $users = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `favorites` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );
603
604 if ( is_wp_error( $users ) ) {
605 return array( 1, sprintf( $statement, $result ) );
606 }
607
608 $sql_type = bbp_get_topic_post_type();
609 $sql_status = "'" . implode( "','", bbp_get_public_topic_statuses() ) . "'";
610 $sql_select = "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$sql_type}' AND `post_status` IN ({$sql_status})";
611
612 $topics = $bbp_db->get_col( $sql_select );
613 if ( is_wp_error( $topics ) ) {
614 return array( 2, sprintf( $statement, $result ) );
615 }
616
617 $values = array();
618 foreach ( $users as $user ) {
619 if ( empty( $user->favorites ) || ! is_string( $user->favorites ) ) {
620 continue;
621 }
622
623 $favorites = array_intersect( $topics, explode( ',', $user->favorites ) );
624 if ( empty( $favorites ) || ! is_array( $favorites ) ) {
625 continue;
626 }
627
628 $favorites_joined = implode( ',', $favorites );
629 $values[] = "('{$user->user_id}', '{$key}', '{$favorites_joined}')";
630
631 // Cleanup
632 unset( $favorites, $favorites_joined );
633 }
634
635 if ( !count( $values ) ) {
636 $result = esc_html__( 'Nothing to remove!', 'bbpress' );
637 return array( 0, sprintf( $statement, $result ) );
638 }
639
640 $sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
641 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
642 return array( 4, sprintf( $statement, $result ) );
643 }
644
645 foreach ( array_chunk( $values, 10000 ) as $chunk ) {
646 $chunk = "\n" . implode( ",\n", $chunk );
647 $sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
648 if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
649 return array( 5, sprintf( $statement, $result ) );
650 }
651 }
652
653 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
654 }
655
656 /**
657 * Clean the user topic subscriptions
658 *
659 * @since 2.0.0 bbPress (r2668)
660 *
661 * @return array An array of the status code and the message
662 */
663 function bbp_admin_repair_user_topic_subscriptions() {
664
665 // Define variables
666 $bbp_db = bbp_db();
667 $statement = esc_html__( 'Removing trashed topics from user subscriptions&hellip; %s', 'bbpress' );
668 $result = esc_html__( 'Failed!', 'bbpress' );
669
670 $key = $bbp_db->prefix . '_bbp_subscriptions';
671 $users = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );
672
673 if ( is_wp_error( $users ) ) {
674 return array( 1, sprintf( $statement, $result ) );
675 }
676
677 $sql_type = bbp_get_topic_post_type();
678 $sql_status = "'" . implode( "','", bbp_get_public_topic_statuses() ) . "'";
679 $sql_select = "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$sql_type}' AND `post_status` IN ({$sql_status})";
680
681 $topics = $bbp_db->get_col( $sql_select );
682 if ( is_wp_error( $topics ) ) {
683 return array( 2, sprintf( $statement, $result ) );
684 }
685
686 $values = array();
687 foreach ( $users as $user ) {
688 if ( empty( $user->subscriptions ) || ! is_string( $user->subscriptions ) ) {
689 continue;
690 }
691
692 $subscriptions = array_intersect( $topics, explode( ',', $user->subscriptions ) );
693 if ( empty( $subscriptions ) || ! is_array( $subscriptions ) ) {
694 continue;
695 }
696
697 $subscriptions_joined = implode( ',', $subscriptions );
698 $values[] = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";
699
700 // Cleanup
701 unset( $subscriptions, $subscriptions_joined );
702 }
703
704 if ( !count( $values ) ) {
705 $result = esc_html__( 'Nothing to remove!', 'bbpress' );
706 return array( 0, sprintf( $statement, $result ) );
707 }
708
709 $sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
710 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
711 return array( 4, sprintf( $statement, $result ) );
712 }
713
714 foreach ( array_chunk( $values, 10000 ) as $chunk ) {
715 $chunk = "\n" . implode( ",\n", $chunk );
716 $sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
717 if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
718 return array( 5, sprintf( $statement, $result ) );
719 }
720 }
721
722 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
723 }
724
725 /**
726 * Clean the user forum subscriptions
727 *
728 * @since 2.5.0 bbPress (r5155)
729 *
730 * @return array An array of the status code and the message
731 */
732 function bbp_admin_repair_user_forum_subscriptions() {
733
734 // Define variables
735 $bbp_db = bbp_db();
736 $statement = esc_html__( 'Removing trashed forums from user subscriptions&hellip; %s', 'bbpress' );
737 $result = esc_html__( 'Failed!', 'bbpress' );
738
739 $key = $bbp_db->prefix . '_bbp_forum_subscriptions';
740 $users = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );
741
742 if ( is_wp_error( $users ) ) {
743 return array( 1, sprintf( $statement, $result ) );
744 }
745
746 $sql_type = bbp_get_forum_post_type();
747 $sql_status = "'" . implode( "','", bbp_get_public_forum_statuses() ) . "'";
748 $sql_select = "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$sql_type}' AND `post_status` IN ({$sql_status})";
749
750 $forums = $bbp_db->get_col( $sql_select );
751 if ( is_wp_error( $forums ) ) {
752 return array( 2, sprintf( $statement, $result ) );
753 }
754
755 $values = array();
756 foreach ( $users as $user ) {
757 if ( empty( $user->subscriptions ) || ! is_string( $user->subscriptions ) ) {
758 continue;
759 }
760
761 $subscriptions = array_intersect( $forums, explode( ',', $user->subscriptions ) );
762 if ( empty( $subscriptions ) || ! is_array( $subscriptions ) ) {
763 continue;
764 }
765
766 $subscriptions_joined = implode( ',', $subscriptions );
767 $values[] = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";
768
769 // Cleanup
770 unset( $subscriptions, $subscriptions_joined );
771 }
772
773 if ( !count( $values ) ) {
774 $result = esc_html__( 'Nothing to remove!', 'bbpress' );
775 return array( 0, sprintf( $statement, $result ) );
776 }
777
778 $sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
779 if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
780 return array( 4, sprintf( $statement, $result ) );
781 }
782
783 foreach ( array_chunk( $values, 10000 ) as $chunk ) {
784 $chunk = "\n" . implode( ",\n", $chunk );
785 $sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
786 if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
787 return array( 5, sprintf( $statement, $result ) );
788 }
789 }
790
791 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
792 }
793
794 /**
795 * This repair tool will map each user of the current site to their respective
796 * forums role. By default, Admins will be Key Masters, and every other role
797 * will be the default role defined in Settings > Forums (Participant).
798 *
799 * @since 2.2.0 bbPress (r4340)
800 */
801 function bbp_admin_repair_user_roles() {
802
803 $statement = esc_html__( 'Remapping forum role for each user on this site&hellip; %s', 'bbpress' );
804 $changed = 0;
805 $role_map = bbp_get_user_role_map();
806 $default_role = bbp_get_default_role();
807
808 // Bail if no role map exists
809 if ( empty( $role_map ) ) {
810 return array( 1, sprintf( $statement, esc_html__( 'Failed!', 'bbpress' ) ) );
811 }
812
813 // Get non-forum roles
814 $blog_roles = array_keys( bbp_get_blog_roles() );
815
816 // Iterate through each role...
817 foreach ( $blog_roles as $role ) {
818
819 // Reset the offset
820 $offset = 0;
821
822 // If no role map exists, give the default forum role (bbp-participant)
823 $new_role = isset( $role_map[ $role ] )
824 ? $role_map[ $role ]
825 : $default_role;
826
827 // Get users of this site, limited to 1000
828 while ( $users = get_users( array(
829 'role' => $role,
830 'fields' => 'ID',
831 'number' => 1000,
832 'offset' => $offset
833 ) ) ) {
834
835 // Iterate through each user of $role and try to set it
836 foreach ( (array) $users as $user_id ) {
837 if ( bbp_set_user_role( $user_id, $new_role ) ) {
838 ++$changed; // Keep a count to display at the end
839 }
840 }
841
842 // Bump the offset for the next query iteration
843 $offset = $offset + 1000;
844 }
845 }
846
847 // Reset the offset
848 $offset = 0;
849 $bbp_db = bbp_db();
850 $cap_key = $bbp_db->get_blog_prefix() . 'capabilities';
851
852 // Users without roles should be granted the default role, but not on multi-
853 // site installations where not all users get a role by default.
854 if ( ! is_multisite() ) {
855
856 // Get users with missing capabilities on this site, limited to 1000
857 while ( $users = get_users( array(
858 'meta_key' => $cap_key,
859 'meta_compare' => 'NOT EXISTS',
860 'fields' => 'ID',
861 'number' => 1000,
862 'offset' => $offset
863 ) ) ) {
864
865 // Iterate through each user of $role and try to set it
866 foreach ( (array) $users as $user_id ) {
867 if ( bbp_set_user_role( $user_id, $default_role ) ) {
868 ++$changed; // Keep a count to display at the end
869 }
870 }
871
872 // Bump the offset for the next query iteration
873 $offset = $offset + 1000;
874 }
875
876 // On multisite, we'll look for users with an empty capabilities array.
877 // These are users who basically have malformed caps, and we can fix that.
878 } else {
879
880 // Get users with empty capabilities on this site, limited to 1000
881 while ( $users = get_users( array(
882 'meta_key' => $cap_key,
883 'meta_value' => 'a:0:{}',
884 'fields' => 'ID',
885 'number' => 1000,
886 'offset' => $offset
887 ) ) ) {
888
889 // Iterate through each user of $role and try to set it
890 foreach ( (array) $users as $user_id ) {
891 if ( bbp_set_user_role( $user_id, $default_role ) ) {
892 ++$changed; // Keep a count to display at the end
893 }
894 }
895
896 // Bump the offset for the next query iteration
897 $offset = $offset + 1000;
898 }
899 }
900
901 $result = sprintf( esc_html__( 'Complete! %s users updated.', 'bbpress' ), bbp_number_format( $changed ) );
902
903 return array( 0, sprintf( $statement, $result ) );
904 }
905
906 /**
907 * Repair the last post in every topic and forum
908 *
909 * @since 2.0.0 bbPress (r3040)
910 *
911 * @return array An array of the status code and the message
912 */
913 function bbp_admin_repair_freshness() {
914
915 // Define variables
916 $bbp_db = bbp_db();
917 $statement = esc_html__( 'Recomputing latest post in every topic and forum&hellip; %s', 'bbpress' );
918 $result = esc_html__( 'Failed!', 'bbpress' );
919
920 // First, delete everything.
921 if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` IN ( '_bbp_last_reply_id', '_bbp_last_topic_id', '_bbp_last_active_id', '_bbp_last_active_time' )" ) ) ) {
922 return array( 1, sprintf( $statement, $result ) );
923 }
924
925 // Post types and status
926 $fpt = bbp_get_forum_post_type();
927 $tpt = bbp_get_topic_post_type();
928 $rpt = bbp_get_reply_post_type();
929 $pps = bbp_get_public_status_id();
930
931 // Next, give all the topics with replies the ID their last reply.
932 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
933 ( SELECT `topic`.`ID`, '_bbp_last_reply_id', MAX( `reply`.`ID` )
934 FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
935 WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
936 GROUP BY `topic`.`ID` )" ) ) ) {
937 return array( 2, sprintf( $statement, $result ) );
938 }
939
940 // For any remaining topics, give a reply ID of 0.
941 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
942 ( SELECT `ID`, '_bbp_last_reply_id', 0
943 FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
944 ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_reply_id'
945 WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
946 return array( 3, sprintf( $statement, $result ) );
947 }
948
949 // Now we give all the forums with topics the ID their last topic.
950 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
951 ( SELECT `forum`.`ID`, '_bbp_last_topic_id', MAX( `topic`.`ID` )
952 FROM `{$bbp_db->posts}` AS `forum` INNER JOIN `{$bbp_db->posts}` AS `topic` ON `forum`.`ID` = `topic`.`post_parent`
953 WHERE `topic`.`post_status` = '{$pps}' AND `forum`.`post_type` = '{$fpt}' AND `topic`.`post_type` = '{$tpt}'
954 GROUP BY `forum`.`ID` )" ) ) ) {
955 return array( 4, sprintf( $statement, $result ) );
956 }
957
958 // For any remaining forums, give a topic ID of 0.
959 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
960 ( SELECT `ID`, '_bbp_last_topic_id', 0
961 FROM `{$bbp_db->posts}` AS `forum` LEFT JOIN `{$bbp_db->postmeta}` AS `topic`
962 ON `forum`.`ID` = `topic`.`post_id` AND `topic`.`meta_key` = '_bbp_last_topic_id'
963 WHERE `topic`.`meta_id` IS NULL AND `forum`.`post_type` = '{$fpt}' )" ) ) ) {
964 return array( 5, sprintf( $statement, $result ) );
965 }
966
967 // After that, we give all the topics with replies the ID their last reply (again, this time for a different reason).
968 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
969 ( SELECT `topic`.`ID`, '_bbp_last_active_id', MAX( `reply`.`ID` )
970 FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
971 WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
972 GROUP BY `topic`.`ID` )" ) ) ) {
973 return array( 6, sprintf( $statement, $result ) );
974 }
975
976 // For any remaining topics, give a reply ID of themself.
977 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
978 ( SELECT `ID`, '_bbp_last_active_id', `ID`
979 FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
980 ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_id'
981 WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
982 return array( 7, sprintf( $statement, $result ) );
983 }
984
985 // Give topics with replies their last update time.
986 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
987 ( SELECT `topic`.`ID`, '_bbp_last_active_time', MAX( `reply`.`post_date` )
988 FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
989 WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
990 GROUP BY `topic`.`ID` )" ) ) ) {
991 return array( 8, sprintf( $statement, $result ) );
992 }
993
994 // Give topics without replies their last update time.
995 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
996 ( SELECT `ID`, '_bbp_last_active_time', `post_date`
997 FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
998 ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_time'
999 WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
1000 return array( 9, sprintf( $statement, $result ) );
1001 }
1002
1003 // Forums need to know what their last active item is as well. Now it gets a bit more complex to do in the database.
1004 $forums = $bbp_db->get_col( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$fpt}' and `post_status` != 'auto-draft'" );
1005 if ( is_wp_error( $forums ) ) {
1006 return array( 10, sprintf( $statement, $result ) );
1007 }
1008
1009 // Loop through forums
1010 foreach ( $forums as $forum_id ) {
1011 if ( ! bbp_is_forum_category( $forum_id ) ) {
1012 bbp_update_forum( array( 'forum_id' => $forum_id ) );
1013 }
1014 }
1015
1016 // Loop through categories when forums are done
1017 foreach ( $forums as $forum_id ) {
1018 if ( bbp_is_forum_category( $forum_id ) ) {
1019 bbp_update_forum( array( 'forum_id' => $forum_id ) );
1020 }
1021 }
1022
1023 // Complete results
1024 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1025 }
1026
1027 /**
1028 * Repair the relationship of sticky topics to the actual parent forum
1029 *
1030 * @since 2.3.0 bbPress (r4695)
1031 *
1032 * @return array An array of the status code and the message
1033 */
1034 function bbp_admin_repair_sticky() {
1035
1036 // Define variables
1037 $bbp_db = bbp_db();
1038 $statement = esc_html__( 'Repairing the sticky topic to the parent forum relationships&hellip; %s', 'bbpress' );
1039 $result = esc_html__( 'Failed!', 'bbpress' );
1040
1041 $forums = $bbp_db->get_col( "SELECT ID FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_forum_post_type() . "'" );
1042
1043 // Bail if no forums found
1044 if ( empty( $forums ) || is_wp_error( $forums ) ) {
1045 return array( 1, sprintf( $statement, $result ) );
1046 }
1047
1048 // Loop through forums and get their sticky topics
1049 foreach ( $forums as $forum ) {
1050 $forum_stickies[ $forum ] = get_post_meta( $forum, '_bbp_sticky_topics', true );
1051 }
1052
1053 // Cleanup
1054 unset( $forums, $forum );
1055
1056 // Loop through each forum with sticky topics
1057 foreach ( $forum_stickies as $forum_id => $stickies ) {
1058
1059 // Skip if no stickies
1060 if ( empty( $stickies ) ) {
1061 continue;
1062 }
1063
1064 // Loop through each sticky topic
1065 foreach ( $stickies as $id => $topic_id ) {
1066
1067 // If the topic is not a super sticky, and the forum ID does not
1068 // match the topic's forum ID, unset the forum's sticky meta.
1069 if ( ! bbp_is_topic_super_sticky( $topic_id ) && ( $forum_id !== bbp_get_topic_forum_id( $topic_id ) ) ) {
1070 unset( $forum_stickies[ $forum_id ][ $id ] );
1071 }
1072 }
1073
1074 // Get sticky topic ID's, or use empty string
1075 $stickers = ! empty( $forum_stickies[ $forum_id ] )
1076 ? array_values( $forum_stickies[ $forum_id ] )
1077 : '';
1078
1079 // Update the forum's sticky topics meta
1080 update_post_meta( $forum_id, '_bbp_sticky_topics', $stickers );
1081 }
1082
1083 // Complete results
1084 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1085 }
1086
1087 /**
1088 * Repair closed topics
1089 *
1090 * Closed topics that are missing the post-meta "_bbp_status" key value "publish"
1091 * result in unexpected behavior, primarily this would have only occurred if you
1092 * had imported forums from another forum package previous to bbPress v2.6,
1093 * https://bbpress.trac.wordpress.org/ticket/2577
1094 *
1095 * @since 2.6.0 bbPress (r5668)
1096 *
1097 * @return array An array of the status code and the message
1098 */
1099 function bbp_admin_repair_closed_topics() {
1100
1101 // Define variables
1102 $bbp_db = bbp_db();
1103 $statement = esc_html__( 'Repairing closed topics&hellip; %s', 'bbpress' );
1104 $result = esc_html__( 'No closed topics to repair.', 'bbpress' );
1105 $changed = 0;
1106
1107 // Results
1108 $query = "SELECT ID FROM `{$bbp_db->posts}` WHERE `post_type` = %s AND `post_status` = %s";
1109 $prepare = $bbp_db->prepare( $query, bbp_get_topic_post_type(), bbp_get_closed_status_id() );
1110 $closed_topics = $bbp_db->get_col( $prepare );
1111
1112 // Bail if no closed topics found
1113 if ( empty( $closed_topics ) || is_wp_error( $closed_topics ) ) {
1114 return array( 1, sprintf( $statement, $result ) );
1115 }
1116
1117 // Loop through each closed topic
1118 foreach ( $closed_topics as $closed_topic ) {
1119
1120 // Check if the closed topic already has a postmeta _bbp_status value
1121 $topic_status = get_post_meta( $closed_topic, '_bbp_status', true );
1122
1123 // If we don't have a postmeta _bbp_status value
1124 if ( empty( $topic_status ) ) {
1125 update_post_meta( $closed_topic, '_bbp_status', 'publish' );
1126 ++$changed; // Keep a count to display at the end
1127 }
1128 }
1129
1130 // Cleanup
1131 unset( $closed_topics, $closed_topic, $topic_status );
1132
1133 // Complete results
1134 $result = sprintf( _n( 'Complete! %d closed topic repaired.', 'Complete! %d closed topics repaired.', $changed, 'bbpress' ), $changed );
1135
1136 return array( 0, sprintf( $statement, $result ) );
1137 }
1138
1139 /**
1140 * Repair the private and hidden forums
1141 *
1142 * @since 2.2.0 bbPress (r4104)
1143 *
1144 * @return array An array of the status code and the message
1145 */
1146 function bbp_admin_repair_forum_visibility() {
1147 $statement = esc_html__( 'Recalculating forum visibility&hellip; %s', 'bbpress' );
1148
1149 // Bail if queries returned errors
1150 if ( ! bbp_repair_forum_visibility() ) {
1151 return array( 2, sprintf( $statement, esc_html__( 'Failed!', 'bbpress' ) ) );
1152
1153 // Complete results
1154 } else {
1155 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1156 }
1157 }
1158
1159 /**
1160 * Repair the parent forum meta for each topic and reply
1161 *
1162 * @since 2.1.0 bbPress (r3876)
1163 *
1164 * @return array An array of the status code and the message
1165 */
1166 function bbp_admin_repair_forum_meta() {
1167
1168 // Define variables
1169 $bbp_db = bbp_db();
1170 $statement = esc_html__( 'Recalculating the forum for each post&hellip; %s', 'bbpress' );
1171 $result = esc_html__( 'Failed!', 'bbpress' );
1172
1173 // First, delete everything.
1174 if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_forum_id'" ) ) ) {
1175 return array( 1, sprintf( $statement, $result ) );
1176 }
1177
1178 // Post types and status
1179 $tpt = bbp_get_topic_post_type();
1180 $rpt = bbp_get_reply_post_type();
1181 $fmt = bbp_get_forum_post_type();
1182
1183 // Next, give all the topics their parent forum id.
1184 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
1185 ( SELECT `topic`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
1186 FROM `$bbp_db->posts`
1187 AS `topic`
1188 WHERE `topic`.`post_type` = '{$tpt}'
1189 GROUP BY `topic`.`ID` )" ) ) ) {
1190 return array( 2, sprintf( $statement, $result ) );
1191 }
1192
1193 // Next, give all the forums their parent forum id.
1194 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
1195 ( SELECT `forum`.`ID`, '_bbp_forum_id', `forum`.`post_parent`
1196 FROM `$bbp_db->posts`
1197 AS `forum`
1198 WHERE `forum`.`post_type` = '{$fmt}'
1199 GROUP BY `forum`.`ID` )" ) ) ) {
1200 return array( 2, sprintf( $statement, $result ) );
1201 }
1202
1203 // Next, give all the replies their parent forum id.
1204 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
1205 ( SELECT `reply`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
1206 FROM `$bbp_db->posts`
1207 AS `reply`
1208 INNER JOIN `$bbp_db->posts`
1209 AS `topic`
1210 ON `reply`.`post_parent` = `topic`.`ID`
1211 WHERE `topic`.`post_type` = '{$tpt}'
1212 AND `reply`.`post_type` = '{$rpt}'
1213 GROUP BY `reply`.`ID` )" ) ) ) {
1214 return array( 3, sprintf( $statement, $result ) );
1215 }
1216
1217 // Complete results
1218 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1219 }
1220
1221 /**
1222 * Repair the topic for each post
1223 *
1224 * @since 2.1.0 bbPress (r3876)
1225 *
1226 * @return array An array of the status code and the message
1227 */
1228 function bbp_admin_repair_topic_meta() {
1229
1230 // Define variables
1231 $bbp_db = bbp_db();
1232 $statement = esc_html__( 'Recalculating the topic for each post&hellip; %s', 'bbpress' );
1233 $result = esc_html__( 'Failed!', 'bbpress' );
1234
1235 // First, delete everything.
1236 if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_topic_id'" ) ) ) {
1237 return array( 1, sprintf( $statement, $result ) );
1238 }
1239
1240 // Post types and status
1241 $tpt = bbp_get_topic_post_type();
1242 $rpt = bbp_get_reply_post_type();
1243
1244 // Next, give all the topics with replies the ID their last reply.
1245 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
1246 ( SELECT `topic`.`ID`, '_bbp_topic_id', `topic`.`ID`
1247 FROM `$bbp_db->posts`
1248 AS `topic`
1249 WHERE `topic`.`post_type` = '{$tpt}'
1250 GROUP BY `topic`.`ID` )" ) ) ) {
1251 return array( 3, sprintf( $statement, $result ) );
1252 }
1253
1254 // Next, give all the topics with replies the ID their last reply.
1255 if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
1256 ( SELECT `reply`.`ID`, '_bbp_topic_id', `topic`.`ID`
1257 FROM `$bbp_db->posts`
1258 AS `reply`
1259 INNER JOIN `$bbp_db->posts`
1260 AS `topic`
1261 ON `reply`.`post_parent` = `topic`.`ID`
1262 WHERE `topic`.`post_type` = '{$tpt}'
1263 AND `reply`.`post_type` = '{$rpt}'
1264 GROUP BY `reply`.`ID` )" ) ) ) {
1265 return array( 4, sprintf( $statement, $result ) );
1266 }
1267
1268 // Complete results
1269 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1270 }
1271
1272 /**
1273 * Recalculate reply menu order
1274 *
1275 * @since 2.5.4 bbPress (r5367)
1276 *
1277 * @return array An array of the status code and the message
1278 */
1279 function bbp_admin_repair_reply_menu_order() {
1280
1281 // Define variables
1282 $bbp_db = bbp_db();
1283 $statement = esc_html__( 'Recalculating reply menu order&hellip; %s', 'bbpress' );
1284 $result = esc_html__( 'No reply positions to recalculate.', 'bbpress' );
1285
1286 // Delete cases where `_bbp_reply_to` was accidentally set to itself
1287 if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_reply_to' AND `post_id` = `meta_value`" ) ) ) {
1288 return array( 1, sprintf( $statement, $result ) );
1289 }
1290
1291 // Post type
1292 $rpt = bbp_get_reply_post_type();
1293
1294 // Get an array of reply id's to update the menu oder for each reply
1295 $replies = $bbp_db->get_results( "SELECT `a`.`ID` FROM `{$bbp_db->posts}` AS `a`
1296 INNER JOIN (
1297 SELECT `menu_order`, `post_parent`
1298 FROM `{$bbp_db->posts}`
1299 GROUP BY `menu_order`, `post_parent`
1300 HAVING COUNT( * ) >1
1301 )`b`
1302 ON `a`.`menu_order` = `b`.`menu_order`
1303 AND `a`.`post_parent` = `b`.`post_parent`
1304 WHERE `post_type` = '{$rpt}'", OBJECT_K );
1305
1306 // Bail if no replies returned
1307 if ( empty( $replies ) ) {
1308 return array( 1, sprintf( $statement, $result ) );
1309 }
1310
1311 // Recalculate the menu order position for each reply
1312 foreach ( $replies as $reply ) {
1313 bbp_update_reply_position( $reply->ID );
1314 }
1315
1316 // Cleanup
1317 unset( $replies, $reply );
1318
1319 // Complete results
1320 return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
1321 }
1322