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
wp-optimize / includes / class-wp-optimizer.php

class-wp-optimizer.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at includes/class-wp-optimizer.php

936 lines 29.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 /**
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 */
8 class WP_Optimizer {
9
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 /**
39 * Returns singleton instance object
40 *
41 * @return WP_Optimizer Returns `WP_Optimizer` object
42 */
43 public static function instance() {
44 static $_instance = null;
45 if (null === $_instance) {
46 $_instance = new self();
47 }
48 return $_instance;
49 }
50
51 /**
52 * Gets retention information
53 *
54 * @return array
55 */
56 public function get_retain_info() {
57
58 $options = WP_Optimize()->get_options();
59
60 $retain_enabled = $options->get_option('retention-enabled', 'false');
61 $retain_period = (($retain_enabled) ? $options->get_option('retention-period', '2') : null);
62
63 return array($retain_enabled, $retain_period);
64 }
65
66 /**
67 * Get data retention options
68 *
69 * @return array
70 */
71 public function get_revisions_retain_info() {
72 $options = WP_Optimize()->get_options();
73
74 $revisions_retention_enabled = $options->get_option('revisions-retention-enabled', 'false');
75 $revisions_retention_count = $revisions_retention_enabled ? $options->get_option('revisions-retention-count', '2') : null;
76
77 return array($revisions_retention_enabled, $revisions_retention_count);
78 }
79
80 /**
81 * Gets a list of optimizations
82 *
83 * @return array
84 */
85 public function get_optimizations_list() {
86
87 $optimizations = array();
88
89 $optimizations_dir = WPO_PLUGIN_MAIN_PATH.'optimizations';
90
91 if ($dh = opendir($optimizations_dir)) {
92 while (($file = readdir($dh)) !== false) {
93 if ('.' === $file || '..' === $file || '.php' !== substr($file, -4, 4) || !is_file($optimizations_dir.'/'.$file) || 'inactive-' === substr($file, 0, 9)) continue;
94 $optimizations[] = substr($file, 0, (strlen($file) - 4));
95 }
96 closedir($dh);
97 }
98
99 $filtered_optimizations = apply_filters('wp_optimize_get_optimizations_list', $optimizations);
100 return is_array($filtered_optimizations) ? $filtered_optimizations : $optimizations;
101 }
102
103 /**
104 * Currently, there is only one sort rule (so, the parameter's value is ignored)
105 *
106 * @param array $optimizations An array of optimizations (i.e. WP_Optimization instances).
107 * @param string $sort_on Specify sort.
108 *
109 * @return array
110 */
111 public function sort_optimizations($optimizations, $sort_on = 'ui_sort_order') {
112 if ('run_sort_order' === $sort_on) {
113 uasort($optimizations, array($this, 'sort_optimizations_run_traditional'));
114 } else {
115 uasort($optimizations, array($this, 'sort_optimizations_ui_traditional'));
116 }
117 return $optimizations;
118 }
119
120 /**
121 * Sorts optimizations based on UI order
122 *
123 * @param WP_Optimization $a
124 * @param WP_Optimization $b
125 * @return int
126 */
127 public function sort_optimizations_ui_traditional($a, $b) {
128 return $this->sort_optimizations_traditional($a, $b);
129 }
130
131 /**
132 * Sorts optimizations based on Run order
133 *
134 * @param WP_Optimization $a
135 * @param WP_Optimization $b
136 * @return int
137 */
138 public function sort_optimizations_run_traditional($a, $b) {
139 return $this->sort_optimizations_traditional($a, $b, 'run_sort_order');
140 }
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 */
150 public function sort_optimizations_traditional($a, $b, $sort_on = 'ui_sort_order') {
151 $sort_order_a = empty($a->$sort_on) ? 0 : $a->$sort_on;
152 $sort_order_b = empty($b->$sort_on) ? 0 : $b->$sort_on;
153
154 if ($sort_order_a === $sort_order_b) return 0;
155
156 return ($sort_order_a < $sort_order_b) ? -1 : 1;
157 }
158
159 /**
160 * This method returns an array of available optimizations.
161 * Each array key is an optimization ID, and the value is an object,
162 * as returned by get_optimization()
163 *
164 * @return array array of optimizations
165 */
166 public function get_optimizations() {
167
168 $optimizations = $this->get_optimizations_list();
169
170 $optimization_objects = array();
171
172 foreach ($optimizations as $optimization) {
173 $optimization_object = $this->get_optimization($optimization);
174 if (is_wp_error($optimization_object)) {
175 WP_Optimize()->log('Failed to load optimization ' . $optimization . ' - ' . $optimization_object->get_error_message());
176 } else {
177 $optimization_objects[$optimization] = $optimization_object;
178 }
179 }
180
181 $filtered_optimizations = apply_filters('wp_optimize_get_optimizations', $optimization_objects);
182 return is_array($filtered_optimizations) ? $filtered_optimizations : $optimization_objects;
183
184 }
185
186 /**
187 * This method returns an object for a specific optimization.
188 *
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.
192 */
193 public function get_optimization($which_optimization, $data = array()) {
194
195 $optimization_class = apply_filters('wp_optimize_optimization_class', 'WP_Optimization_'.$which_optimization);
196
197 if (!class_exists('WP_Optimization')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimization.php');
198
199 if (!class_exists($optimization_class)) {
200 $optimization_file = WPO_PLUGIN_MAIN_PATH.'optimizations/'.$which_optimization.'.php';
201 $class_file = apply_filters('wp_optimize_optimization_class_file', $optimization_file);
202 if (!preg_match('/^[a-z]+$/', $which_optimization) || !file_exists($class_file)) {
203 return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
204 }
205
206 include_once($class_file);
207
208 if (!class_exists($optimization_class)) {
209 return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
210 }
211 }
212
213 // set sites option for Multisite cron job.
214 if (defined('DOING_CRON') && DOING_CRON && is_multisite()) {
215 $options = WP_Optimize()->get_options();
216 $data['optimization_sites'] = $options->get_option('wpo-sites-cron', array('all'));
217 }
218
219 $optimization = new $optimization_class($data);
220
221 return $optimization;
222
223 }
224
225 /**
226 * The method to call to perform an optimization.
227 *
228 * @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
229 * @return object Array of results from the optimization.
230 */
231 public function do_optimization($which_optimization) {
232
233 $optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
234
235 if (is_wp_error($optimization)) {
236 WP_Optimize()->log('Error occurred. Unknown optimization.');
237 return $optimization;
238 }
239
240 WP_Optimize()->change_time_limit();
241
242 $optimization->init();
243
244 if (apply_filters('wp_optimize_do_optimization', true, $which_optimization, $optimization)) {
245
246 $optimization->before_optimize();
247
248 if ($optimization->run_multisite) {
249 foreach ($optimization->blogs_ids as $blog_id) {
250 $optimization->switch_to_blog($blog_id);
251 $optimization->optimize();
252 $optimization->restore_current_blog();
253 }
254 } else {
255 $optimization->optimize();
256 }
257
258 $optimization->after_optimize();
259
260 }
261
262 do_action('wp_optimize_after_optimization', $which_optimization, $optimization);
263
264 $results = $optimization->get_results();
265
266 return $results;
267 }
268
269 /**
270 * The method to call to get information about an optimization.
271 * As with do_optimization, it is somewhat modelled after the template interface
272 *
273 * @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
274 * @return object returns the optimization information
275 */
276 public function get_optimization_info($which_optimization) {
277
278 $optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
279
280 if (is_wp_error($optimization)) return $optimization;
281
282 WP_Optimize()->change_time_limit();
283
284 $optimization->before_get_info();
285
286 if ($optimization->run_multisite) {
287 foreach ($optimization->blogs_ids as $blog_id) {
288 $optimization->switch_to_blog($blog_id);
289 $optimization->get_info();
290 $optimization->restore_current_blog();
291 }
292 } else {
293 $optimization->get_info();
294 }
295
296 $optimization->after_get_info();
297 return $optimization->get_results();
298 }
299
300 /**
301 * This runs the list of optimizations.
302 *
303 * @param array $optimization_options Whether to do an optimization depends on what keys are set (legacy - can be changed hopefully).
304 * @param string $which_option Specify which option.
305 * @return array Returns an array of result objects.
306 */
307 public function do_optimizations($optimization_options, $which_option = 'dom') {
308
309 $results = array();
310
311 if (empty($optimization_options)) return $results;
312
313 $this->snapshot_cleaned_before_run();
314
315 $optimizations = $this->sort_optimizations($this->get_optimizations(), 'run_sort_order');
316
317 foreach ($optimizations as $optimization_id => $optimization) {
318 $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
319
320 if (isset($optimization_options[$option_id])) {
321 // if options saved as a string then compare with string (for support different versions)
322 if ('false' === $optimization_options[$option_id]) continue;
323
324 if ('auto' === $which_option && empty($optimization->available_for_auto)) continue;
325
326 WP_Optimize()->change_time_limit();
327
328 $results[$optimization_id] = $this->do_optimization($optimization);
329 }
330 }
331
332 $this->save_last_run_cleaned();
333 // Run action after all optimizations completed.
334 do_action('wp_optimize_after_optimizations');
335
336 return $results;
337
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 }
359
360 public function get_table_prefix($allow_override = false) {
361 $wpdb = $GLOBALS['wpdb'];
362 if (is_multisite() && !defined('MULTISITE')) {
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.
364 $prefix = $wpdb->base_prefix;
365 } else {
366 $prefix = $wpdb->get_blog_prefix(0);
367 }
368 return ($allow_override) ? apply_filters('wp_optimize_get_table_prefix', $prefix) : $prefix;
369 }
370
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 /**
424 * Returns information about database tables.
425 *
426 * @param bool $update refresh or no cached data
427 *
428 * @return mixed
429 */
430 public function get_tables($update = false) {
431 static $tables_info = null;
432
433 if (false === $update && null !== $tables_info) return $tables_info;
434
435 $wpo_db_info = WP_Optimize()->get_db_info();
436
437 $too_many_tables = $this->is_table_count_too_high();
438 $scan_complete = $this->is_large_table_count_scan_complete();
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
447 // Filter on the site's DB prefix (was not done in releases up to 1.9.1).
448 $table_prefix = $this->get_table_prefix();
449
450 if (is_array($table_status)) {
451
452 $corrupted_tables_count = 0;
453 $array_index_was_unset = false;
454
455 foreach ($table_status as $index => $table) {
456 $table_name = $table->Name;
457
458 $include_table = (0 === stripos($table_name, $table_prefix));
459
460 $include_table = apply_filters('wp_optimize_get_tables_include_table', $include_table, $table_name, $table_prefix);
461
462 if (!$include_table && '' !== $table_prefix) {
463 unset($table_status[$index]);
464 $array_index_was_unset = true;
465 continue;
466 }
467
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);
472
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);
477 // add information about corrupted tables.
478 $is_needing_repair = $wpo_db_info->is_table_needing_repair($table_name, $table_type);
479 $table_status[$index]->is_needing_repair = $is_needing_repair;
480 if ($is_needing_repair) $corrupted_tables_count++;
481
482 $table_status[$index] = $this->join_plugin_information($table_name, $table_status[$index]);
483
484 $table_status[$index]->blog_id = $wpo_db_info->get_table_blog_id($table_name);
485 }
486 if ($array_index_was_unset) {
487 // Reset array keys after removing elements
488 $table_status = array_values($table_status);
489 }
490
491 WP_Optimize()->get_options()->update_option('corrupted-tables-count', $corrupted_tables_count);
492 }
493
494 $tables_info = apply_filters('wp_optimize_get_tables', $table_status);
495 return $tables_info;
496 }
497
498 /**
499 * Returns information about single table by table name.
500 *
501 * @param string $table_name table name
502 * @return object|boolean table information object.
503 */
504 public function get_table($table_name) {
505
506 $db_info = WP_Optimize()->get_db_info();
507
508 $table = $db_info->get_table_status($table_name);
509
510 if (false === $table) return false;
511
512 $table->is_optimizable = $db_info->is_table_optimizable($table_name);
513 $table->is_type_supported = $db_info->is_table_type_optimize_supported($table_name);
514 $table->is_needing_repair = $db_info->is_table_needing_repair($table_name);
515
516 // add information about plugins.
517 $table = $this->join_plugin_information($table_name, $table);
518
519 $table = apply_filters('wp_optimize_get_table', $table);
520 return $table;
521 }
522
523 /**
524 * Add information about relationship database tables with plugins.
525 *
526 * @param string $table_name
527 * @param object $table_obj
528 *
529 * @return object
530 */
531 private function join_plugin_information($table_name, $table_obj) {
532 // set can be removed flag.
533 $can_be_removed = false;
534 // set WP core table flag.
535 $wp_core_table = false;
536 // set WP actionscheduler table flag.
537 $wp_actionscheduler_table = (false !== stripos($table_name, 'actionscheduler_'));
538 // if table belongs to any plugin then add plugins status.
539 $plugins = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
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
551 if (false !== $plugins) {
552 // if belongs to any of plugin then we can remove table if plugin not active.
553 $can_be_removed = true;
554
555 foreach ($plugins as $plugin) {
556 $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin);
557
558 if (__('WordPress core', 'wp-optimize') === $plugin) $wp_core_table = true;
559 // if plugin is active then we can't remove.
560 if ($wp_core_table || $status['active'] || $wp_actionscheduler_table) $can_be_removed = false;
561
562 if ($status['installed'] || $status['active'] || !$table_obj->is_using) {
563 $plugin_status[] = array(
564 'plugin' => $plugin,
565 'status' => $status,
566 );
567 }
568 }
569 }
570
571 $table_obj->plugin_status = $plugin_status;
572 $table_obj->wp_core_table = $wp_core_table;
573 $table_obj->can_be_removed = $can_be_removed;
574
575 return $table_obj;
576 }
577
578 /**
579 * This function grabs a list of tables
580 * and information regarding each table and returns
581 * the results to optimizations-table.php and optimizationstable.php
582 *
583 * @param int $blog_id filter tables by prefix
584 *
585 * @return array - an array of data such as table list, innodb info and data free
586 */
587 public function get_table_information($blog_id = 0) {
588 // Get table information.
589 $tablesstatus = $this->get_tables();
590
591 // Set defaults.
592 $table_information = array();
593 $table_information['total_gain'] = 0;
594 $table_information['inno_db_tables'] = 0;
595 $table_information['non_inno_db_tables'] = 0;
596 $table_information['table_list'] = '';
597 $table_information['is_optimizable'] = true;
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
607 // Make a list of tables to optimize.
608 foreach ($tablesstatus as $each_table) {
609 // if $blog_id is set then filter tables
610 if ($blog_id > 0 && $blog_id !== $each_table->blog_id) continue;
611
612 $table_information['table_list'] .= $each_table->Name.'|';
613
614 // check if table type supported.
615 if (!$each_table->is_type_supported) continue;
616
617 // check if table is optimizable.
618 if (!$each_table->is_optimizable) {
619 $table_information['is_optimizable'] = false;
620 }
621
622 // calculate total gain value.
623 $table_information['total_gain'] += $each_table->Data_free;
624
625 // count InnoDB tables.
626 if ('InnoDB' === $each_table->Engine) {
627 $table_information['inno_db_tables']++;
628 } else {
629 $table_information['non_inno_db_tables']++;
630 }
631 }
632
633 return $table_information;
634 }
635
636 /**
637 * What sort of linkback to enable or disable: valid values are 'trackbacks' or 'comments', and whether to enable or disable.
638 *
639 * @param string $type Specify the type of linkbacks.
640 * @param boolean $enable If it is enabled or disabled.
641 */
642 public function enable_linkbacks($type, $enable = true) {
643
644 $wpdb = $GLOBALS['wpdb'];
645 $wpo_options = WP_Optimize()->get_options();
646
647 $new_status = $enable ? 'open' : 'closed';
648
649 switch ($type) {
650 case "trackbacks":
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 );
659 break;
660
661 case "comments":
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 );
670 break;
671
672 default:
673 break;
674 }
675 $wpo_options->update_option($type.'_action', array('action' => $enable, 'timestamp' => time()));
676
677 }
678
679 /**
680 * This function will return total database size and a possible gain of db in KB.
681 *
682 * @param boolean $update - Whether to update the values or not
683 * @return array total db size gained.
684 */
685 public function get_current_db_size($update = false) {
686
687 if (!$update && $db_size = get_transient('wpo_get_current_db_size')) {
688 return $db_size;
689 }
690
691 $wp_optimize = WP_Optimize();
692
693 $total_gain = 0;
694 $total_size = 0;
695 $row_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage Used in the foreach below
696 $data_usage = 0;
697 $index_usage = 0;
698 $overhead_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage Used in the foreach below
699
700 $tablesstatus = $this->get_tables();
701
702 foreach ($tablesstatus as $tablestatus) {
703 $row_usage += $tablestatus->Rows;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage declared up above
704 $total_gain += $tablestatus->Data_free;
705 $data_usage += $tablestatus->Data_length;
706 $index_usage += $tablestatus->Index_length;
707
708 if ('InnoDB' !== $tablestatus->Engine) {
709 $overhead_usage += $tablestatus->Data_free;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage declared up above
710 $total_gain += $tablestatus->Data_free;
711 }
712 }
713
714 $total_size = ($data_usage + $index_usage);
715 $db_size = array($wp_optimize->format_size($total_size), $wp_optimize->format_size($total_gain));
716 set_transient('wpo_get_current_db_size', $db_size, 3600);
717 return $db_size;
718 }
719
720 /**
721 * This function will return total saved data in KB.
722 *
723 * @param string $current How big the data is.
724 * @return string Returns new total value.
725 */
726 public function update_total_cleaned($current) {
727
728 $options = WP_Optimize()->get_options();
729
730 $previously_saved = floatval($options->get_option('total-cleaned', '0'));
731 $converted_current = floatval($current);
732
733 $total_now = strval($previously_saved + $converted_current);
734
735 $options->update_option('total-cleaned', $total_now);
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
746 return $total_now;
747 }
748
749
750 /**
751 * Trackback, Comments actions
752 *
753 * @param array $options
754 * @return array
755 */
756 public function trackback_comment_actions($options) {
757
758 $output = array();
759 $messages = array();
760
761 if (isset($options['comments'])) {
762 if (!$options['comments']) {
763 $this->enable_linkbacks('comments', false);
764 $output[] = __('Comments have now been disabled on all current and previously published posts.', 'wp-optimize');
765 // translators: %s is a date and time
766 $messages[] = sprintf(__('All comments on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
767 } else {
768 $this->enable_linkbacks('comments');
769 $output[] = __('Comments have now been enabled on all current and previously published posts.', 'wp-optimize');
770 // translators: %s is a date and time
771 $messages[] = sprintf(__('All comments on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
772 }
773 }
774
775 if (isset($options['trackbacks'])) {
776 if (!$options['trackbacks']) {
777 $this->enable_linkbacks('trackbacks', false);
778 $output[] = __('Trackbacks have now been disabled on all current and previously published posts.', 'wp-optimize');
779 // translators: %s is a date and time
780 $messages[] = sprintf(__('All trackbacks on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
781 } else {
782 $this->enable_linkbacks('trackbacks');
783 $output[] = __('Trackbacks have now been enabled on all current and previously published posts.', 'wp-optimize');
784 // translators: %s is a date and time
785 $messages[] = sprintf(__('All trackbacks on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
786 }
787 }
788
789 return array('output' => $output,'messages' => $messages);
790 }
791
792 /**
793 * Whether InnoDB tables require confirmation to be optimized
794 *
795 * @return boolean
796 */
797 public function show_innodb_force_optimize() {
798 $tablesstatus = $this->get_table_information();
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;
934 }
935 }
936