| @@ -106,12 +106,13 @@ | ||
| 106 | 106 | array( |
| 107 | 107 | 'ajax_url' => admin_url( 'admin-ajax.php' ), |
| 108 | 108 | 'security' => wp_create_nonce( 'tptn-admin' ), |
| 109 | 109 | 'strings' => array( |
| 110 | - 'confirm_message' => esc_html__( 'Are you sure you want to clear the cache?', 'top-10' ), | |
| 111 | - 'clearing_text' => esc_html__( 'Clearing...', 'top-10' ), | |
| 112 | - 'fail_message' => esc_html__( 'Failed to clear cache. Please try again.', 'top-10' ), | |
| 113 | - 'request_fail_message' => esc_html__( 'Request failed: ', 'top-10' ), | |
| 110 | + 'confirm_message' => esc_html__( 'Are you sure you want to clear the cache?', 'top-10' ), | |
| 111 | + 'network_confirm_message' => esc_html__( 'Are you sure you want to clear the Top 10 cache across all active sites?', 'top-10' ), | |
| 112 | + 'clearing_text' => esc_html__( 'Clearing...', 'top-10' ), | |
| 113 | + 'fail_message' => esc_html__( 'Failed to clear cache. Please try again.', 'top-10' ), | |
| 114 | + 'request_fail_message' => esc_html__( 'Request failed: ', 'top-10' ), | |
| 114 | 115 | ), |
| 115 | 116 | ) |
| 116 | 117 | ); |
| 117 | 118 | } |
| @@ -125,16 +126,18 @@ | ||
| 125 | 126 | * @return void |
| 126 | 127 | */ |
| 127 | 128 | public function render_page() { |
| 128 | 129 | $screen = get_current_screen(); |
| 129 | - $network_wide = false; | |
| 130 | + $network_wide = is_multisite() && is_network_admin(); | |
| 130 | 131 | |
| 131 | - if ( $screen->id === $this->parent_id . '-network' ) { | |
| 132 | + // Keep the screen check as a fallback for admin screen implementations that | |
| 133 | + // do not expose is_network_admin() reliably. | |
| 134 | + if ( $screen && $screen->id === $this->parent_id . '-network' ) { | |
| 132 | 135 | $network_wide = true; |
| 133 | 136 | } |
| 134 | 137 | |
| 135 | - /* Truncate overall posts table */ | |
| 136 | - if ( isset( $_POST['tptn_recreate_primary_key'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { | |
| 138 | + /* Recreate the shared table indexes. */ | |
| 139 | + if ( ( ! is_multisite() || $network_wide ) && isset( $_POST['tptn_recreate_primary_key'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { | |
| 137 | 140 | self::recreate_primary_key(); |
| 138 | 141 | add_settings_error( 'tptn-notices', '', esc_html__( 'Primary Key has been recreated', 'top-10' ), 'updated' ); |
| 139 | 142 | } |
| 140 | 143 | |
| @@ -144,8 +147,9 @@ | ||
| 144 | 147 | Database::truncate_table( Database::get_table( false ) ); |
| 145 | 148 | } else { |
| 146 | 149 | Counter::delete_counts( array( 'daily' => false ) ); |
| 147 | 150 | } |
| 151 | + Dashboard_Widgets::clear_network_dashboard_cache(); | |
| 148 | 152 | add_settings_error( 'tptn-notices', '', esc_html__( 'Top 10 popular posts reset', 'top-10' ), 'updated' ); |
| 149 | 153 | } |
| 150 | 154 | |
| 151 | 155 | /* Truncate daily posts table */ |
| @@ -154,13 +158,14 @@ | ||
| 154 | 158 | Database::truncate_table( Database::get_table( true ) ); |
| 155 | 159 | } else { |
| 156 | 160 | Counter::delete_counts( array( 'daily' => true ) ); |
| 157 | 161 | } |
| 162 | + Dashboard_Widgets::clear_network_dashboard_cache(); | |
| 158 | 163 | add_settings_error( 'tptn-notices', '', esc_html__( 'Top 10 daily popular posts reset', 'top-10' ), 'updated' ); |
| 159 | 164 | } |
| 160 | 165 | |
| 161 | - /* Recreate tables */ | |
| 162 | - if ( isset( $_POST['tptn_recreate_tables'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { | |
| 166 | + /* Recreate the shared tables. */ | |
| 167 | + if ( ( ! is_multisite() || $network_wide ) && isset( $_POST['tptn_recreate_tables'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { | |
| 163 | 168 | $result = self::recreate_tables(); |
| 164 | 169 | if ( is_wp_error( $result ) ) { |
| 165 | 170 | add_settings_error( 'tptn-notices', '', $result->get_error_message(), 'error' ); |
| 166 | 171 | } else { |
| @@ -169,13 +174,20 @@ | ||
| 169 | 174 | } |
| 170 | 175 | |
| 171 | 176 | /* Sync funnel (run aggregation now) */ |
| 172 | 177 | if ( isset( $_POST['tptn_sync_funnel'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { |
| 173 | - $result = Database::aggregate_visit_log(); | |
| 178 | + $blog_id = ( is_multisite() && ! $network_wide ) ? get_current_blog_id() : null; | |
| 179 | + $result = Database::aggregate_visit_log( 10000, $blog_id ); | |
| 174 | 180 | if ( true === $result ) { |
| 175 | - add_settings_error( 'tptn-notices', '', esc_html__( 'Funnel has been synced. Buffered visits have been aggregated.', 'top-10' ), 'updated' ); | |
| 181 | + $message = $network_wide | |
| 182 | + ? __( 'The network funnel has been synced. Buffered visits from all sites have been aggregated.', 'top-10' ) | |
| 183 | + : __( 'The site funnel has been synced. Buffered visits for this site have been aggregated.', 'top-10' ); | |
| 184 | + add_settings_error( 'tptn-notices', '', esc_html( $message ), 'updated' ); | |
| 176 | 185 | } elseif ( 0 === $result ) { |
| 177 | - add_settings_error( 'tptn-notices', '', esc_html__( 'Nothing to sync. The funnel is empty.', 'top-10' ), 'updated' ); | |
| 186 | + $message = $network_wide | |
| 187 | + ? __( 'Nothing to sync. The network funnel is empty.', 'top-10' ) | |
| 188 | + : __( 'Nothing to sync. This site funnel is empty.', 'top-10' ); | |
| 189 | + add_settings_error( 'tptn-notices', '', esc_html( $message ), 'updated' ); | |
| 178 | 190 | } elseif ( false === $result ) { |
| 179 | 191 | add_settings_error( 'tptn-notices', '', esc_html__( 'Sync skipped: another aggregation is already in progress. Please try again in a moment.', 'top-10' ), 'updated' ); |
| 180 | 192 | } elseif ( is_wp_error( $result ) ) { |
| 181 | 193 | add_settings_error( |
| @@ -192,9 +204,9 @@ | ||
| 192 | 204 | } |
| 193 | 205 | |
| 194 | 206 | /* Fix cron schedules */ |
| 195 | 207 | if ( isset( $_POST['tptn_fix_crons'] ) && check_admin_referer( 'tptn-tools-settings' ) ) { |
| 196 | - $result = self::fix_crons(); | |
| 208 | + $result = self::fix_crons( $network_wide ); | |
| 197 | 209 | if ( is_wp_error( $result ) ) { |
| 198 | 210 | add_settings_error( 'tptn-notices', '', implode( ' ', array_map( 'esc_html', $result->get_error_messages() ) ), 'error' ); |
| 199 | 211 | } else { |
| 200 | 212 | add_settings_error( 'tptn-notices', '', esc_html( $result ), 'updated' ); |
| @@ -204,9 +216,12 @@ | ||
| 204 | 216 | ob_start(); |
| 205 | 217 | ?> |
| 206 | 218 | <div class="wrap"> |
| 207 | 219 | <h1><?php esc_html_e( 'Top 10 Tools', 'top-10' ); ?></h1> |
| 208 | - <?php do_action( 'tptn_settings_page_header' ); ?> | |
| 220 | + <?php | |
| 221 | + /** This action is documented in includes/admin/class-dashboard.php */ | |
| 222 | + do_action( 'tptn_settings_page_header' ); | |
| 223 | + ?> | |
| 209 | 224 | |
| 210 | 225 | <?php settings_errors(); ?> |
| 211 | 226 | |
| 212 | 227 | <div id="poststuff"> |
| @@ -229,70 +244,110 @@ | ||
| 229 | 244 | <div class="inside"> |
| 230 | 245 | <p> |
| 231 | 246 | <?php |
| 232 | 247 | printf( |
| 233 | - '<button type="button" name="tptn_cache_clear" class="button button-secondary tptn_cache_clear" aria-label="%1$s">%1$s</button>', | |
| 234 | - esc_html__( 'Clear cache', 'top-10' ) | |
| 248 | + '<button type="button" name="tptn_cache_clear" class="button button-secondary tptn_cache_clear" data-network-wide="%1$s" aria-label="%2$s">%2$s</button>', | |
| 249 | + $network_wide ? '1' : '0', | |
| 250 | + esc_html( $network_wide ? __( 'Clear Cache Across Network', 'top-10' ) : __( 'Clear cache', 'top-10' ) ) | |
| 235 | 251 | ); |
| 236 | 252 | ?> |
| 237 | 253 | </p> |
| 238 | 254 | <p class="description"> |
| 239 | - <?php esc_html_e( 'Clear the Top 10 cache. This will also be cleared automatically when you save the settings page.', 'top-10' ); ?> | |
| 255 | + <?php | |
| 256 | + if ( $network_wide ) { | |
| 257 | + esc_html_e( 'Clear the Top 10 cache for all active sites in the network.', 'top-10' ); | |
| 258 | + } else { | |
| 259 | + esc_html_e( 'Clear the Top 10 cache. This will also be cleared automatically when you save the settings page.', 'top-10' ); | |
| 260 | + } | |
| 261 | + ?> | |
| 240 | 262 | </p> |
| 241 | 263 | </div> |
| 242 | 264 | </div> |
| 243 | 265 | |
| 244 | 266 | <div class="postbox"> |
| 245 | - <h2><span><?php esc_html_e( 'Sync Funnel', 'top-10' ); ?></span></h2> | |
| 267 | + <h2><span><?php echo esc_html( $network_wide ? __( 'Sync Network Funnel', 'top-10' ) : __( 'Sync Funnel', 'top-10' ) ); ?></span></h2> | |
| 246 | 268 | <div class="inside"> |
| 247 | 269 | <p> |
| 248 | - <button name="tptn_sync_funnel" type="submit" id="tptn_sync_funnel" class="button button-secondary"><?php esc_attr_e( 'Sync Funnel Now', 'top-10' ); ?></button> | |
| 270 | + <button name="tptn_sync_funnel" type="submit" id="tptn_sync_funnel" class="button button-secondary"><?php echo esc_html( $network_wide ? __( 'Sync Network Funnel Now', 'top-10' ) : __( 'Sync Funnel Now', 'top-10' ) ); ?></button> | |
| 249 | 271 | </p> |
| 250 | 272 | <p class="description"> |
| 251 | - <?php esc_html_e( 'Drain the visits funnel into the count tables immediately. This is equivalent to running the aggregation cron job.', 'top-10' ); ?> | |
| 273 | + <?php | |
| 274 | + if ( $network_wide ) { | |
| 275 | + esc_html_e( 'Drain buffered visits from all sites into the count tables immediately. This is equivalent to running the aggregation cron job.', 'top-10' ); | |
| 276 | + } else { | |
| 277 | + esc_html_e( 'Drain this site\'s buffered visits into the count tables immediately. Other sites\' buffered visits are not affected.', 'top-10' ); | |
| 278 | + } | |
| 279 | + ?> | |
| 252 | 280 | </p> |
| 253 | 281 | </div> |
| 254 | 282 | </div> |
| 255 | 283 | |
| 284 | + <?php | |
| 285 | + /** | |
| 286 | + * Fires between the action boxes on the Tools page. | |
| 287 | + * | |
| 288 | + * @since 4.5.0 | |
| 289 | + * | |
| 290 | + * @param bool $network_wide Whether the Tools page is being rendered in network admin. | |
| 291 | + */ | |
| 292 | + do_action( 'tptn_tools_page_actions', $network_wide ); | |
| 293 | + ?> | |
| 294 | + | |
| 256 | 295 | <div class="postbox"> |
| 257 | - <h2><span><?php esc_html_e( 'Fix Cron Schedules', 'top-10' ); ?></span></h2> | |
| 296 | + <h2><span><?php echo esc_html( $network_wide ? __( 'Fix Network Cron Schedules', 'top-10' ) : __( 'Fix Cron Schedules', 'top-10' ) ); ?></span></h2> | |
| 258 | 297 | <div class="inside"> |
| 259 | 298 | <p> |
| 260 | - <button name="tptn_fix_crons" type="submit" id="tptn_fix_crons" class="button button-secondary"><?php esc_attr_e( 'Fix Cron Schedules', 'top-10' ); ?></button> | |
| 299 | + <button name="tptn_fix_crons" type="submit" id="tptn_fix_crons" class="button button-secondary"><?php echo esc_html( $network_wide ? __( 'Fix Network Cron Schedules', 'top-10' ) : __( 'Fix Cron Schedules', 'top-10' ) ); ?></button> | |
| 261 | 300 | </p> |
| 262 | 301 | <p class="description"> |
| 263 | - <?php esc_html_e( 'Clears and reschedules the Top 10 cron jobs (maintenance and aggregation). Use this if the status above shows a job as not scheduled or if your error log reports cron reschedule errors for the Top 10 hooks.', 'top-10' ); ?> | |
| 302 | + <?php | |
| 303 | + if ( $network_wide ) { | |
| 304 | + esc_html_e( 'Clears and reschedules the Top 10 maintenance and aggregation jobs for all active sites. Use this if a site\'s job is not scheduled or if your error log reports cron reschedule errors.', 'top-10' ); | |
| 305 | + } else { | |
| 306 | + esc_html_e( 'Clears and reschedules the Top 10 cron jobs for this site. Use this if the status above shows a job as not scheduled or if your error log reports cron reschedule errors for the Top 10 hooks.', 'top-10' ); | |
| 307 | + } | |
| 308 | + ?> | |
| 264 | 309 | </p> |
| 265 | 310 | </div> |
| 266 | 311 | </div> |
| 267 | 312 | |
| 268 | - <div class="postbox"> | |
| 269 | - <h2><span><?php esc_html_e( 'Recreate Primary Key', 'top-10' ); ?></span></h2> | |
| 270 | - <div class="inside"> | |
| 271 | - <p> | |
| 272 | - <button name="tptn_recreate_primary_key" type="submit" id="tptn_recreate_primary_key" class="button button-secondary"><?php esc_attr_e( 'Recreate Primary Key', 'top-10' ); ?></button> | |
| 273 | - </p> | |
| 274 | - <p class="description"> | |
| 275 | - <?php esc_html_e( 'Deletes and reinitializes the primary key in the database tables. If the above function gives an error, then you can run the below code in phpMyAdmin or Adminer. Remember to backup your database first!', 'top-10' ); ?> | |
| 276 | - </p> | |
| 277 | - <p> | |
| 278 | - <code style="display:block;"><?php echo self::recreate_primary_key_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></code> | |
| 279 | - </p> | |
| 313 | + <?php if ( ! is_multisite() || $network_wide ) : ?> | |
| 314 | + <div class="postbox"> | |
| 315 | + <h2><span><?php esc_html_e( 'Recreate Primary Key', 'top-10' ); ?></span></h2> | |
| 316 | + <div class="inside"> | |
| 317 | + <p> | |
| 318 | + <button name="tptn_recreate_primary_key" type="submit" id="tptn_recreate_primary_key" class="button button-secondary"><?php esc_attr_e( 'Recreate Primary Key', 'top-10' ); ?></button> | |
| 319 | + </p> | |
| 320 | + <p class="description"> | |
| 321 | + <?php esc_html_e( 'Deletes and reinitializes the primary key in the shared database tables. Run this from Network Admin on multisite installations. Remember to back up your database first!', 'top-10' ); ?> | |
| 322 | + </p> | |
| 323 | + <p> | |
| 324 | + <code style="display:block;"><?php echo self::recreate_primary_key_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></code> | |
| 325 | + </p> | |
| 326 | + </div> | |
| 280 | 327 | </div> |
| 281 | - </div> | |
| 328 | + <?php endif; ?> | |
| 282 | 329 | |
| 283 | 330 | <div class="postbox"> |
| 284 | 331 | <h2><span><?php esc_html_e( 'Reset database', 'top-10' ); ?></span></h2> |
| 285 | 332 | <div class="inside"> |
| 286 | 333 | <p class="description"> |
| 287 | - <?php esc_html_e( 'This will reset the Top 10 tables. If this is a multisite install, this will reset the popular posts for the current site. If this is the Network Admin screen, then it will reset the popular posts across all sites. This cannot be reversed. Make sure that your database has been backed up before proceeding', 'top-10' ); ?> | |
| 334 | + <?php | |
| 335 | + if ( $network_wide ) { | |
| 336 | + esc_html_e( 'This will reset the Top 10 popular posts across all sites in the network. This cannot be reversed. Make sure that your database has been backed up before proceeding.', 'top-10' ); | |
| 337 | + } elseif ( is_multisite() ) { | |
| 338 | + esc_html_e( 'This will reset the Top 10 popular posts for the current site only. Other sites in the network will not be affected. This cannot be reversed. Make sure that your database has been backed up before proceeding.', 'top-10' ); | |
| 339 | + } else { | |
| 340 | + esc_html_e( 'This will reset the Top 10 popular posts for this site. This cannot be reversed. Make sure that your database has been backed up before proceeding.', 'top-10' ); | |
| 341 | + } | |
| 342 | + ?> | |
| 288 | 343 | </p> |
| 289 | 344 | <p> |
| 290 | 345 | <?php |
| 291 | 346 | printf( |
| 292 | 347 | '<button name="tptn_reset_overall" type="submit" id="tptn_reset_overall" class="button button-secondary" style="color:#fff;background-color: #a00;border-color: #900;" onclick="if (!confirm(\'%s\')) return false;">%s</button>', |
| 293 | - esc_attr__( 'Are you sure you want to reset the popular posts?', 'top-10' ), | |
| 294 | - esc_attr__( 'Reset Popular Posts', 'top-10' ) | |
| 348 | + esc_attr__( $network_wide ? 'Are you sure you want to reset popular posts across the network?' : 'Are you sure you want to reset the popular posts for this site?', 'top-10' ), | |
| 349 | + esc_attr__( $network_wide ? 'Reset Popular Posts Across Network' : 'Reset Popular Posts', 'top-10' ) | |
| 295 | 350 | ); |
| 296 | 351 | ?> |
| 297 | 352 | </p> |
| 298 | 353 | <p> |
| @@ -298,10 +353,10 @@ | ||
| 298 | 353 | <p> |
| 299 | 354 | <?php |
| 300 | 355 | printf( |
| 301 | 356 | '<button name="tptn_reset_daily" type="submit" id="tptn_reset_daily" class="button button-secondary" style="color:#fff;background-color: #a00;border-color: #900;" onclick="if (!confirm(\'%s\')) return false;">%s</button>', |
| 302 | - esc_attr__( 'Are you sure you want to reset the daily popular posts?', 'top-10' ), | |
| 303 | - esc_attr__( 'Reset Daily Popular Posts', 'top-10' ) | |
| 357 | + esc_attr__( $network_wide ? 'Are you sure you want to reset daily popular posts across the network?' : 'Are you sure you want to reset the daily popular posts for this site?', 'top-10' ), | |
| 358 | + esc_attr__( $network_wide ? 'Reset Daily Popular Posts Across Network' : 'Reset Daily Popular Posts', 'top-10' ) | |
| 304 | 359 | ); |
| 305 | 360 | ?> |
| 306 | 361 | </p> |
| 307 | 362 | </div> |
| @@ -306,9 +361,9 @@ | ||
| 306 | 361 | </p> |
| 307 | 362 | </div> |
| 308 | 363 | </div> |
| 309 | 364 | |
| 310 | - <?php if ( ! is_multisite() || is_network_admin() ) : ?> | |
| 365 | + <?php if ( ! is_multisite() || $network_wide ) : ?> | |
| 311 | 366 | <div class="postbox"> |
| 312 | 367 | <h2><span><?php esc_html_e( 'Recreate Database Tables', 'top-10' ); ?></span></h2> |
| 313 | 368 | <div class="inside"> |
| 314 | 369 | <p class="description"> |
| @@ -431,8 +486,11 @@ | ||
| 431 | 486 | if ( is_wp_error( $result ) ) { |
| 432 | 487 | $errors->merge_from( $result ); |
| 433 | 488 | } |
| 434 | 489 | |
| 490 | + Database::clear_table_installation_cache(); | |
| 491 | + Dashboard_Widgets::clear_network_dashboard_cache(); | |
| 492 | + | |
| 435 | 493 | return $errors->has_errors() ? $errors : true; |
| 436 | 494 | } |
| 437 | 495 | |
| 438 | 496 | /** |
| @@ -439,11 +497,81 @@ | ||
| 439 | 497 | * Clear and reschedule the Top 10 cron jobs. |
| 440 | 498 | * |
| 441 | 499 | * @since 4.4.0 |
| 442 | 500 | * |
| 501 | + * @param bool $network_wide Whether to repair cron schedules for all active sites. | |
| 443 | 502 | * @return string|\WP_Error Success message or WP_Error if a job could not be rescheduled. |
| 444 | 503 | */ |
| 445 | - public static function fix_crons() { | |
| 504 | + public static function fix_crons( $network_wide = false ) { | |
| 505 | + if ( $network_wide && is_multisite() ) { | |
| 506 | + $site_ids = wp_list_pluck( | |
| 507 | + get_sites( | |
| 508 | + array( | |
| 509 | + 'archived' => 0, | |
| 510 | + 'spam' => 0, | |
| 511 | + 'deleted' => 0, | |
| 512 | + 'number' => 0, | |
| 513 | + ) | |
| 514 | + ), | |
| 515 | + 'blog_id' | |
| 516 | + ); | |
| 517 | + $errors = new \WP_Error(); | |
| 518 | + $sites_processed = 0; | |
| 519 | + $current_blog_id = get_current_blog_id(); | |
| 520 | + | |
| 521 | + foreach ( $site_ids as $site_id ) { | |
| 522 | + $site_id = absint( $site_id ); | |
| 523 | + $switched = $site_id !== $current_blog_id; | |
| 524 | + if ( $switched ) { | |
| 525 | + switch_to_blog( $site_id ); | |
| 526 | + } | |
| 527 | + | |
| 528 | + try { | |
| 529 | + $result = self::fix_crons_for_site(); | |
| 530 | + if ( is_wp_error( $result ) ) { | |
| 531 | + foreach ( $result->get_error_messages() as $message ) { | |
| 532 | + $errors->add( | |
| 533 | + 'tptn-cron-site-' . $site_id, | |
| 534 | + sprintf( | |
| 535 | + /* translators: 1: Site ID, 2: Error message. */ | |
| 536 | + __( 'Site %1$d: %2$s', 'top-10' ), | |
| 537 | + $site_id, | |
| 538 | + $message | |
| 539 | + ) | |
| 540 | + ); | |
| 541 | + } | |
| 542 | + } else { | |
| 543 | + ++$sites_processed; | |
| 544 | + } | |
| 545 | + } finally { | |
| 546 | + if ( $switched ) { | |
| 547 | + restore_current_blog(); | |
| 548 | + } | |
| 549 | + } | |
| 550 | + } | |
| 551 | + | |
| 552 | + if ( $errors->has_errors() ) { | |
| 553 | + return $errors; | |
| 554 | + } | |
| 555 | + | |
| 556 | + return sprintf( | |
| 557 | + /* translators: %s: Number of sites. */ | |
| 558 | + __( 'Cron schedules have been repaired for %s active site(s).', 'top-10' ), | |
| 559 | + number_format_i18n( $sites_processed ) | |
| 560 | + ); | |
| 561 | + } | |
| 562 | + | |
| 563 | + return self::fix_crons_for_site(); | |
| 564 | + } | |
| 565 | + | |
| 566 | + /** | |
| 567 | + * Clear and reschedule the Top 10 cron jobs for the current site. | |
| 568 | + * | |
| 569 | + * @since 4.5.0 | |
| 570 | + * | |
| 571 | + * @return string|\WP_Error Success message or WP_Error if a job could not be rescheduled. | |
| 572 | + */ | |
| 573 | + private static function fix_crons_for_site() { | |
| 446 | 574 | $errors = new \WP_Error(); |
| 447 | 575 | $messages = array(); |
| 448 | 576 | $success = true; |
| 449 | 577 | |
| @@ -548,8 +676,15 @@ | ||
| 548 | 676 | '<p>' . __( 'Clear the cache, reset the popular posts tables plus some miscellaneous fixes for older versions of Top 10.', 'top-10' ) . '</p>', |
| 549 | 677 | ) |
| 550 | 678 | ); |
| 551 | 679 | |
| 680 | + /** | |
| 681 | + * Fires after the Tools page help tabs have been registered. | |
| 682 | + * | |
| 683 | + * @since 2.5.0 | |
| 684 | + * | |
| 685 | + * @param \WP_Screen $screen The current screen object. | |
| 686 | + */ | |
| 552 | 687 | do_action( 'tptn_settings_tools_help', $screen ); |
| 553 | 688 | } |
| 554 | 689 | |
| 555 | 690 | /** |
| @@ -570,22 +705,24 @@ | ||
| 570 | 705 | $statuses = array(); |
| 571 | 706 | |
| 572 | 707 | $installed_label = '<span style="color: #006400;">' . __( 'Installed', 'top-10' ) . '</span>'; |
| 573 | 708 | $not_installed_label = '<span style="color: #8B0000;">' . __( 'Not Installed', 'top-10' ) . '</span>'; |
| 709 | + $table_statuses = Database::get_table_installation_status(); | |
| 574 | 710 | |
| 575 | 711 | foreach ( $tables as $key => $table_name ) { |
| 576 | - $statuses[ $key ] = Database::is_table_installed( $table_name ) ? $installed_label : $not_installed_label; | |
| 712 | + $statuses[ $key ] = ! empty( $table_statuses[ $table_name ] ) ? $installed_label : $not_installed_label; | |
| 577 | 713 | } |
| 578 | 714 | |
| 579 | 715 | // Create tables if they don't exist. |
| 580 | - if ( ! Database::are_tables_installed() ) { | |
| 716 | + if ( empty( $table_statuses[ Database::get_table( false ) ] ) || empty( $table_statuses[ Database::get_table( true ) ] ) ) { | |
| 581 | 717 | // Use Activator to create tables. |
| 582 | 718 | Activator::create_tables(); |
| 583 | 719 | Database::clear_table_statistics_cache(); |
| 720 | + $table_statuses = Database::get_table_installation_status( true ); | |
| 584 | 721 | |
| 585 | 722 | // Refresh statuses after creating tables. |
| 586 | 723 | foreach ( $tables as $key => $table_name ) { |
| 587 | - $statuses[ $key ] = Database::is_table_installed( $table_name ) ? $installed_label : $not_installed_label; | |
| 724 | + $statuses[ $key ] = ! empty( $table_statuses[ $table_name ] ) ? $installed_label : $not_installed_label; | |
| 588 | 725 | } |
| 589 | 726 | } |
| 590 | 727 | |
| 591 | 728 | /** |
| @@ -625,9 +762,14 @@ | ||
| 625 | 762 | </td> |
| 626 | 763 | </tr> |
| 627 | 764 | |
| 628 | 765 | <?php |
| 629 | - $table_keys = array( 'top_ten', 'top_ten_daily', 'top_ten_visits_funnel', 'top_ten_visits_log' ); | |
| 766 | + $table_keys = array( | |
| 767 | + 'top_ten', | |
| 768 | + 'top_ten_daily', | |
| 769 | + 'top_ten_visits_funnel', | |
| 770 | + 'top_ten_visits_log', | |
| 771 | + ); | |
| 630 | 772 | foreach ( $table_keys as $table_key ) : |
| 631 | 773 | if ( ! isset( $statuses[ $table_key ] ) ) { |
| 632 | 774 | continue; |
| 633 | 775 | } |
| @@ -638,13 +780,11 @@ | ||
| 638 | 780 | <?php |
| 639 | 781 | echo $statuses[ $table_key ]; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 640 | 782 | |
| 641 | 783 | if ( isset( $table_stats[ $table_key ] ) ) { |
| 642 | - $format = ( is_multisite() && ! is_network_admin() ) | |
| 643 | - /* translators: 1: Number of entries, 2: Estimated table size */ | |
| 644 | - ? __( 'Entries: %1$s | Est. Size: %2$s', 'top-10' ) | |
| 645 | - /* translators: 1: Number of entries, 2: Table size */ | |
| 646 | - : __( 'Entries: %1$s | Size: %2$s', 'top-10' ); | |
| 784 | + $format = is_multisite() | |
| 785 | + ? __( 'Network-wide estimated entries: %1$s | Network-wide estimated size: %2$s', 'top-10' ) | |
| 786 | + : __( 'Estimated entries: %1$s | Estimated size: %2$s', 'top-10' ); | |
| 647 | 787 | |
| 648 | 788 | echo '<br><span class="description">'; |
| 649 | 789 | printf( |
| 650 | 790 | esc_html( $format ), |
| @@ -716,13 +856,13 @@ | ||
| 716 | 856 | </td> |
| 717 | 857 | </tr> |
| 718 | 858 | <?php endforeach; ?> |
| 719 | 859 | |
| 720 | - <?php if ( ! Database::are_tables_installed() ) : ?> | |
| 860 | + <?php if ( ( ! is_multisite() || is_network_admin() ) && ! Database::are_tables_installed() ) : ?> | |
| 721 | 861 | <tr> |
| 722 | 862 | <th scope="row"><?php esc_html_e( 'Repair database', 'top-10' ); ?></th> |
| 723 | 863 | <td> |
| 724 | - <a href="<?php echo esc_url( wp_nonce_url( admin_url( 'admin.php?page=tptn_dashboard&action=recreate_tables' ), 'tptn-recreate-tables' ) ); ?>" class="button"> | |
| 864 | + <a href="<?php echo esc_url( wp_nonce_url( ( is_multisite() && is_network_admin() ? network_admin_url( 'admin.php?page=tptn_network_tools_page&action=recreate_tables' ) : admin_url( 'admin.php?page=tptn_tools_page&action=recreate_tables' ) ), 'tptn-recreate-tables' ) ); ?>" class="button"> | |
| 725 | 865 | <?php esc_html_e( 'Recreate tables', 'top-10' ); ?> |
| 726 | 866 | </a> |
| 727 | 867 | </td> |
| 728 | 868 | </tr> |
| @@ -751,18 +891,25 @@ | ||
| 751 | 891 | if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'tptn-create-missing-tables' ) ) { |
| 752 | 892 | wp_die( esc_html__( 'Security check failed', 'top-10' ) ); |
| 753 | 893 | } |
| 754 | 894 | |
| 755 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 895 | + if ( is_multisite() && ! is_network_admin() ) { | |
| 896 | + wp_die( esc_html__( 'Database table repair must be run from Network Admin.', 'top-10' ) ); | |
| 897 | + } | |
| 898 | + | |
| 899 | + $capability = is_network_admin() ? 'manage_network_options' : 'manage_options'; | |
| 900 | + if ( ! current_user_can( $capability ) ) { | |
| 756 | 901 | wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'top-10' ) ); |
| 757 | 902 | } |
| 758 | 903 | |
| 759 | 904 | Activator::create_tables(); |
| 760 | 905 | Database::clear_table_statistics_cache(); |
| 906 | + Dashboard_Widgets::clear_network_dashboard_cache(); | |
| 907 | + $table_statuses = Database::get_table_installation_status( true ); | |
| 761 | 908 | |
| 762 | 909 | $still_missing = false; |
| 763 | - foreach ( array( Database::get_table( false ), Database::get_table( true ), Database::get_log_table(), Database::get_funnel_table() ) as $table ) { | |
| 764 | - if ( ! Database::is_table_installed( $table ) ) { | |
| 910 | + foreach ( $table_statuses as $installed ) { | |
| 911 | + if ( ! $installed ) { | |
| 765 | 912 | $still_missing = true; |
| 766 | 913 | break; |
| 767 | 914 | } |
| 768 | 915 | } |
| @@ -768,9 +915,9 @@ | ||
| 768 | 915 | } |
| 769 | 916 | |
| 770 | 917 | $status = $still_missing ? 'failed' : 'created'; |
| 771 | 918 | $referer = wp_get_referer(); |
| 772 | - $fallback = admin_url( 'admin.php?page=' . ( is_network_admin() ? 'tptn_network_tools_page' : 'tptn_tools_page' ) ); | |
| 919 | + $fallback = is_network_admin() ? network_admin_url( 'admin.php?page=tptn_network_tools_page' ) : admin_url( 'admin.php?page=tptn_tools_page' ); | |
| 773 | 920 | $redirect = add_query_arg( 'tptn_tables_created', $status, $referer ? $referer : $fallback ); |
| 774 | 921 | |
| 775 | 922 | wp_safe_redirect( $redirect ); |
| 776 | 923 | exit; |
| @@ -789,9 +936,14 @@ | ||
| 789 | 936 | if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'tptn-recreate-tables' ) ) { |
| 790 | 937 | wp_die( esc_html__( 'Security check failed', 'top-10' ) ); |
| 791 | 938 | } |
| 792 | 939 | |
| 793 | - if ( ! current_user_can( 'manage_options' ) ) { | |
| 940 | + if ( is_multisite() && ! is_network_admin() ) { | |
| 941 | + wp_die( esc_html__( 'Database table repair must be run from Network Admin.', 'top-10' ) ); | |
| 942 | + } | |
| 943 | + | |
| 944 | + $capability = is_network_admin() ? 'manage_network_options' : 'manage_options'; | |
| 945 | + if ( ! current_user_can( $capability ) ) { | |
| 794 | 946 | wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'top-10' ) ); |
| 795 | 947 | } |
| 796 | 948 | |
| 797 | 949 | // Recreate tables. |
| @@ -798,8 +950,10 @@ | ||
| 798 | 950 | $result_overall = Database::recreate_overall_table( false ); |
| 799 | 951 | $result_daily = Database::recreate_daily_table( false ); |
| 800 | 952 | $result_funnel = Database::recreate_funnel_table( false ); |
| 801 | 953 | $result_log = Database::recreate_log_table( false ); |
| 954 | + Database::clear_table_installation_cache(); | |
| 955 | + Dashboard_Widgets::clear_network_dashboard_cache(); | |
| 802 | 956 | |
| 803 | 957 | // Check for errors. |
| 804 | 958 | if ( is_wp_error( $result_overall ) ) { |
| 805 | 959 | add_settings_error( |
| @@ -850,9 +1004,12 @@ | ||
| 850 | 1004 | Database::clear_table_statistics_cache(); |
| 851 | 1005 | } |
| 852 | 1006 | |
| 853 | 1007 | // Redirect back to the tools page. |
| 854 | - $page = is_network_admin() ? 'tptn_network_tools_page' : 'tptn_tools_page'; | |
| 855 | - wp_safe_redirect( admin_url( 'admin.php?page=' . $page . '&settings-updated=true' ) ); | |
| 1008 | + if ( is_network_admin() ) { | |
| 1009 | + wp_safe_redirect( network_admin_url( 'admin.php?page=tptn_network_tools_page&settings-updated=true' ) ); | |
| 1010 | + } else { | |
| 1011 | + wp_safe_redirect( admin_url( 'admin.php?page=tptn_tools_page&settings-updated=true' ) ); | |
| 1012 | + } | |
| 856 | 1013 | exit; |
| 857 | 1014 | } |
| 858 | 1015 | } |