PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.2
WebberZone Top 10 — Popular Posts v4.5.2
4.5.2 4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 All 118 releases
← All changes | includes/admin/class-tools-page.php +221 -64 4.4.1 → 4.5.2 View file →
@@ -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">
@@ -353,9 +408,9 @@
353 408
354 409 $table_name = Database::get_table( false );
355 410 $table_name_daily = Database::get_table( true );
356 411
357 - $wpdb->hide_errors();
412 + $show_errors = $wpdb->hide_errors();
358 413
359 414 if ( $wpdb->query( $wpdb->prepare( "SHOW INDEXES FROM {$table_name} WHERE Key_name = %s", 'PRIMARY' ) ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
360 415 $wpdb->query( 'ALTER TABLE ' . $table_name . ' DROP PRIMARY KEY ' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange
361 416 }
@@ -369,9 +424,9 @@
369 424 $wpdb->query( 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY(postnumber, blog_id) ' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange
370 425 $wpdb->query( 'ALTER TABLE ' . $table_name_daily . ' ADD PRIMARY KEY(postnumber, dp_date, blog_id) ' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange
371 426 $wpdb->query( 'ALTER TABLE ' . $table_name_daily . ' ADD INDEX blog_date(blog_id, dp_date, postnumber)' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.SchemaChange
372 427
373 - $wpdb->show_errors();
428 + $wpdb->show_errors( $show_errors );
374 429 }
375 430
376 431 /**
377 432 * Retrieves the SQL code to recreate the PRIMARY KEY.
@@ -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 }