PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.6.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.6.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.6.0, at includes/class-wp-optimizer.php

676 lines 21.7 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 * Returns singleton instance object
12 *
13 * @return WP_Optimizer Returns `WP_Optimizer` object
14 */
15 public static function instance() {
16 static $_instance = null;
17 if (null === $_instance) {
18 $_instance = new self();
19 }
20 return $_instance;
21 }
22
23 /**
24 * Gets retention information
25 *
26 * @return array
27 */
28 public function get_retain_info() {
29
30 $options = WP_Optimize()->get_options();
31
32 $retain_enabled = $options->get_option('retention-enabled', 'false');
33 $retain_period = (($retain_enabled) ? $options->get_option('retention-period', '2') : null);
34
35 return array($retain_enabled, $retain_period);
36 }
37
38 /**
39 * Get data retention options
40 *
41 * @return array
42 */
43 public function get_revisions_retain_info() {
44 $options = WP_Optimize()->get_options();
45
46 $revisions_retention_enabled = $options->get_option('revisions-retention-enabled', 'false');
47 $revisions_retention_count = $revisions_retention_enabled ? $options->get_option('revisions-retention-count', '2') : null;
48
49 return array($revisions_retention_enabled, $revisions_retention_count);
50 }
51
52 /**
53 * Gets a list of optimizations
54 *
55 * @return array
56 */
57 public function get_optimizations_list() {
58
59 $optimizations = array();
60
61 $optimizations_dir = WPO_PLUGIN_MAIN_PATH.'optimizations';
62
63 if ($dh = opendir($optimizations_dir)) {
64 while (($file = readdir($dh)) !== false) {
65 if ('.' === $file || '..' === $file || '.php' !== substr($file, -4, 4) || !is_file($optimizations_dir.'/'.$file) || 'inactive-' === substr($file, 0, 9)) continue;
66 $optimizations[] = substr($file, 0, (strlen($file) - 4));
67 }
68 closedir($dh);
69 }
70
71 $filtered_optimizations = apply_filters('wp_optimize_get_optimizations_list', $optimizations);
72 return is_array($filtered_optimizations) ? $filtered_optimizations : $optimizations;
73 }
74
75 /**
76 * Currently, there is only one sort rule (so, the parameter's value is ignored)
77 *
78 * @param array $optimizations An array of optimizations (i.e. WP_Optimization instances).
79 * @param string $sort_on Specify sort.
80 *
81 * @return array
82 */
83 public function sort_optimizations($optimizations, $sort_on = 'ui_sort_order') {
84 if ('run_sort_order' === $sort_on) {
85 uasort($optimizations, array($this, 'sort_optimizations_run_traditional'));
86 } else {
87 uasort($optimizations, array($this, 'sort_optimizations_ui_traditional'));
88 }
89 return $optimizations;
90 }
91
92 /**
93 * Sorts optimizations based on UI order
94 *
95 * @param WP_Optimization $a
96 * @param WP_Optimization $b
97 * @return int
98 */
99 public function sort_optimizations_ui_traditional($a, $b) {
100 return $this->sort_optimizations_traditional($a, $b);
101 }
102
103 /**
104 * Sorts optimizations based on Run order
105 *
106 * @param WP_Optimization $a
107 * @param WP_Optimization $b
108 * @return int
109 */
110 public function sort_optimizations_run_traditional($a, $b) {
111 return $this->sort_optimizations_traditional($a, $b, 'run_sort_order');
112 }
113
114 /**
115 * Sorting list of optimization based on given order
116 *
117 * @param WP_Optimization $a
118 * @param WP_Optimization $b
119 * @param string $sort_on
120 * @return int
121 */
122 public function sort_optimizations_traditional($a, $b, $sort_on = 'ui_sort_order') {
123 $sort_order_a = empty($a->$sort_on) ? 0 : $a->$sort_on;
124 $sort_order_b = empty($b->$sort_on) ? 0 : $b->$sort_on;
125
126 if ($sort_order_a === $sort_order_b) return 0;
127
128 return ($sort_order_a < $sort_order_b) ? -1 : 1;
129 }
130
131 /**
132 * This method returns an array of available optimizations.
133 * Each array key is an optimization ID, and the value is an object,
134 * as returned by get_optimization()
135 *
136 * @return array array of optimizations
137 */
138 public function get_optimizations() {
139
140 $optimizations = $this->get_optimizations_list();
141
142 $optimization_objects = array();
143
144 foreach ($optimizations as $optimization) {
145 $optimization_object = $this->get_optimization($optimization);
146 if (is_wp_error($optimization_object)) {
147 WP_Optimize()->log('Failed to load optimization ' . $optimization . ' - ' . $optimization_object->get_error_message());
148 } else {
149 $optimization_objects[$optimization] = $optimization_object;
150 }
151 }
152
153 $filtered_optimizations = apply_filters('wp_optimize_get_optimizations', $optimization_objects);
154 return is_array($filtered_optimizations) ? $filtered_optimizations : $optimization_objects;
155
156 }
157
158 /**
159 * This method returns an object for a specific optimization.
160 *
161 * @param string|object $which_optimization An optimization ID.
162 * @param array $data An array of anny options $data.
163 * @return array|WP_Error WP_Error Will return the optimization, or a WP_Error object if it was not found.
164 */
165 public function get_optimization($which_optimization, $data = array()) {
166
167 $optimization_class = apply_filters('wp_optimize_optimization_class', 'WP_Optimization_'.$which_optimization);
168
169 if (!class_exists('WP_Optimization')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimization.php');
170
171 if (!class_exists($optimization_class)) {
172 $optimization_file = WPO_PLUGIN_MAIN_PATH.'optimizations/'.$which_optimization.'.php';
173 $class_file = apply_filters('wp_optimize_optimization_class_file', $optimization_file);
174 if (!preg_match('/^[a-z]+$/', $which_optimization) || !file_exists($class_file)) {
175 return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
176 }
177
178 include_once($class_file);
179
180 if (!class_exists($optimization_class)) {
181 return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
182 }
183 }
184
185 // set sites option for Multisite cron job.
186 if (defined('DOING_CRON') && DOING_CRON && is_multisite()) {
187 $options = WP_Optimize()->get_options();
188 $data['optimization_sites'] = $options->get_option('wpo-sites-cron', array('all'));
189 }
190
191 $optimization = new $optimization_class($data);
192
193 return $optimization;
194
195 }
196
197 /**
198 * The method to call to perform an optimization.
199 *
200 * @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
201 * @return object Array of results from the optimization.
202 */
203 public function do_optimization($which_optimization) {
204
205 $optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
206
207 if (is_wp_error($optimization)) {
208 WP_Optimize()->log('Error occurred. Unknown optimization.');
209 return $optimization;
210 }
211
212 WP_Optimize()->change_time_limit();
213
214 $optimization->init();
215
216 if (apply_filters('wp_optimize_do_optimization', true, $which_optimization, $optimization)) {
217
218 $optimization->before_optimize();
219
220 if ($optimization->run_multisite) {
221 foreach ($optimization->blogs_ids as $blog_id) {
222 $optimization->switch_to_blog($blog_id);
223 $optimization->optimize();
224 $optimization->restore_current_blog();
225 }
226 } else {
227 $optimization->optimize();
228 }
229
230 $optimization->after_optimize();
231
232 }
233
234 do_action('wp_optimize_after_optimization', $which_optimization, $optimization);
235
236 $results = $optimization->get_results();
237
238 return $results;
239 }
240
241 /**
242 * The method to call to get information about an optimization.
243 * As with do_optimization, it is somewhat modelled after the template interface
244 *
245 * @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
246 * @return object returns the optimization information
247 */
248 public function get_optimization_info($which_optimization) {
249
250 $optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
251
252 if (is_wp_error($optimization)) return $optimization;
253
254 WP_Optimize()->change_time_limit();
255
256 $optimization->before_get_info();
257
258 if ($optimization->run_multisite) {
259 foreach ($optimization->blogs_ids as $blog_id) {
260 $optimization->switch_to_blog($blog_id);
261 $optimization->get_info();
262 $optimization->restore_current_blog();
263 }
264 } else {
265 $optimization->get_info();
266 }
267
268 $optimization->after_get_info();
269
270 return $optimization->get_results();
271 }
272
273 /**
274 * This runs the list of optimizations.
275 *
276 * @param array $optimization_options Whether to do an optimization depends on what keys are set (legacy - can be changed hopefully).
277 * @param string $which_option Specify which option.
278 * @return array Returns an array of result objects.
279 */
280 public function do_optimizations($optimization_options, $which_option = 'dom') {
281
282 $results = array();
283
284 if (empty($optimization_options)) return $results;
285
286 $optimizations = $this->sort_optimizations($this->get_optimizations(), 'run_sort_order');
287
288 foreach ($optimizations as $optimization_id => $optimization) {
289 $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
290
291 if (isset($optimization_options[$option_id])) {
292 // if options saved as a string then compare with string (for support different versions)
293 if ('false' === $optimization_options[$option_id]) continue;
294
295 if ('auto' === $which_option && empty($optimization->available_for_auto)) continue;
296
297 WP_Optimize()->change_time_limit();
298
299 $results[$optimization_id] = $this->do_optimization($optimization);
300 }
301 }
302
303 // Run action after all optimizations completed.
304 do_action('wp_optimize_after_optimizations');
305
306 return $results;
307
308 }
309
310 public function get_table_prefix($allow_override = false) {
311 $wpdb = $GLOBALS['wpdb'];
312 if (is_multisite() && !defined('MULTISITE')) {
313 // 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.
314 $prefix = $wpdb->base_prefix;
315 } else {
316 $prefix = $wpdb->get_blog_prefix(0);
317 }
318 return ($allow_override) ? apply_filters('wp_optimize_get_table_prefix', $prefix) : $prefix;
319 }
320
321 /**
322 * Returns information about database tables.
323 *
324 * @param bool $update refresh or no cached data
325 *
326 * @return mixed
327 */
328 public function get_tables($update = false) {
329 static $tables_info = null;
330
331 if (false === $update && null !== $tables_info) return $tables_info;
332
333 $wpo_db_info = WP_Optimize()->get_db_info();
334
335 $table_status = $wpo_db_info->get_show_table_status($update);
336
337 // Filter on the site's DB prefix (was not done in releases up to 1.9.1).
338 $table_prefix = $this->get_table_prefix();
339
340 if (is_array($table_status)) {
341
342 $corrupted_tables_count = 0;
343 $array_index_was_unset = false;
344
345 foreach ($table_status as $index => $table) {
346 $table_name = $table->Name;
347
348 $include_table = (0 === stripos($table_name, $table_prefix));
349
350 $include_table = apply_filters('wp_optimize_get_tables_include_table', $include_table, $table_name, $table_prefix);
351
352 if (!$include_table && '' !== $table_prefix) {
353 unset($table_status[$index]);
354 $array_index_was_unset = true;
355 continue;
356 }
357
358 $table_status[$index]->Engine = $wpo_db_info->get_table_type($table_name);
359
360 $table_status[$index]->is_optimizable = $wpo_db_info->is_table_optimizable($table_name);
361 $table_status[$index]->is_type_supported = $wpo_db_info->is_table_type_optimize_supported($table_name);
362 // add information about corrupted tables.
363 $is_needing_repair = $wpo_db_info->is_table_needing_repair($table_name);
364 $table_status[$index]->is_needing_repair = $is_needing_repair;
365 if ($is_needing_repair) $corrupted_tables_count++;
366
367 $table_status[$index] = $this->join_plugin_information($table_name, $table_status[$index]);
368
369 $table_status[$index]->blog_id = $wpo_db_info->get_table_blog_id($table_name);
370 }
371 if ($array_index_was_unset) {
372 // Reset array keys after removing elements
373 $table_status = array_values($table_status);
374 }
375
376 WP_Optimize()->get_options()->update_option('corrupted-tables-count', $corrupted_tables_count);
377 }
378
379 $tables_info = apply_filters('wp_optimize_get_tables', $table_status);
380 return $tables_info;
381 }
382
383 /**
384 * Returns information about single table by table name.
385 *
386 * @param string $table_name table name
387 * @return object|boolean table information object.
388 */
389 public function get_table($table_name) {
390
391 $db_info = WP_Optimize()->get_db_info();
392
393 $table = $db_info->get_table_status($table_name);
394
395 if (false === $table) return false;
396
397 $table->is_optimizable = $db_info->is_table_optimizable($table_name);
398 $table->is_type_supported = $db_info->is_table_type_optimize_supported($table_name);
399 $table->is_needing_repair = $db_info->is_table_needing_repair($table_name);
400
401 // add information about plugins.
402 $table = $this->join_plugin_information($table_name, $table);
403
404 $table = apply_filters('wp_optimize_get_table', $table);
405 return $table;
406 }
407
408 /**
409 * Add information about relationship database tables with plugins.
410 *
411 * @param string $table_name
412 * @param object $table_obj
413 *
414 * @return object
415 */
416 private function join_plugin_information($table_name, $table_obj) {
417 // set can be removed flag.
418 $can_be_removed = false;
419 // set WP core table flag.
420 $wp_core_table = false;
421 // set WP actionscheduler table flag.
422 $wp_actionscheduler_table = (false !== stripos($table_name, 'actionscheduler_'));
423 // if table belongs to any plugin then add plugins status.
424 $plugins = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
425
426 if (false === $plugins) {
427 // if we can't determine which plugin use $table then mark table as used.
428 $table_obj->is_using = true;
429 } else {
430 // if any plugin is installed which use table - $table_name then mark table as used.
431 $table_obj->is_using = WP_Optimize()->get_db_info()->is_any_plugin_installed($plugins);
432 }
433
434 $plugin_status = array();
435
436 if (false !== $plugins) {
437 // if belongs to any of plugin then we can remove table if plugin not active.
438 $can_be_removed = true;
439
440 foreach ($plugins as $plugin) {
441 $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin);
442
443 if (__('WordPress core', 'wp-optimize') === $plugin) $wp_core_table = true;
444 // if plugin is active then we can't remove.
445 if ($wp_core_table || $status['active'] || $wp_actionscheduler_table) $can_be_removed = false;
446
447 if ($status['installed'] || $status['active'] || !$table_obj->is_using) {
448 $plugin_status[] = array(
449 'plugin' => $plugin,
450 'status' => $status,
451 );
452 }
453 }
454 }
455
456 $table_obj->plugin_status = $plugin_status;
457 $table_obj->wp_core_table = $wp_core_table;
458 $table_obj->can_be_removed = $can_be_removed;
459
460 return $table_obj;
461 }
462
463 /**
464 * This function grabs a list of tables
465 * and information regarding each table and returns
466 * the results to optimizations-table.php and optimizationstable.php
467 *
468 * @param int $blog_id filter tables by prefix
469 *
470 * @return array - an array of data such as table list, innodb info and data free
471 */
472 public function get_table_information($blog_id = 0) {
473 // Get table information.
474 $tablesstatus = $this->get_tables();
475
476 // Set defaults.
477 $table_information = array();
478 $table_information['total_gain'] = 0;
479 $table_information['inno_db_tables'] = 0;
480 $table_information['non_inno_db_tables'] = 0;
481 $table_information['table_list'] = '';
482 $table_information['is_optimizable'] = true;
483
484 // Make a list of tables to optimize.
485 foreach ($tablesstatus as $each_table) {
486 // if $blog_id is set then filter tables
487 if ($blog_id > 0 && $blog_id !== $each_table->blog_id) continue;
488
489 $table_information['table_list'] .= $each_table->Name.'|';
490
491 // check if table type supported.
492 if (!$each_table->is_type_supported) continue;
493
494 // check if table is optimizable.
495 if (!$each_table->is_optimizable) {
496 $table_information['is_optimizable'] = false;
497 }
498
499 // calculate total gain value.
500 $table_information['total_gain'] += $each_table->Data_free;
501
502 // count InnoDB tables.
503 if ('InnoDB' === $each_table->Engine) {
504 $table_information['inno_db_tables']++;
505 } else {
506 $table_information['non_inno_db_tables']++;
507 }
508 }
509
510 return $table_information;
511 }
512
513 /**
514 * What sort of linkback to enable or disable: valid values are 'trackbacks' or 'comments', and whether to enable or disable.
515 *
516 * @param string $type Specify the type of linkbacks.
517 * @param boolean $enable If it is enabled or disabled.
518 */
519 public function enable_linkbacks($type, $enable = true) {
520
521 $wpdb = $GLOBALS['wpdb'];
522 $wpo_options = WP_Optimize()->get_options();
523
524 $new_status = $enable ? 'open' : 'closed';
525
526 switch ($type) {
527 case "trackbacks":
528 $wpdb->query(
529 $wpdb->prepare(
530 "UPDATE `{$wpdb->posts}` SET ping_status = %s WHERE post_status = %s AND post_type = %s",
531 $new_status,
532 'publish',
533 'post'
534 )
535 );
536 break;
537
538 case "comments":
539 $wpdb->query(
540 $wpdb->prepare(
541 "UPDATE `{$wpdb->posts}` SET comment_status = %s WHERE post_status = %s AND post_type = %s",
542 $new_status,
543 'publish',
544 'post'
545 )
546 );
547 break;
548
549 default:
550 break;
551 }
552 $wpo_options->update_option($type.'_action', array('action' => $enable, 'timestamp' => time()));
553
554 }
555
556 /**
557 * This function will return total database size and a possible gain of db in KB.
558 *
559 * @param boolean $update - Whether to update the values or not
560 * @return array total db size gained.
561 */
562 public function get_current_db_size($update = false) {
563
564 if (!$update && $db_size = get_transient('wpo_get_current_db_size')) {
565 return $db_size;
566 }
567
568 $wp_optimize = WP_Optimize();
569
570 $total_gain = 0;
571 $total_size = 0;
572 $row_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage Used in the foreach below
573 $data_usage = 0;
574 $index_usage = 0;
575 $overhead_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage Used in the foreach below
576
577 $tablesstatus = $this->get_tables();
578
579 foreach ($tablesstatus as $tablestatus) {
580 $row_usage += $tablestatus->Rows;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage declared up above
581 $total_gain += $tablestatus->Data_free;
582 $data_usage += $tablestatus->Data_length;
583 $index_usage += $tablestatus->Index_length;
584
585 if ('InnoDB' !== $tablestatus->Engine) {
586 $overhead_usage += $tablestatus->Data_free;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage declared up above
587 $total_gain += $tablestatus->Data_free;
588 }
589 }
590
591 $total_size = ($data_usage + $index_usage);
592 $db_size = array($wp_optimize->format_size($total_size), $wp_optimize->format_size($total_gain));
593 set_transient('wpo_get_current_db_size', $db_size, 3600);
594 return $db_size;
595 }
596
597 /**
598 * This function will return total saved data in KB.
599 *
600 * @param string $current How big the data is.
601 * @return string Returns new total value.
602 */
603 public function update_total_cleaned($current) {
604
605 $options = WP_Optimize()->get_options();
606
607 $previously_saved = floatval($options->get_option('total-cleaned', '0'));
608 $converted_current = floatval($current);
609
610 $total_now = strval($previously_saved + $converted_current);
611
612 $options->update_option('total-cleaned', $total_now);
613
614 $previously_saved = floatval($options->get_option('total-cleaned-current-month', '0'));
615
616 $total_now = strval($previously_saved + $converted_current);
617
618 $options->update_option('total-cleaned-current-month', $total_now);
619
620 return $total_now;
621 }
622
623
624 /**
625 * Trackback, Comments actions
626 *
627 * @param array $options
628 * @return array
629 */
630 public function trackback_comment_actions($options) {
631
632 $output = array();
633 $messages = array();
634
635 if (isset($options['comments'])) {
636 if (!$options['comments']) {
637 $this->enable_linkbacks('comments', false);
638 $output[] = __('Comments have now been disabled on all current and previously published posts.', 'wp-optimize');
639 // translators: %s is a date and time
640 $messages[] = sprintf(__('All comments on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
641 } else {
642 $this->enable_linkbacks('comments');
643 $output[] = __('Comments have now been enabled on all current and previously published posts.', 'wp-optimize');
644 // translators: %s is a date and time
645 $messages[] = sprintf(__('All comments on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
646 }
647 }
648
649 if (isset($options['trackbacks'])) {
650 if (!$options['trackbacks']) {
651 $this->enable_linkbacks('trackbacks', false);
652 $output[] = __('Trackbacks have now been disabled on all current and previously published posts.', 'wp-optimize');
653 // translators: %s is a date and time
654 $messages[] = sprintf(__('All trackbacks on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
655 } else {
656 $this->enable_linkbacks('trackbacks');
657 $output[] = __('Trackbacks have now been enabled on all current and previously published posts.', 'wp-optimize');
658 // translators: %s is a date and time
659 $messages[] = sprintf(__('All trackbacks on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
660 }
661 }
662
663 return array('output' => $output,'messages' => $messages);
664 }
665
666 /**
667 * Whether InnoDB tables require confirmation to be optimized
668 *
669 * @return boolean
670 */
671 public function show_innodb_force_optimize() {
672 $tablesstatus = $this->get_table_information();
673 return false === $tablesstatus['is_optimizable'] && $tablesstatus['inno_db_tables'] > 0;
674 }
675 }
676