| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * BuddyPress Tools panel |
| 5 | * |
| 6 | * @since BuddyPress (2.0.0) |
| 7 | */ |
| 8 | |
| 9 | /** |
| 10 | * Render the BuddyPress Tools page. |
| 11 | * |
| 12 | * @since BuddyPress (2.0.0) |
| 13 | */ |
| 14 | function bp_core_admin_tools() { |
| 15 | ?> |
| 16 | <div class="wrap"> |
| 17 | <?php screen_icon( 'buddypress'); ?> |
| 18 | |
| 19 | <h2 class="nav-tab-wrapper"><?php bp_core_admin_tabs( __( 'Tools', 'buddypress' ) ); ?></h2> |
| 20 | |
| 21 | <p><?php esc_html_e( 'BuddyPress keeps track of various relationships between users, groups, and activity items. Occasionally these relationships become out of sync, most often after an import, update, or migration. Use the tools below to manually recalculate these relationships.', 'buddypress' ); ?></p> |
| 22 | <p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Avoid running more than one repair job at a time.', 'buddypress' ); ?></p> |
| 23 | |
| 24 | <form class="settings" method="post" action=""> |
| 25 | <table class="form-table"> |
| 26 | <tbody> |
| 27 | <tr valign="top"> |
| 28 | <th scope="row"><?php esc_html_e( 'Data to Repair:', 'buddypress' ) ?></th> |
| 29 | <td> |
| 30 | <fieldset> |
| 31 | <legend class="screen-reader-text"><span><?php esc_html_e( 'Repair', 'buddypress' ) ?></span></legend> |
| 32 | |
| 33 | <?php foreach ( bp_admin_repair_list() as $item ) : ?> |
| 34 | |
| 35 | <label><input type="checkbox" class="checkbox" name="<?php echo esc_attr( $item[0] ) . '" id="' . esc_attr( str_replace( '_', '-', $item[0] ) ); ?>" value="1" /> <?php echo esc_html( $item[1] ); ?></label><br /> |
| 36 | |
| 37 | <?php endforeach; ?> |
| 38 | |
| 39 | </fieldset> |
| 40 | </td> |
| 41 | </tr> |
| 42 | </tbody> |
| 43 | </table> |
| 44 | |
| 45 | <fieldset class="submit"> |
| 46 | <input class="button-primary" type="submit" name="submit" value="<?php esc_attr_e( 'Repair Items', 'buddypress' ); ?>" /> |
| 47 | <?php wp_nonce_field( 'bp-do-counts' ); ?> |
| 48 | </fieldset> |
| 49 | </form> |
| 50 | </div> |
| 51 | <?php |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Handle the processing and feedback of the admin tools page. |
| 56 | * |
| 57 | * @since BuddyPress (2.0.0) |
| 58 | */ |
| 59 | function bp_admin_repair_handler() { |
| 60 | if ( ! bp_is_post_request() ) { |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | check_admin_referer( 'bp-do-counts' ); |
| 65 | |
| 66 | // Stores messages |
| 67 | $messages = array(); |
| 68 | |
| 69 | wp_cache_flush(); |
| 70 | |
| 71 | foreach ( (array) bp_admin_repair_list() as $item ) { |
| 72 | if ( isset( $item[2] ) && isset( $_POST[$item[0]] ) && 1 === absint( $_POST[$item[0]] ) && is_callable( $item[2] ) ) { |
| 73 | $messages[] = call_user_func( $item[2] ); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | if ( count( $messages ) ) { |
| 78 | foreach ( $messages as $message ) { |
| 79 | bp_admin_tools_feedback( $message[1] ); |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | add_action( bp_core_admin_hook(), 'bp_admin_repair_handler' ); |
| 84 | |
| 85 | /** |
| 86 | * Get the array of the repair list. |
| 87 | * |
| 88 | * @return array |
| 89 | */ |
| 90 | function bp_admin_repair_list() { |
| 91 | // Members: |
| 92 | // - member count |
| 93 | $repair_list = array( |
| 94 | 20 => array( |
| 95 | 'bp-total-member-count', |
| 96 | __( 'Count total members', 'buddypress' ), |
| 97 | 'bp_admin_repair_count_members', |
| 98 | ), |
| 99 | ); |
| 100 | |
| 101 | // Friends: |
| 102 | // - user friend count |
| 103 | if ( bp_is_active( 'friends' ) ) { |
| 104 | $repair_list[0] = array( |
| 105 | 'bp-user-friends', |
| 106 | __( 'Count friends for each user', 'buddypress' ), |
| 107 | 'bp_admin_repair_friend_count', |
| 108 | ); |
| 109 | } |
| 110 | |
| 111 | // Groups: |
| 112 | // - user group count |
| 113 | if ( bp_is_active( 'groups' ) ) { |
| 114 | $repair_list[10] = array( |
| 115 | 'bp-group-count', |
| 116 | __( 'Count groups for each user', 'buddypress' ), |
| 117 | 'bp_admin_repair_group_count', |
| 118 | ); |
| 119 | } |
| 120 | |
| 121 | ksort( $repair_list ); |
| 122 | |
| 123 | return (array) apply_filters( 'bp_repair_list', $repair_list ); |
| 124 | } |
| 125 | |
| 126 | /** |
| 127 | * Recalculate friend counts for each user. |
| 128 | * |
| 129 | * @since BuddyPress (2.0.0) |
| 130 | * |
| 131 | * @return array |
| 132 | */ |
| 133 | function bp_admin_repair_friend_count() { |
| 134 | global $wpdb, $bp; |
| 135 | |
| 136 | if ( ! bp_is_active( 'friends' ) ) { |
| 137 | return; |
| 138 | } |
| 139 | |
| 140 | $statement = __( 'Counting the number of friends for each user… %s', 'buddypress' ); |
| 141 | $result = __( 'Failed!', 'buddypress' ); |
| 142 | |
| 143 | $sql_delete = "DELETE FROM {$wpdb->usermeta} WHERE meta_key IN ( 'total_friend_count' );"; |
| 144 | if ( is_wp_error( $wpdb->query( $sql_delete ) ) ) { |
| 145 | return array( 1, sprintf( $statement, $result ) ); |
| 146 | } |
| 147 | |
| 148 | // Walk through all users on the site |
| 149 | $total_users = $wpdb->get_row( "SELECT count(ID) as c FROM {$wpdb->users}" )->c; |
| 150 | |
| 151 | $updated = array(); |
| 152 | if ( $total_users > 0 ) { |
| 153 | $per_query = 500; |
| 154 | $offset = 0; |
| 155 | while ( $offset < $total_users ) { |
| 156 | // Only bother updating counts for users who actually have friendships |
| 157 | $friendships = $wpdb->get_results( $wpdb->prepare( "SELECT initiator_user_id, friend_user_id FROM {$bp->friends->table_name} WHERE is_confirmed = 1 AND ( ( initiator_user_id > %d AND initiator_user_id <= %d ) OR ( friend_user_id > %d AND friend_user_id <= %d ) )", $offset, $offset + $per_query, $offset, $offset + $per_query ) ); |
| 158 | |
| 159 | // The previous query will turn up duplicates, so we |
| 160 | // filter them here |
| 161 | foreach ( $friendships as $friendship ) { |
| 162 | if ( ! isset( $updated[ $friendship->initiator_user_id ] ) ) { |
| 163 | BP_Friends_Friendship::total_friend_count( $friendship->initiator_user_id ); |
| 164 | $updated[ $friendship->initiator_user_id ] = 1; |
| 165 | } |
| 166 | |
| 167 | if ( ! isset( $updated[ $friendship->friend_user_id ] ) ) { |
| 168 | BP_Friends_Friendship::total_friend_count( $friendship->friend_user_id ); |
| 169 | $updated[ $friendship->friend_user_id ] = 1; |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | $offset += $per_query; |
| 174 | } |
| 175 | } else { |
| 176 | return array( 2, sprintf( $statement, $result ) ); |
| 177 | } |
| 178 | |
| 179 | return array( 0, sprintf( $statement, __( 'Complete!', 'buddypress' ) ) ); |
| 180 | } |
| 181 | |
| 182 | /** |
| 183 | * Recalculate group counts for each user. |
| 184 | * |
| 185 | * @since BuddyPress (2.0.0) |
| 186 | * |
| 187 | * @return array |
| 188 | */ |
| 189 | function bp_admin_repair_group_count() { |
| 190 | global $wpdb, $bp; |
| 191 | |
| 192 | if ( ! bp_is_active( 'groups' ) ) { |
| 193 | return; |
| 194 | } |
| 195 | |
| 196 | $statement = __( 'Counting the number of groups for each user… %s', 'buddypress' ); |
| 197 | $result = __( 'Failed!', 'buddypress' ); |
| 198 | |
| 199 | $sql_delete = "DELETE FROM {$wpdb->usermeta} WHERE meta_key IN ( 'total_group_count' );"; |
| 200 | if ( is_wp_error( $wpdb->query( $sql_delete ) ) ) { |
| 201 | return array( 1, sprintf( $statement, $result ) ); |
| 202 | } |
| 203 | |
| 204 | // Walk through all users on the site |
| 205 | $total_users = $wpdb->get_row( "SELECT count(ID) as c FROM {$wpdb->users}" )->c; |
| 206 | |
| 207 | if ( $total_users > 0 ) { |
| 208 | $per_query = 500; |
| 209 | $offset = 0; |
| 210 | while ( $offset < $total_users ) { |
| 211 | // But only bother to update counts for users that have groups |
| 212 | $users = $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM {$bp->groups->table_name_members} WHERE is_confirmed = 1 AND is_banned = 0 AND user_id > %d AND user_id <= %d", $offset, $offset + $per_query ) ); |
| 213 | |
| 214 | foreach ( $users as $user ) { |
| 215 | BP_Groups_Member::refresh_total_group_count_for_user( $user ); |
| 216 | } |
| 217 | |
| 218 | $offset += $per_query; |
| 219 | } |
| 220 | } else { |
| 221 | return array( 2, sprintf( $statement, $result ) ); |
| 222 | } |
| 223 | |
| 224 | return array( 0, sprintf( $statement, __( 'Complete!', 'buddypress' ) ) ); |
| 225 | } |
| 226 | |
| 227 | /** |
| 228 | * Recalculate the total number of active site members. |
| 229 | * |
| 230 | * @since BuddyPress (2.0.0) |
| 231 | */ |
| 232 | function bp_admin_repair_count_members() { |
| 233 | $statement = __( 'Counting the number of active members on the site… %s', 'buddypress' ); |
| 234 | delete_transient( 'bp_active_member_count' ); |
| 235 | bp_core_get_active_member_count(); |
| 236 | return array( 0, sprintf( $statement, __( 'Complete!', 'buddypress' ) ) ); |
| 237 | } |
| 238 | |
| 239 | /** |
| 240 | * Assemble admin notices relating success/failure of repair processes. |
| 241 | * |
| 242 | * @since BuddyPress (2.0.0) |
| 243 | * |
| 244 | * @param string $message Feedback message. |
| 245 | * @param unknown $class Unused. |
| 246 | */ |
| 247 | function bp_admin_tools_feedback( $message, $class = false ) { |
| 248 | if ( is_string( $message ) ) { |
| 249 | $message = '<p>' . $message . '</p>'; |
| 250 | $class = $class ? $class : 'updated'; |
| 251 | } elseif ( is_wp_error( $message ) ) { |
| 252 | $errors = $message->get_error_messages(); |
| 253 | |
| 254 | switch ( count( $errors ) ) { |
| 255 | case 0: |
| 256 | return false; |
| 257 | break; |
| 258 | |
| 259 | case 1: |
| 260 | $message = '<p>' . $errors[0] . '</p>'; |
| 261 | break; |
| 262 | |
| 263 | default: |
| 264 | $message = '<ul>' . "\n\t" . '<li>' . implode( '</li>' . "\n\t" . '<li>', $errors ) . '</li>' . "\n" . '</ul>'; |
| 265 | break; |
| 266 | } |
| 267 | |
| 268 | $class = $class ? $class : 'error'; |
| 269 | } else { |
| 270 | return false; |
| 271 | } |
| 272 | |
| 273 | $message = '<div id="message" class="' . esc_attr( $class ) . '">' . $message . '</div>'; |
| 274 | $message = str_replace( "'", "\'", $message ); |
| 275 | $lambda = create_function( '', "echo '$message';" ); |
| 276 | |
| 277 | add_action( 'admin_notices', $lambda ); |
| 278 | |
| 279 | return $lambda; |
| 280 | } |