PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / trunk
Forumax – AI Powered Advanced Community Forum Plugin vtrunk
2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 2.0.0 2.1.0 All 29 releases
bbp-core / lib / bbpress / includes / admin / tools / repair.php

repair.php in Forumax – AI Powered Advanced Community Forum Plugin trunk, at lib/bbpress/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