PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
← All changes | includes/class-wp-optimizer.php +382 -54 3.3.1 → 4.7.0 View file →
@@ -1,14 +1,42 @@
1 1 <?php
2 2
3 -if (!defined('WPO_VERSION')) die('No direct access allowed');
3 +if (!defined('ABSPATH')) die('No direct access allowed');
4 4
5 5 /**
6 - * This class invokes optimiazations. The optimizations themselves live in the 'optimizations' sub-directory of the plugin. The proper way to obtain access to the instance is via WP_Optimize()->get_optimizer()
6 + * This class invokes optimiazations. The optimizations themselves live in the 'optimizations' subdirectory of the plugin. The proper way to obtain access to the instance is via WP_Optimize()->get_optimizer()
7 7 */
8 8 class WP_Optimizer {
9 9
10 10 /**
11 + * Table count limit to consider as too many tables to load in a single request
12 + *
13 + * @var int
14 + */
15 + const HIGH_TABLE_COUNT_THRESHOLD = 150;
16 +
17 + /**
18 + * Option name to store all the status information for the tables
19 + *
20 + * @var string
21 + */
22 + const TABLES_LIST_OPTION_NAME = 'all-tables-status';
23 +
24 + /**
25 + * Option name to save the state of the table scan
26 + *
27 + * @var string
28 + */
29 + const TABLES_LIST_STATE_OPTION_NAME = 'all-tables-names-scan-status';
30 +
31 + /**
32 + * Option name to save the total table count
33 + *
34 + * @var string
35 + */
36 + const TABLES_LIST_COUNT_OPTION_NAME = 'all-tables-names-count';
37 +
38 + /**
11 39 * Returns singleton instance object
12 40 *
13 41 * @return WP_Optimizer Returns `WP_Optimizer` object
14 42 */
@@ -18,9 +46,14 @@
18 46 $_instance = new self();
19 47 }
20 48 return $_instance;
21 49 }
22 -
50 +
51 + /**
52 + * Gets retention information
53 + *
54 + * @return array
55 + */
23 56 public function get_retain_info() {
24 57
25 58 $options = WP_Optimize()->get_options();
26 59
@@ -43,8 +76,13 @@
43 76
44 77 return array($revisions_retention_enabled, $revisions_retention_count);
45 78 }
46 79
80 + /**
81 + * Gets a list of optimizations
82 + *
83 + * @return array
84 + */
47 85 public function get_optimizations_list() {
48 86
49 87 $optimizations = array();
50 88
@@ -51,16 +89,16 @@
51 89 $optimizations_dir = WPO_PLUGIN_MAIN_PATH.'optimizations';
52 90
53 91 if ($dh = opendir($optimizations_dir)) {
54 92 while (($file = readdir($dh)) !== false) {
55 - if ('.' == $file || '..' == $file || '.php' != substr($file, -4, 4) || !is_file($optimizations_dir.'/'.$file) || 'inactive-' == substr($file, 0, 9)) continue;
93 + if ('.' === $file || '..' === $file || '.php' !== substr($file, -4, 4) || !is_file($optimizations_dir.'/'.$file) || 'inactive-' === substr($file, 0, 9)) continue;
56 94 $optimizations[] = substr($file, 0, (strlen($file) - 4));
57 95 }
58 96 closedir($dh);
59 97 }
60 98
61 - return apply_filters('wp_optimize_get_optimizations_list', $optimizations);
62 -
99 + $filtered_optimizations = apply_filters('wp_optimize_get_optimizations_list', $optimizations);
100 + return is_array($filtered_optimizations) ? $filtered_optimizations : $optimizations;
63 101 }
64 102
65 103 /**
66 104 * Currently, there is only one sort rule (so, the parameter's value is ignored)
@@ -70,9 +108,9 @@
70 108 *
71 109 * @return array
72 110 */
73 111 public function sort_optimizations($optimizations, $sort_on = 'ui_sort_order') {
74 - if ('run_sort_order' == $sort_on) {
112 + if ('run_sort_order' === $sort_on) {
75 113 uasort($optimizations, array($this, 'sort_optimizations_run_traditional'));
76 114 } else {
77 115 uasort($optimizations, array($this, 'sort_optimizations_ui_traditional'));
78 116 }
@@ -78,28 +116,45 @@
78 116 }
79 117 return $optimizations;
80 118 }
81 119
120 + /**
121 + * Sorts optimizations based on UI order
122 + *
123 + * @param WP_Optimization $a
124 + * @param WP_Optimization $b
125 + * @return int
126 + */
82 127 public function sort_optimizations_ui_traditional($a, $b) {
83 - return $this->sort_optimizations_traditional($a, $b, 'ui_sort_order');
128 + return $this->sort_optimizations_traditional($a, $b);
84 129 }
85 130
131 + /**
132 + * Sorts optimizations based on Run order
133 + *
134 + * @param WP_Optimization $a
135 + * @param WP_Optimization $b
136 + * @return int
137 + */
86 138 public function sort_optimizations_run_traditional($a, $b) {
87 139 return $this->sort_optimizations_traditional($a, $b, 'run_sort_order');
88 140 }
89 141
142 + /**
143 + * Sorting list of optimization based on given order
144 + *
145 + * @param WP_Optimization $a
146 + * @param WP_Optimization $b
147 + * @param string $sort_on
148 + * @return int
149 + */
90 150 public function sort_optimizations_traditional($a, $b, $sort_on = 'ui_sort_order') {
91 -
92 - if (!is_a($a, 'WP_Optimization')) return (!is_a($b, 'WP_Optimization')) ? 0 : 1;
93 - if (!is_a($b, 'WP_Optimization')) return -1;
94 -
95 151 $sort_order_a = empty($a->$sort_on) ? 0 : $a->$sort_on;
96 152 $sort_order_b = empty($b->$sort_on) ? 0 : $b->$sort_on;
97 153
98 - if ($sort_order_a == $sort_order_b) return 0;
154 + if ($sort_order_a === $sort_order_b) return 0;
99 155
100 - return ($sort_order_a < $sort_order_b) ? (-1) : 1;
101 -
156 + return ($sort_order_a < $sort_order_b) ? -1 : 1;
102 157 }
103 158
104 159 /**
105 160 * This method returns an array of available optimizations.
@@ -105,9 +160,9 @@
105 160 * This method returns an array of available optimizations.
106 161 * Each array key is an optimization ID, and the value is an object,
107 162 * as returned by get_optimization()
108 163 *
109 - * @return [array] array of optimizations or WP_Error objects
164 + * @return array array of optimizations
110 165 */
111 166 public function get_optimizations() {
112 167
113 168 $optimizations = $this->get_optimizations_list();
@@ -122,9 +177,10 @@
122 177 $optimization_objects[$optimization] = $optimization_object;
123 178 }
124 179 }
125 180
126 - return apply_filters('wp_optimize_get_optimizations', $optimization_objects);
181 + $filtered_optimizations = apply_filters('wp_optimize_get_optimizations', $optimization_objects);
182 + return is_array($filtered_optimizations) ? $filtered_optimizations : $optimization_objects;
127 183
128 184 }
129 185
130 186 /**
@@ -129,11 +185,11 @@
129 185
130 186 /**
131 187 * This method returns an object for a specific optimization.
132 188 *
133 - * @param string $which_optimization An optimization ID.
134 - * @param array $data An array of anny options $data.
135 - * @return array WP_Error Will return the optimization, or a WP_Error object if it was not found.
189 + * @param string|object $which_optimization An optimization ID.
190 + * @param array $data An array of anny options $data.
191 + * @return array|WP_Error WP_Error Will return the optimization, or a WP_Error object if it was not found.
136 192 */
137 193 public function get_optimization($which_optimization, $data = array()) {
138 194
139 195 $optimization_class = apply_filters('wp_optimize_optimization_class', 'WP_Optimization_'.$which_optimization);
@@ -169,9 +225,9 @@
169 225 /**
170 226 * The method to call to perform an optimization.
171 227 *
172 228 * @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
173 - * @return array Array of results from the optimization.
229 + * @return object Array of results from the optimization.
174 230 */
175 231 public function do_optimization($which_optimization) {
176 232
177 233 $optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
@@ -237,9 +293,8 @@
237 293 $optimization->get_info();
238 294 }
239 295
240 296 $optimization->after_get_info();
241 -
242 297 return $optimization->get_results();
243 298 }
244 299
245 300 /**
@@ -253,9 +308,11 @@
253 308
254 309 $results = array();
255 310
256 311 if (empty($optimization_options)) return $results;
257 -
312 +
313 + $this->snapshot_cleaned_before_run();
314 +
258 315 $optimizations = $this->sort_optimizations($this->get_optimizations(), 'run_sort_order');
259 316
260 317 foreach ($optimizations as $optimization_id => $optimization) {
261 318 $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
@@ -261,11 +318,11 @@
261 318 $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
262 319
263 320 if (isset($optimization_options[$option_id])) {
264 321 // if options saved as a string then compare with string (for support different versions)
265 - if (is_string($optimization_options[$option_id]) && 'false' === $optimization_options[$option_id]) continue;
322 + if ('false' === $optimization_options[$option_id]) continue;
266 323
267 - if ('auto' == $which_option && empty($optimization->available_for_auto)) continue;
324 + if ('auto' === $which_option && empty($optimization->available_for_auto)) continue;
268 325
269 326 WP_Optimize()->change_time_limit();
270 327
271 328 $results[$optimization_id] = $this->do_optimization($optimization);
@@ -271,8 +328,9 @@
271 328 $results[$optimization_id] = $this->do_optimization($optimization);
272 329 }
273 330 }
274 331
332 + $this->save_last_run_cleaned();
275 333 // Run action after all optimizations completed.
276 334 do_action('wp_optimize_after_optimizations');
277 335
278 336 return $results;
@@ -277,13 +335,33 @@
277 335
278 336 return $results;
279 337
280 338 }
339 +
340 + /**
341 + * Saves a snapshot of total-cleaned before a run so the per-run diff can be computed afterwards.
342 + */
343 + public function snapshot_cleaned_before_run() {
344 + $options = WP_Optimize()->get_options();
345 + $options->update_option('wpo_last_run_cleaned_snapshot', $options->get_option('total-cleaned', '0'));
346 + }
347 +
348 + /**
349 + * Computes bytes cleaned in the last run (current total minus pre-run snapshot)
350 + * and persists it as last-run-cleaned-bytes.
351 + */
352 + public function save_last_run_cleaned() {
353 + $options = WP_Optimize()->get_options();
354 + $snapshot = floatval($options->get_option('wpo_last_run_cleaned_snapshot', '0'));
355 + $now = floatval($options->get_option('total-cleaned', '0'));
356 + $last_run_bytes = strval(max(0, $now - $snapshot));
357 + $options->update_option('last-run-cleaned-bytes', $last_run_bytes);
358 + }
281 359
282 360 public function get_table_prefix($allow_override = false) {
283 361 $wpdb = $GLOBALS['wpdb'];
284 362 if (is_multisite() && !defined('MULTISITE')) {
285 - // In this case (which should only be possible on installs upgraded from pre WP 3.0 WPMU), $wpdb->get_blog_prefix() cannot be made to return the right thing. $wpdb->base_prefix is not explicitly marked as public, so we prefer to use get_blog_prefix if we can, for future compatibility.
363 + // In this case (which should only be possible on installations upgraded from pre WP 3.0 WPMU), $wpdb->get_blog_prefix() cannot be made to return the right thing. $wpdb->base_prefix is not explicitly marked as public, so we prefer to use get_blog_prefix if we can, for future compatibility.
286 364 $prefix = $wpdb->base_prefix;
287 365 } else {
288 366 $prefix = $wpdb->get_blog_prefix(0);
289 367 }
@@ -290,8 +368,60 @@
290 368 return ($allow_override) ? apply_filters('wp_optimize_get_table_prefix', $prefix) : $prefix;
291 369 }
292 370
293 371 /**
372 + * Verify if the number of tables in the database is too large
373 + *
374 + * @param int $total_table_count Passed by reference. Will carry the actual count value
375 + * @return bool
376 + */
377 + public function is_table_count_too_high(&$total_table_count = null) {
378 + $wpo_db_info = WP_Optimize()->get_db_info();
379 + $table_prefix = $this->get_table_prefix();
380 +
381 + $total_table_count = $wpo_db_info->get_table_count($table_prefix);
382 + return self::HIGH_TABLE_COUNT_THRESHOLD < $total_table_count;
383 + }
384 +
385 + /**
386 + * Check the scan job state in options
387 + *
388 + * @return bool
389 + */
390 + public function is_large_table_count_scan_complete() {
391 + $options = WP_Optimize()->get_options();
392 +
393 + $state = $options->get_option(self::TABLES_LIST_STATE_OPTION_NAME);
394 +
395 + if (is_array($state) && isset($state['state'])) {
396 + return 'done' == $state['state'];
397 + }
398 +
399 + return false;
400 + }
401 +
402 + /**
403 + * Get the status for all scanned tables
404 + *
405 + * @return array
406 + */
407 + private function get_table_status_from_options() {
408 + $options = WP_Optimize()->get_options();
409 + $tables = $options->get_option(WP_Optimizer::TABLES_LIST_OPTION_NAME);
410 + return is_array($tables) ? $tables : array();
411 + }
412 +
413 + /**
414 + * Get the count of the already scanned tables
415 + *
416 + * @return int
417 + */
418 + public function get_table_status_count() {
419 + $statuses = $this->get_table_status_from_options();
420 + return is_array($statuses) ? count($statuses) : 0;
421 + }
422 +
423 + /**
294 424 * Returns information about database tables.
295 425 *
296 426 * @param bool $update refresh or no cached data
297 427 *
@@ -303,10 +433,18 @@
303 433 if (false === $update && null !== $tables_info) return $tables_info;
304 434
305 435 $wpo_db_info = WP_Optimize()->get_db_info();
306 436
307 - $table_status = $wpo_db_info->get_show_table_status($update);
437 + $too_many_tables = $this->is_table_count_too_high();
438 + $scan_complete = $this->is_large_table_count_scan_complete();
308 439
440 + $table_status = array();
441 + if (!$too_many_tables) {
442 + $table_status = $wpo_db_info->get_show_table_status($update);
443 + } elseif ($scan_complete) {
444 + $table_status = $this->get_table_status_from_options();
445 + }
446 +
309 447 // Filter on the site's DB prefix (was not done in releases up to 1.9.1).
310 448 $table_prefix = $this->get_table_prefix();
311 449
312 450 if (is_array($table_status)) {
@@ -311,8 +449,9 @@
311 449
312 450 if (is_array($table_status)) {
313 451
314 452 $corrupted_tables_count = 0;
453 + $array_index_was_unset = false;
315 454
316 455 foreach ($table_status as $index => $table) {
317 456 $table_name = $table->Name;
318 457
@@ -321,17 +460,23 @@
321 460 $include_table = apply_filters('wp_optimize_get_tables_include_table', $include_table, $table_name, $table_prefix);
322 461
323 462 if (!$include_table && '' !== $table_prefix) {
324 463 unset($table_status[$index]);
464 + $array_index_was_unset = true;
325 465 continue;
326 466 }
327 467
328 - $table_status[$index]->Engine = $wpo_db_info->get_table_type($table_name);
468 + // Pass the already-fetched $table object through so these lookups don't have to
469 + // re-search for it by name again (that search is O(n), and doing it here for every
470 + // table turns the whole loop into O(n^2) on sites with a large table count).
471 + $table_type = $wpo_db_info->get_table_type($table_name, $table);
329 472
330 - $table_status[$index]->is_optimizable = $wpo_db_info->is_table_optimizable($table_name);
331 - $table_status[$index]->is_type_supported = $wpo_db_info->is_table_type_optimize_supported($table_name);
473 + $table_status[$index]->Engine = $table_type;
474 +
475 + $table_status[$index]->is_optimizable = $wpo_db_info->is_table_optimizable($table_name, $table_type);
476 + $table_status[$index]->is_type_supported = $wpo_db_info->is_table_type_optimize_supported($table_name, $table_type);
332 477 // add information about corrupted tables.
333 - $is_needing_repair = $wpo_db_info->is_table_needing_repair($table_name);
478 + $is_needing_repair = $wpo_db_info->is_table_needing_repair($table_name, $table_type);
334 479 $table_status[$index]->is_needing_repair = $is_needing_repair;
335 480 if ($is_needing_repair) $corrupted_tables_count++;
336 481
337 482 $table_status[$index] = $this->join_plugin_information($table_name, $table_status[$index]);
@@ -337,8 +482,12 @@
337 482 $table_status[$index] = $this->join_plugin_information($table_name, $table_status[$index]);
338 483
339 484 $table_status[$index]->blog_id = $wpo_db_info->get_table_blog_id($table_name);
340 485 }
486 + if ($array_index_was_unset) {
487 + // Reset array keys after removing elements
488 + $table_status = array_values($table_status);
489 + }
341 490
342 491 WP_Optimize()->get_options()->update_option('corrupted-tables-count', $corrupted_tables_count);
343 492 }
344 493
@@ -348,10 +497,10 @@
348 497
349 498 /**
350 499 * Returns information about single table by table name.
351 500 *
352 - * @param String $table_name table name
353 - * @return Object|Boolean table information object.
501 + * @param string $table_name table name
502 + * @return object|boolean table information object.
354 503 */
355 504 public function get_table($table_name) {
356 505
357 506 $db_info = WP_Optimize()->get_db_info();
@@ -373,14 +522,14 @@
373 522
374 523 /**
375 524 * Add information about relationship database tables with plugins.
376 525 *
377 - * @param {string} $table_name
378 - * @param {object} $table_obj
526 + * @param string $table_name
527 + * @param object $table_obj
379 528 *
380 - * @return {object}
529 + * @return object
381 530 */
382 - public function join_plugin_information($table_name, $table_obj) {
531 + private function join_plugin_information($table_name, $table_obj) {
383 532 // set can be removed flag.
384 533 $can_be_removed = false;
385 534 // set WP core table flag.
386 535 $wp_core_table = false;
@@ -385,22 +534,29 @@
385 534 // set WP core table flag.
386 535 $wp_core_table = false;
387 536 // set WP actionscheduler table flag.
388 537 $wp_actionscheduler_table = (false !== stripos($table_name, 'actionscheduler_'));
389 - // add information about using table by any of installed plugins.
390 - $table_obj->is_using = WP_Optimize()->get_db_info()->is_table_using_by_plugin($table_name);
391 538 // if table belongs to any plugin then add plugins status.
392 539 $plugins = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
393 540
541 + if (false === $plugins) {
542 + // if we can't determine which plugin use $table then mark table as used.
543 + $table_obj->is_using = true;
544 + } else {
545 + // if any plugin is installed which use table - $table_name then mark table as used.
546 + $table_obj->is_using = WP_Optimize()->get_db_info()->is_any_plugin_installed($plugins);
547 + }
548 +
549 + $plugin_status = array();
550 +
394 551 if (false !== $plugins) {
395 552 // if belongs to any of plugin then we can remove table if plugin not active.
396 553 $can_be_removed = true;
397 554
398 - $plugin_status = array();
399 555 foreach ($plugins as $plugin) {
400 556 $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin);
401 557
402 - if (__('WordPress core', 'wp-optimize') == $plugin) $wp_core_table = true;
558 + if (__('WordPress core', 'wp-optimize') === $plugin) $wp_core_table = true;
403 559 // if plugin is active then we can't remove.
404 560 if ($wp_core_table || $status['active'] || $wp_actionscheduler_table) $can_be_removed = false;
405 561
406 562 if ($status['installed'] || $status['active'] || !$table_obj->is_using) {
@@ -409,12 +565,11 @@
409 565 'status' => $status,
410 566 );
411 567 }
412 568 }
413 -
414 - $table_obj->plugin_status = $plugin_status;
415 569 }
416 570
571 + $table_obj->plugin_status = $plugin_status;
417 572 $table_obj->wp_core_table = $wp_core_table;
418 573 $table_obj->can_be_removed = $can_be_removed;
419 574
420 575 return $table_obj;
@@ -426,9 +581,9 @@
426 581 * the results to optimizations-table.php and optimizationstable.php
427 582 *
428 583 * @param int $blog_id filter tables by prefix
429 584 *
430 - * @return Array - an array of data such as table list, innodb info and data free
585 + * @return array - an array of data such as table list, innodb info and data free
431 586 */
432 587 public function get_table_information($blog_id = 0) {
433 588 // Get table information.
434 589 $tablesstatus = $this->get_tables();
@@ -440,12 +595,20 @@
440 595 $table_information['non_inno_db_tables'] = 0;
441 596 $table_information['table_list'] = '';
442 597 $table_information['is_optimizable'] = true;
443 598
599 + // When too many tables exist and the batch scan hasn't completed yet, get_tables() returns an empty array.
600 + // Fall back to a lightweight COUNT query so the UI shows the real table count instead of zero.
601 + if (empty($tablesstatus) && $this->is_table_count_too_high() && !$this->is_large_table_count_scan_complete()) {
602 + $prefix = $this->get_table_prefix();
603 + $table_information['non_inno_db_tables'] = (int) WP_Optimize()->get_db_info()->get_table_count($prefix);
604 + return $table_information;
605 + }
606 +
444 607 // Make a list of tables to optimize.
445 608 foreach ($tablesstatus as $each_table) {
446 609 // if $blog_id is set then filter tables
447 - if ($blog_id > 0 && $blog_id != $each_table->blog_id) continue;
610 + if ($blog_id > 0 && $blog_id !== $each_table->blog_id) continue;
448 611
449 612 $table_information['table_list'] .= $each_table->Name.'|';
450 613
451 614 // check if table type supported.
@@ -459,9 +622,9 @@
459 622 // calculate total gain value.
460 623 $table_information['total_gain'] += $each_table->Data_free;
461 624
462 625 // count InnoDB tables.
463 - if ('InnoDB' == $each_table->Engine) {
626 + if ('InnoDB' === $each_table->Engine) {
464 627 $table_information['inno_db_tables']++;
465 628 } else {
466 629 $table_information['non_inno_db_tables']++;
467 630 }
@@ -484,15 +647,27 @@
484 647 $new_status = $enable ? 'open' : 'closed';
485 648
486 649 switch ($type) {
487 650 case "trackbacks":
488 - $thissql = "UPDATE `".$wpdb->posts."` SET ping_status='".$new_status."' WHERE post_status = 'publish' AND post_type = 'post';";
489 - $wpdb->query($thissql);
651 + $wpdb->query(
652 + $wpdb->prepare(
653 + "UPDATE `{$wpdb->posts}` SET ping_status = %s WHERE post_status = %s AND post_type = %s",
654 + $new_status,
655 + 'publish',
656 + 'post'
657 + )
658 + );
490 659 break;
491 660
492 661 case "comments":
493 - $thissql = "UPDATE `".$wpdb->posts."` SET comment_status='".$new_status."' WHERE post_status = 'publish' AND post_type = 'post';";
494 - $wpdb->query($thissql);
662 + $wpdb->query(
663 + $wpdb->prepare(
664 + "UPDATE `{$wpdb->posts}` SET comment_status = %s WHERE post_status = %s AND post_type = %s",
665 + $new_status,
666 + 'publish',
667 + 'post'
668 + )
669 + );
495 670 break;
496 671
497 672 default:
498 673 break;
@@ -503,10 +678,10 @@
503 678
504 679 /**
505 680 * This function will return total database size and a possible gain of db in KB.
506 681 *
507 - * @param boolean $update - Wether to update the values or not
508 - * @return string total db size gained.
682 + * @param boolean $update - Whether to update the values or not
683 + * @return array total db size gained.
509 684 */
510 685 public function get_current_db_size($update = false) {
511 686
512 687 if (!$update && $db_size = get_transient('wpo_get_current_db_size')) {
@@ -529,9 +704,9 @@
529 704 $total_gain += $tablestatus->Data_free;
530 705 $data_usage += $tablestatus->Data_length;
531 706 $index_usage += $tablestatus->Index_length;
532 707
533 - if ('InnoDB' != $tablestatus->Engine) {
708 + if ('InnoDB' !== $tablestatus->Engine) {
534 709 $overhead_usage += $tablestatus->Data_free;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage declared up above
535 710 $total_gain += $tablestatus->Data_free;
536 711 }
537 712 }
@@ -558,12 +733,27 @@
558 733 $total_now = strval($previously_saved + $converted_current);
559 734
560 735 $options->update_option('total-cleaned', $total_now);
561 736
737 + $previously_saved = floatval($options->get_option('total-cleaned-current-month', '0'));
738 +
739 + $total_now = strval($previously_saved + $converted_current);
740 +
741 + $options->update_option('total-cleaned-current-month', $total_now);
742 +
743 + $previously_saved = floatval($options->get_option('db_bytes_saved', '0'));
744 + $options->update_option('db_bytes_saved', strval($previously_saved + $converted_current));
745 +
562 746 return $total_now;
563 747 }
564 748
565 749
750 + /**
751 + * Trackback, Comments actions
752 + *
753 + * @param array $options
754 + * @return array
755 + */
566 756 public function trackback_comment_actions($options) {
567 757
568 758 $output = array();
569 759 $messages = array();
@@ -571,12 +761,14 @@
571 761 if (isset($options['comments'])) {
572 762 if (!$options['comments']) {
573 763 $this->enable_linkbacks('comments', false);
574 764 $output[] = __('Comments have now been disabled on all current and previously published posts.', 'wp-optimize');
765 + // translators: %s is a date and time
575 766 $messages[] = sprintf(__('All comments on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
576 767 } else {
577 768 $this->enable_linkbacks('comments');
578 769 $output[] = __('Comments have now been enabled on all current and previously published posts.', 'wp-optimize');
770 + // translators: %s is a date and time
579 771 $messages[] = sprintf(__('All comments on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
580 772 }
581 773 }
582 774
@@ -583,12 +775,14 @@
583 775 if (isset($options['trackbacks'])) {
584 776 if (!$options['trackbacks']) {
585 777 $this->enable_linkbacks('trackbacks', false);
586 778 $output[] = __('Trackbacks have now been disabled on all current and previously published posts.', 'wp-optimize');
779 + // translators: %s is a date and time
587 780 $messages[] = sprintf(__('All trackbacks on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
588 781 } else {
589 782 $this->enable_linkbacks('trackbacks');
590 783 $output[] = __('Trackbacks have now been enabled on all current and previously published posts.', 'wp-optimize');
784 + // translators: %s is a date and time
591 785 $messages[] = sprintf(__('All trackbacks on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
592 786 }
593 787 }
594 788
@@ -595,9 +789,9 @@
595 789 return array('output' => $output,'messages' => $messages);
596 790 }
597 791
598 792 /**
599 - * Wether InnoDB tables require confirmation to be optimized
793 + * Whether InnoDB tables require confirmation to be optimized
600 794 *
601 795 * @return boolean
602 796 */
603 797 public function show_innodb_force_optimize() {
@@ -602,6 +796,140 @@
602 796 */
603 797 public function show_innodb_force_optimize() {
604 798 $tablesstatus = $this->get_table_information();
605 799 return false === $tablesstatus['is_optimizable'] && $tablesstatus['inno_db_tables'] > 0;
800 + }
801 +
802 + /**
803 + * Queue handler for this class
804 + *
805 + * @return WP_Optimize_Tasks_Queue
806 + */
807 + private function _tasks_queue() {
808 + return WP_Optimize_Tasks_Queue::this('optimizer');
809 + }
810 +
811 + /**
812 + * Add a batch scan job to the queue
813 + *
814 + * @param int $offset Batch offset
815 + * @return void
816 + */
817 + public function add_load_tables_task($offset) {
818 + $this->_tasks_queue()->add_task(new WP_Optimize_Queue_Task(array(get_class($this), 'load_tables_in_batches'), array('offset' => $offset), '', 1));
819 + }
820 +
821 + /**
822 + * Persist queue tasks in DB
823 + *
824 + * @return void
825 + */
826 + public function flush_tasks() {
827 + $this->_tasks_queue()->flush();
828 + }
829 +
830 + /**
831 + * Run next available task for this queue
832 + *
833 + * @return void
834 + */
835 + public function do_next_load_table_task() {
836 + $this->_tasks_queue()->do_next_task();
837 + }
838 +
839 + /**
840 + * Check if the queue ran all jobs
841 + *
842 + * @return bool
843 + */
844 + public function is_task_queue_empty() {
845 + return $this->_tasks_queue()->is_empty();
846 + }
847 +
848 + /**
849 + * Find tables names and load their status, in sequenced requests so it does not timeout
850 + *
851 + * @param int $offset The pagination offset
852 + * @return void
853 + */
854 + public function load_tables_in_batches($offset) {
855 + global $wpdb;
856 +
857 + $prefix = $wpdb->base_prefix;
858 +
859 + $options = WP_Optimize()->get_options();
860 +
861 + $db_info = WP_Optimize_Database_Information::instance();
862 +
863 + $tables = $options->get_option(WP_Optimizer::TABLES_LIST_OPTION_NAME);
864 + $tables = is_array($tables) ? $tables : array();
865 + $tables_count = $options->get_option(WP_Optimizer::TABLES_LIST_COUNT_OPTION_NAME);
866 + $tables_count = false !== $tables_count ? $tables_count : 0;
867 +
868 + $tables_batch = $db_info->get_tables_names($prefix, $offset, WP_Optimizer::HIGH_TABLE_COUNT_THRESHOLD);
869 +
870 +
871 + foreach ($tables_batch as $table_name) {
872 + $tables[$table_name] = $db_info->get_table_status($table_name);
873 + }
874 +
875 + $options->update_option(WP_Optimizer::TABLES_LIST_OPTION_NAME, $tables, false);
876 +
877 + $done = 0 < count($tables_batch) && count($tables) >= (int) $tables_count;
878 + if (true === $done) {
879 + $options->update_option(WP_Optimizer::TABLES_LIST_STATE_OPTION_NAME, array('state' => 'done'));
880 + }
881 + }
882 +
883 + /**
884 + * Initialize the table scan job
885 + *
886 + * @return int
887 + */
888 + public function scan_job_init() {
889 + global $wpdb;
890 +
891 + $options = WP_Optimize()->get_options();
892 + $db_info = WP_Optimize_Database_Information::instance();
893 +
894 + $this->_tasks_queue()->unlock();
895 + $this->_tasks_queue()->delete_queue();
896 +
897 + $prefix = $wpdb->base_prefix;
898 + $tables_count = $db_info->get_table_count($prefix);
899 + $options->update_option(self::TABLES_LIST_COUNT_OPTION_NAME, $tables_count);
900 + $options->update_option(self::TABLES_LIST_OPTION_NAME, array(), false);
901 + $options->update_option(self::TABLES_LIST_STATE_OPTION_NAME, array(
902 + 'state' => 'working',
903 + 'start' => time()
904 + ));
905 +
906 + return $tables_count;
907 + }
908 +
909 + /**
910 + * Check if all scan is done, or it has been idle for too long
911 + *
912 + * @return bool
913 + */
914 + public function maybe_restart_scan_job() {
915 + if ($this->is_large_table_count_scan_complete()) {
916 + return false;
917 + }
918 +
919 + if ($this->_tasks_queue()->is_empty()) {
920 + return true;
921 + }
922 +
923 + $options = WP_Optimize()->get_options();
924 +
925 + $idle_max_time = HOUR_IN_SECONDS;
926 +
927 + $scan = $options->get_option(self::TABLES_LIST_STATE_OPTION_NAME);
928 +
929 + if (is_array($scan) && isset($scan['start'])) {
930 + return (time() - $scan['start']) > $idle_max_time;
931 + }
932 +
933 + return false;
606 934 }
607 935 }