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 | wp-optimize.php +565 -244 3.4.1 → 4.7.0 View file →
@@ -1,13 +1,15 @@
1 1 <?php
2 2 /**
3 3 Plugin Name: WP-Optimize - Clean, Compress, Cache
4 -Plugin URI: https://getwpo.com
4 +Plugin URI: https://teamupdraft.com/wp-optimize
5 5 Description: WP-Optimize makes your site fast and efficient. It cleans the database, compresses images and caches pages. Fast sites attract more traffic and users.
6 -Version: 3.4.1
6 +Version: 4.7.0
7 +Requires at least: 4.9
8 +Requires PHP: 7.2
7 9 Update URI: https://wordpress.org/plugins/wp-optimize/
8 -Author: David Anderson, Ruhani Rabin, Team Updraft
9 -Author URI: https://updraftplus.com
10 +Author: TeamUpdraft, DavidAnderson
11 +Author URI: https://teamupdraft.com/wp-optimize?utm_source=wpo-wp-dir&utm_medium=referral&utm_campaign=plugin-dir&utm_content=teamupdraft&utm_creative_format=author
10 12 Text Domain: wp-optimize
11 13 Domain Path: /languages
12 14 License: GPLv2 or later
13 15 */
@@ -15,19 +17,21 @@
15 17 if (!defined('ABSPATH')) die('No direct access allowed');
16 18
17 19 // Check to make sure if WP_Optimize is already call and returns.
18 20 if (!class_exists('WP_Optimize')) :
19 -define('WPO_VERSION', '3.4.1');
21 +define('WPO_VERSION', '4.7.0');
20 22 define('WPO_PLUGIN_URL', plugin_dir_url(__FILE__));
21 23 define('WPO_PLUGIN_MAIN_PATH', plugin_dir_path(__FILE__));
22 24 define('WPO_PLUGIN_SLUG', plugin_basename(__FILE__));
23 25 define('WPO_PREMIUM_NOTIFICATION', false);
24 -define('WPO_MINIFY_PHP_VERSION_MET', version_compare(PHP_VERSION, '5.4', '>=') ? true : false);
26 +define('WPO_REQUIRED_PHP_VERSION', '7.2');
27 +define('WPO_REQUIRED_WP_VERSION', '4.9');
25 28 if (!defined('WPO_USE_WEBP_CONVERSION')) define('WPO_USE_WEBP_CONVERSION', true);
29 +require_once(WPO_PLUGIN_MAIN_PATH.'includes/fragments/input-processing.php');
26 30
27 31 class WP_Optimize {
28 32
29 - public $premium_version_link = 'https://getwpo.com/buy/';
33 + public $premium_version_link = 'https://teamupdraft.com/wp-optimize/pricing/?utm_source=wpo-plugin&utm_medium=referral&utm_campaign=paac&utm_creative_format=overlay';
30 34
31 35 private $template_directories;
32 36
33 37 protected static $_instance = null;
@@ -34,13 +38,49 @@
34 38
35 39 protected $_cache_init_status = null;
36 40
37 41 /**
42 + * An array of schedule types
43 + *
44 + * @param boolean $placeholder Determines whether a placeholder select option should be included or not
45 + *
46 + * @return array An array of schedule types
47 + */
48 + public static function get_schedule_types($placeholder = false) {
49 + $schedule_types = array(
50 + 'wpo_daily' => __('Daily', 'wp-optimize'),
51 + 'wpo_weekly' => __('Weekly', 'wp-optimize'),
52 + 'wpo_fortnightly' => __('Fortnightly', 'wp-optimize'),
53 + 'wpo_monthly' => __('Monthly', 'wp-optimize'),
54 + );
55 +
56 + $schedule_types = apply_filters('wp_optimize_schedule_types', $schedule_types);
57 + if (true === $placeholder) {
58 + $schedule_types = array_merge(array('' => __('Select schedule', 'wp-optimize')), $schedule_types);
59 + }
60 + return $schedule_types;
61 + }
62 +
63 + /**
38 64 * Class constructor
39 65 */
40 66 public function __construct() {
67 +
41 68 spl_autoload_register(array($this, 'loader'));
42 69
70 + // Don't process when accessing without normal WordPress core loading.
71 + if (!defined('WPINC')) return;
72 +
73 + $bypass_instance = $this->get_bypass_instance();
74 + if ($bypass_instance->should_bypass()) {
75 + // Show a bypass notice in the admin bar
76 + $bypass_instance->show_admin_notice();
77 + if (!headers_sent()) {
78 + header('WPO-Bypass-Mode: active');
79 + }
80 + return;
81 + }
82 +
43 83 // Checks if premium is installed along with plugins needed.
44 84 add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
45 85
46 86 register_activation_hook(__FILE__, array('WPO_Activation', 'actions'));
@@ -45,15 +85,14 @@
45 85
46 86 register_activation_hook(__FILE__, array('WPO_Activation', 'actions'));
47 87 register_deactivation_hook(__FILE__, array('WPO_Deactivation', 'actions'));
48 88 register_uninstall_hook(__FILE__, array('WPO_Uninstall', 'actions'));
49 -
89 +
90 + WPO_Page_Optimizer::instance()->maybe_initialise();
91 +
50 92 $this->load_admin();
51 93 add_action('admin_init', array($this, 'admin_init'));
52 - add_action('admin_bar_menu', array($this, 'cache_admin_bar'), 100, 1);
53 94
54 - add_action('init', array($this, 'schedule_plugin_cron_tasks'));
55 -
56 95 add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
57 96 add_action('wpo_cron_event2', array($this, 'cron_action'));
58 97 add_filter('cron_schedules', array($this, 'cron_schedules'));
59 98
@@ -58,23 +97,24 @@
58 97 add_filter('cron_schedules', array($this, 'cron_schedules'));
59 98
60 99 if (!$this->get_options()->get_option('installed-for', false)) $this->get_options()->update_option('installed-for', time());
61 100
62 - if (!self::is_premium()) {
63 - add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
64 - }
101 + add_action('admin_footer-upload.php', array($this, 'add_smush_popup_template'));
65 102
66 103 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
67 104
68 105 add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_scripts'));
69 106
107 + if ($this->get_options()->get_option('404_detector', 0)) {
108 + WP_Optimize_Performance::get_instance($this->get_404_detector())->hook_404_handler();
109 + }
110 +
70 111 $this->load_ajax_handler();
71 - WP_Optimize_Heartbeat::get_instance();
72 112
73 113 // Show update to Premium notice for non-premium multisite.
74 114 add_action('wpo_additional_options', array($this, 'show_multisite_update_to_premium_notice'));
75 115
76 - // Action column (show repair button if need).
116 + // Action column (show repair button, if needed).
77 117 add_filter('wpo_tables_list_additional_column_data', array($this, 'tables_list_additional_column_data'), 15, 2);
78 118
79 119 /**
80 120 * Add action for display Images > Compress images tab.
@@ -80,9 +120,9 @@
80 120 * Add action for display Images > Compress images tab.
81 121 */
82 122 add_action('wp_optimize_admin_page_wpo_images_smush', array($this, 'admin_page_wpo_images_smush'));
83 123
84 - include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral.php');
124 + include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral/updraftcentral.php');
85 125
86 126 include_once(WPO_PLUGIN_MAIN_PATH.'includes/backward-compatibility-functions.php');
87 127
88 128 register_shutdown_function(array($this, 'log_fatal_errors'));
@@ -91,9 +131,9 @@
91 131
92 132 add_action('upgrader_process_complete', array($this, 'detect_active_plugins_and_themes_updates'), 10, 2);
93 133
94 134 $import_done_hooks = array(
95 - 'import_end', // wordpress importer
135 + 'import_end', // WordPress importer
96 136 'pmxi_after_xml_import', // wp all import
97 137 );
98 138
99 139 $db_update_hooks = apply_filters('wp_optimize_db_update_hooks', $import_done_hooks);
@@ -102,16 +142,87 @@
102 142 add_action($hook, array($this, 'maybe_schedule_update_record_count_event'));
103 143 }
104 144 add_action('wpo_update_record_count_event', array($this->get_db_info(), 'wpo_update_record_count'));
105 145
146 + add_action('wpo_reset_stats_counter', array($this, 'reset_stats_counters'));
147 +
148 + $this->schedule_reset_stats_counters_event();
149 +
106 150 }
107 151
108 152 /**
109 - * Auto-loads classes.
153 + * Reset stats counter at the start of each month
154 + */
155 + public function reset_stats_counters() {
156 + // Save current total cleaned as previous month data
157 + $options = $this->get_options();
158 + $last_month_total_cleaned = $options->get_option('total-cleaned-current-month');
159 + $options->update_option('total-cleaned-previous-month', $last_month_total_cleaned);
160 + $options->update_option('total-cleaned-current-month', '0');
161 + $this->schedule_reset_stats_counters_event();
162 + }
163 +
164 + /**
165 + * Schedule the reset of stat's counter at the start of each month
166 + */
167 + private function schedule_reset_stats_counters_event() {
168 + if (!wp_next_scheduled('wpo_reset_stats_counter')) {
169 + $next_reset = strtotime('first day of next month midnight');
170 + wp_schedule_single_event($next_reset, 'wpo_reset_stats_counter');
171 + }
172 + }
173 +
174 + /**
175 + * Returns Onboarding class instance
110 176 *
177 + * @return WPO_Onboarding
178 + */
179 + public function get_onboarding() {
180 + return WPO_Onboarding::instance();
181 + }
182 +
183 + /**
184 + * Check if minimum requirements for WP-Optimize is met or not.
185 + *
186 + * @return bool
187 + */
188 + public function is_minimum_requirement_met() {
189 + global $wp_version;
190 + return (version_compare(WPO_REQUIRED_PHP_VERSION, PHP_VERSION, '<=') && version_compare(WPO_REQUIRED_WP_VERSION, $wp_version, '<='));
191 + }
192 +
193 + /**
194 + * Add admin notice about minimum server requirements.
195 + */
196 + public function add_notice_minimum_requirements_not_met() {
197 + add_action('admin_notices', array($this, 'output_minimum_requirements_notice'));
198 + }
199 +
200 + /**
201 + * Deactivate the plugin programmatically
202 + */
203 + public function deactivate_plugin() {
204 + if (!function_exists('deactivate_plugins')) {
205 + require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
206 + }
207 + deactivate_plugins(plugin_basename(__FILE__));
208 + }
209 +
210 + /**
211 + * Die after stating minimum requirements
212 + */
213 + public function die_minimum_requirement_not_met() {
214 + $message = $this->get_minimum_requirements_notice_message();
215 + $message .= ' <a href="'.esc_url(admin_url('plugins.php')).'">'.esc_html__('Back to Plugins.', 'wp-optimize').'</a>';
216 + wp_die(wp_kses_post($message));
217 + }
218 +
219 + /**
220 + * Autoloads classes.
221 + *
111 222 * @param string $class_name The name of the class.
112 223 */
113 - private function loader($class_name) {
224 + public function loader($class_name) {
114 225 $dirs = $this->get_class_directories();
115 226
116 227 foreach ($dirs as $dir) {
117 228 $class_file = WPO_PLUGIN_MAIN_PATH . trailingslashit($dir) . 'class-' . str_replace('_', '-', strtolower($class_name)) . '.php';
@@ -118,8 +229,14 @@
118 229 if (file_exists($class_file)) {
119 230 require_once($class_file);
120 231 return;
121 232 }
233 +
234 + $interface_file = WPO_PLUGIN_MAIN_PATH . trailingslashit($dir) . 'interface-' . str_replace('_', '-', strtolower($class_name)) . '.php';
235 + if (file_exists($interface_file)) {
236 + require_once($interface_file);
237 + return;
238 + }
122 239 }
123 240
124 241 // Include PHP Minify - https://github.com/matthiasmullie/minify
125 242 if (strpos($class_name, 'MatthiasMullie') !== false) {
@@ -129,12 +246,11 @@
129 246 require_once($class_file);
130 247 return;
131 248 }
132 249 }
133 -
134 - if ('Minify_HTML' == $class_name) {
250 +
251 + if ('Minify_HTML' === $class_name) {
135 252 require_once WPO_PLUGIN_MAIN_PATH.'vendor/mrclay/minify/lib/Minify/HTML.php';
136 - return;
137 253 }
138 254 }
139 255
140 256 /**
@@ -146,11 +262,17 @@
146 262 return array(
147 263 'cache',
148 264 'compatibility',
149 265 'includes',
266 + 'includes/tables',
267 + 'includes/list-tables',
268 + 'includes/dashboard',
269 + 'includes/gravatars',
270 + 'includes/lcp',
150 271 'minify',
151 272 'optimizations',
152 273 'webp',
274 + 'includes/updraftcentral',
153 275 );
154 276 }
155 277
156 278 /**
@@ -160,8 +282,17 @@
160 282 $this->get_admin_instance();
161 283 }
162 284
163 285 /**
286 + * Returns Bypass class instance
287 + *
288 + * @return WP_Optimize_Bypass
289 + */
290 + private function get_bypass_instance() {
291 + return WP_Optimize_Bypass::instance();
292 + }
293 +
294 + /**
164 295 * Returns Admin class instance
165 296 *
166 297 * @return WP_Optimize_Admin
167 298 */
@@ -182,11 +313,23 @@
182 313 $should_purge_cache = false;
183 314 $skin = $upgrader_object->skin;
184 315 if ('plugin' === $options['type']) {
185 316 // A plugin is updated using the default update system (upgrader_overwrote_package is used for the upload method)
186 - if (property_exists($skin, 'plugin_active') && $skin->plugin_active) {
187 - $should_purge_cache = true;
317 + $plugins = array();
318 + if (!empty($options['plugin'])) {
319 + $plugins = array($options['plugin']);
320 + } elseif (!empty($options['plugins']) && is_array($options['plugins'])) {
321 + $plugins = $options['plugins'];
188 322 }
323 +
324 + foreach ($plugins as $plugin) {
325 + if (!empty($plugin) && ! is_wp_error($upgrader_object->result)) {
326 + if (is_plugin_active($plugin)) {
327 + $should_purge_cache = true;
328 + break;
329 + }
330 + }
331 + }
189 332 } elseif ('theme' === $options['type']) {
190 333 $active_theme = get_stylesheet();
191 334 $parent_theme = get_template();
192 335 // A theme is updated using the upload system
@@ -192,9 +335,9 @@
192 335 // A theme is updated using the upload system
193 336 if (isset($options['action']) && 'install' === $options['action'] && isset($skin->options['overwrite']) && 'update-theme' === $skin->options['overwrite']) {
194 337 $updated_theme = $upgrader_object->result['destination_name'];
195 338 // Check if the theme is in use
196 - if ($active_theme == $updated_theme || $parent_theme == $updated_theme) {
339 + if ($active_theme === $updated_theme || $parent_theme === $updated_theme) {
197 340 $should_purge_cache = true;
198 341 }
199 342 // A theme is updated using the classic update system
200 343 } elseif (isset($options['action']) && 'update' === $options['action'] && isset($options['themes']) && is_array($options['themes'])) {
@@ -223,11 +366,12 @@
223 366
224 367 public function admin_page_wpo_images_smush() {
225 368 $options = Updraft_Smush_Manager()->get_smush_options();
226 369 $custom = 90 >= $options['image_quality'] && 65 <= $options['image_quality'];
227 - $sites = WP_Optimize()->get_sites();
228 - $this->include_template('images/smush.php', false, array('smush_options' => $options, 'custom' => $custom, 'sites' => $sites, 'does_server_allows_local_webp_conversion' => $this->does_server_allows_local_webp_conversion()));
229 - $this->include_template('images/smush-popup.php');
370 + $sites = $this->get_sites();
371 + $compression_server_hint = Updraft_Smush_Manager()->get_compression_server_hint();
372 + $this->include_template('images/smush.php', false, array('smush_options' => $options, 'custom' => $custom, 'sites' => $sites, 'does_server_allow_local_webp_conversion' => $this->get_server_compatibility_instance()->does_server_allow_local_webp_conversion(), 'compression_server_hint' => $compression_server_hint));
373 + $this->add_smush_popup_template();
230 374 }
231 375
232 376 public static function instance() {
233 377 if (empty(self::$_instance)) {
@@ -243,13 +387,29 @@
243 387 /**
244 388 * Adds 3rd party plugin compatibilities.
245 389 */
246 390 public function load_compatibilities() {
247 - WPO_Polylang_Compatibility::instance();
391 + global $wp_version;
392 +
393 + if (class_exists('Polylang')) {
394 + WPO_Polylang_Compatibility::instance();
395 + }
396 +
397 + if (version_compare($wp_version, '5.2', '<')) {
398 + WPO_WP_Kses_Compatibility::instance();
399 + }
400 +
248 401 WPO_Page_Builder_Compatibility::instance();
249 - WPO_Custom_Permalink_Compatibility::instance();
250 - WPO_TranslatePress_Compatibility::instance();
402 + WPO_KD_Submissions_Compatibility::instance();
251 403
404 + if (class_exists('Custom_Permalinks')) {
405 + WPO_Custom_Permalink_Compatibility::instance();
406 + }
407 +
408 + if (class_exists('TRP_Translate_Press')) {
409 + WPO_TranslatePress_Compatibility::instance();
410 + }
411 +
252 412 do_action('wpo_load_compatibilities');
253 413 }
254 414
255 415 /**
@@ -269,58 +429,59 @@
269 429 return WP_Optimize_Notices::instance();
270 430 }
271 431
272 432 /**
273 - * Returns instance if WPO_Page_Cache class.
433 + * Get and instantiate WP_Optimize_Delay_JS
274 434 *
275 - * @return WPO_Page_Cache
435 + * @return WP_Optimize_Delay_JS
276 436 */
277 - public function get_page_cache() {
278 - return WPO_Page_Cache::instance();
437 + private function get_delay_js() {
438 + return WP_Optimize_Delay_JS::instance();
279 439 }
280 440
281 441 /**
282 - * Returns instance if WP_Optimize_WebP class.
442 + * Returns instance of WPO_Page_Optimizer class.
283 443 *
284 - * @return WP_Optimize_WebP
444 + * @return WPO_Page_Optimizer
285 445 */
286 - public function get_webp_instance() {
287 - return WP_Optimize_WebP::get_instance();
446 + public function get_page_optimizer() {
447 + return WPO_Page_Optimizer::instance();
288 448 }
289 449
290 450 /**
291 - * Detects if the platform is Kinsta or not
451 + * Returns instance 404 Detector Cron class.
292 452 *
293 - * @return bool Returns true if it is Kinsta platform, otherwise returns false
453 + * @return WP_Optimize_404_Detector_Cron
294 454 */
295 - private function is_kinsta() {
296 - return isset($_SERVER['KINSTA_CACHE_ZONE']);
455 + private function get_404_detector_cron() {
456 + return WP_Optimize_404_Detector_Cron::get_instance();
297 457 }
298 458
299 459 /**
300 - * Detects whether the server handles cache. eg. Nginx cache
460 + * Returns instance of WPO_Page_Cache class.
461 + *
462 + * @return WPO_Page_Cache
301 463 */
302 - public function does_server_handles_cache() {
303 - return $this->is_kinsta();
464 + public function get_page_cache() {
465 + return WPO_Page_Cache::instance();
304 466 }
305 467
306 468 /**
307 - * Detects whether the server supports table optimization.
469 + * Returns instance of WP_Optimize_WebP class.
308 470 *
309 - * Some servers prevent table optimization
310 - * because InnoDB engine does not optimize table
311 - * instead it drops tables and recreate them
312 - * which results in elevated disk write operations
471 + * @return WP_Optimize_WebP
313 472 */
314 - public function does_server_allows_table_optimization() {
315 - return !$this->is_kinsta();
473 + public function get_webp_instance() {
474 + return WP_Optimize_WebP::get_instance();
316 475 }
317 476
318 477 /**
319 - * Detects whether the server supports local webp conversion tools
478 + * Returns instance of WP_Optimize_Server_Compatibility class.
479 + *
480 + * @return WP_Optimize_Server_Compatibility
320 481 */
321 - private function does_server_allows_local_webp_conversion() {
322 - return !$this->is_kinsta();
482 + public function get_server_compatibility_instance(): WP_Optimize_Server_Compatibility {
483 + return WP_Optimize_Server_Compatibility::get_instance();
323 484 }
324 485
325 486 /**
326 487 * Create instance of WP_Optimize_Browser_Cache.
@@ -382,8 +543,9 @@
382 543 /**
383 544 * Enqueue scripts and styles on WP-Optimize pages.
384 545 */
385 546 public function admin_enqueue_scripts() {
547 + global $wp_version;
386 548 $enqueue_version = $this->get_enqueue_version();
387 549 $min_or_not = $this->get_min_or_not_string();
388 550 $min_or_not_internal = $this->get_min_or_not_internal_string();
389 551
@@ -389,12 +551,22 @@
389 551
390 552 // Register or enqueue common scripts
391 553 wp_register_script('wp-optimize-send-command', WPO_PLUGIN_URL.'js/send-command'.$min_or_not_internal.'.js', array(), $enqueue_version);
392 554 wp_localize_script('wp-optimize-send-command', 'wp_optimize_send_command_data', array('nonce' => wp_create_nonce('wp-optimize-ajax-nonce')));
555 + wp_register_script('wp-optimize-block-ui', WPO_PLUGIN_URL.'js/blockUI'.$min_or_not_internal.'.js', array('jquery'), $enqueue_version);
393 556 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
394 557
395 558 // load scripts and styles only on WP-Optimize pages.
396 559 if (!$this->is_wpo_page()) return;
560 +
561 + wp_enqueue_script( 'jquery-ui-tooltip' );
562 + // Defeat other plugins/themes which dump their jQuery UI CSS onto our settings page
563 + wp_deregister_style('jquery-ui');
564 + wp_enqueue_style('jquery-ui', WPO_PLUGIN_URL.'css/jquery-ui.custom' . $min_or_not_internal . '.css', array(), $enqueue_version);
565 +
566 +
567 + wp_enqueue_script('select2', WPO_PLUGIN_URL . 'js/select2/select2' . $min_or_not . '.js', array('jquery'), $enqueue_version);
568 + wp_enqueue_style('select2', WPO_PLUGIN_URL . 'css/select2/select2' . $min_or_not . '.css', array(), $enqueue_version);
397 569
398 570 wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);
399 571
400 572 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
@@ -399,25 +571,35 @@
399 571
400 572 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
401 573
402 574 wp_enqueue_script('wp-optimize-modal', WPO_PLUGIN_URL.'js/modal'.$min_or_not_internal.'.js', array('jquery', 'backbone', 'wp-util'), $enqueue_version);
403 - wp_enqueue_script('wp-optimize-cache-js', WPO_PLUGIN_URL.'js/cache'.$min_or_not_internal.'.js', array('wp-optimize-send-command', 'smush-js', 'wp-optimize-heartbeat-js'), $enqueue_version);
575 + wp_enqueue_script('wp-optimize-cache-js', WPO_PLUGIN_URL.'js/cache'.$min_or_not_internal.'.js', array('wp-optimize-send-command', 'smush-js', 'wp-optimize-heartbeat-js', 'wp-optimize-block-ui'), $enqueue_version);
404 576 wp_enqueue_script('wp-optimize-admin-js', WPO_PLUGIN_URL.'js/wpoadmin'.$min_or_not_internal.'.js', array('jquery', 'updraft-queue-js', 'wp-optimize-send-command', 'smush-js', 'wp-optimize-modal', 'wp-optimize-cache-js', 'wp-optimize-heartbeat-js'), $enqueue_version);
405 577 wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
406 - // Using tablesorter to help with organising the DB size on Table Information
407 - // https://github.com/Mottie/tablesorter
408 - wp_enqueue_script('tablesorter-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter'.$min_or_not.'.js', array('jquery', 'wp-optimize-send-command'), $enqueue_version);
578 + // Using table sorter to help with organising the DB size on Table Information
579 + // https://github.com/tofsjonas/sortable/
580 + wp_enqueue_script('sortable-js', WPO_PLUGIN_URL.'js/sortable/sortable'.$min_or_not.'.js', array('wp-optimize-send-command'), $enqueue_version);
581 + wp_enqueue_script('sortable-a11y-js', WPO_PLUGIN_URL.'js/sortable/sortable.a11y'.$min_or_not.'.js', array('wp-optimize-send-command'), $enqueue_version);
409 582
410 - wp_enqueue_script('tablesorter-widgets-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter.widgets'.$min_or_not.'.js', array('jquery'), $enqueue_version);
583 + wp_enqueue_style('sortable-css', WPO_PLUGIN_URL.'css/sortable/sortable'.$min_or_not_internal.'.css', array(), $enqueue_version);
411 584
412 - // wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);
413 -
414 585 $js_variables = $this->wpo_js_translations();
415 586 $js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
416 -
417 587 wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
418 588
419 589 do_action('wpo_premium_scripts_styles', $min_or_not_internal, $min_or_not, $enqueue_version);
590 +
591 + $status_report_dependencies = array('wp-optimize-admin-js');
592 +
593 + // Only include wp-api-fetch if WP >= 5.0
594 + if (version_compare($wp_version, '5.0', '>=')) {
595 + $status_report_dependencies[] = 'wp-api-fetch';
596 + }
597 +
598 + wp_enqueue_script('wp-optimize-status-report', WPO_PLUGIN_URL.'js/status'.$min_or_not_internal.'.js', $status_report_dependencies, $enqueue_version);
599 +
600 + wp_enqueue_script('js-zip', WPO_PLUGIN_URL.'/js/jszip/jszip' . $min_or_not . '.js', array(), $enqueue_version);
601 +
420 602 }
421 603
422 604 /**
423 605 * Enqueue any required front-end scripts
@@ -424,11 +606,11 @@
424 606 *
425 607 * @return void
426 608 */
427 609 public function frontend_enqueue_scripts() {
428 - if (!current_user_can('manage_options') || !is_admin_bar_showing()) return;
610 + if (!$this->current_user_can('manage_options') || !is_admin_bar_showing()) return;
429 611 $enqueue_version = $this->get_enqueue_version();
430 - $min_or_not_internal = WP_Optimize()->get_min_or_not_internal_string();
612 + $min_or_not_internal = $this->get_min_or_not_internal_string();
431 613
432 614 // Register or enqueue common scripts
433 615 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
434 616 }
@@ -434,8 +616,10 @@
434 616 }
435 617
436 618 /**
437 619 * Load Task Manager
620 + *
621 + * @return Updraft_Smush_Manager
438 622 */
439 623 public function get_task_manager() {
440 624 include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
441 625
@@ -453,9 +637,9 @@
453 637
454 638 /**
455 639 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
456 640 *
457 - * @returns Boolean
641 + * @returns bool
458 642 */
459 643 public static function is_premium() {
460 644 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && function_exists('WP_Optimize_Premium')) {
461 645 $wp_optimize_premium = WP_Optimize_Premium();
@@ -470,9 +654,9 @@
470 654 * @return bool
471 655 */
472 656 public function is_apache_server() {
473 657 global $is_apache;
474 - return $is_apache;
658 + return (bool) $is_apache;
475 659 }
476 660
477 661 /**
478 662 * Check if script running on IIS web server.
@@ -516,12 +700,23 @@
516 700 * Checks if this is the premium version and loads it. It also ensures that if the free version is installed then it is disabled with an appropriate error message.
517 701 */
518 702 public function plugins_loaded() {
519 703
520 - if ($this->does_server_handles_cache()) {
704 + if (!$this->is_minimum_requirement_met()) {
705 + $this->add_notice_minimum_requirements_not_met();
706 + $this->deactivate_plugin();
707 + WPO_Deactivation::actions();
708 + return;
709 + }
710 +
711 + if (is_admin() && $this->current_user_can()) {
712 + WP_Optimize_Heartbeat::get_instance();
713 + }
714 +
715 + if ($this->get_server_compatibility_instance()->does_server_handle_cache()) {
521 716 add_filter('wp_optimize_admin_page_wpo_cache_tabs', array($this, 'filter_cache_tabs'), 99, 1);
522 717
523 - // If newly migrated to server that handles cache, disable wpo cache
718 + // If newly migrated to a server that handles cache, disable wpo cache
524 719 $cache = $this->get_page_cache();
525 720 if ($cache->is_enabled()) {
526 721 $cache->disable();
527 722 }
@@ -533,23 +728,28 @@
533 728 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && !class_exists('WP_Optimize_Premium')) {
534 729 include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
535 730 }
536 731
732 + if (!self::is_premium()) {
733 + $this->get_server_compatibility_instance()->maybe_disable_unsupported_table_optimization();
734 + add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
735 + }
736 +
537 737 // load defaults
538 - WP_Optimize()->get_options()->set_default_options();
738 + $this->get_options()->set_default_options();
539 739
540 740 // Initialize loggers.
541 - $this->setup_loggers();
741 + add_action('init', array($this, 'setup_loggers'));
542 742
543 743 if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
544 744 if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
545 745 deactivate_plugins($free_plugin);
546 746
547 - // If WPO_ADVANCED_CACHE is defined, we empty advanced-cache.php to regenerate later. Otherwise it contains the path to free.
747 + // If WPO_ADVANCED_CACHE is defined, we empty advanced-cache.php to regenerate later. Otherwise, it contains the path to free.
548 748 if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
549 749 $advanced_cache_filename = trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
550 750
551 - if (!is_file($advanced_cache_filename) && is_writable(dirname($advanced_cache_filename)) || (is_file($advanced_cache_filename) && is_writable($advanced_cache_filename))) {
751 + if (!is_file($advanced_cache_filename) && wp_is_writable(dirname($advanced_cache_filename)) || (is_file($advanced_cache_filename) && wp_is_writable($advanced_cache_filename))) {
552 752 file_put_contents($advanced_cache_filename, '');
553 753 }
554 754 }
555 755
@@ -557,23 +757,29 @@
557 757 add_action('admin_notices', array($this, 'show_admin_notice_premium'));
558 758 return;
559 759 }
560 760
561 - // Loads the task manager
562 - $this->get_task_manager();
761 + add_action('init', array($this, 'init'));
563 762
564 - // Loads the language file.
565 - load_plugin_textdomain('wp-optimize', false, dirname(plugin_basename(__FILE__)) . '/languages');
763 + // add_filter('updraftcentral_host_plugins', array($this, 'attach_updraftcentral_host'));
764 + // if (file_exists(WPO_PLUGIN_MAIN_PATH.'central/factory.php')) include_once(WPO_PLUGIN_MAIN_PATH.'central/factory.php');
765 + }
566 766
767 + /**
768 + * Methods needed to be run in init hook.
769 + *
770 + * @return void
771 + */
772 + public function init() {
773 + $this->load_language_file();
774 + $this->schedule_plugin_cron_tasks();
775 + $this->init_page_cache();
776 + $this->get_minify();
777 + $this->get_delay_js();
778 +
567 779 // Load 3rd party plugin compatibilities.
568 780 $this->load_compatibilities();
569 781
570 - // Load page cache.
571 - $this->get_page_cache();
572 - $this->init_page_cache();
573 -
574 - // Include minify
575 - $this->get_minify();
576 782 $this->run_updates();
577 783
578 784 // We need this here because webp can be unavailable because of server moves
579 785 // This deletes already converted webp images and original image file when a media is deleted
@@ -578,18 +784,29 @@
578 784 // We need this here because webp can be unavailable because of server moves
579 785 // This deletes already converted webp images and original image file when a media is deleted
580 786 WP_Optimize_WebP_Images::get_instance();
581 787
788 + // Loads the task manager
789 + $this->get_task_manager();
790 +
582 791 // Include WebP
583 792 if (WPO_USE_WEBP_CONVERSION) {
584 793 $this->get_webp_instance();
585 794 }
586 795
587 - // add_filter('updraftcentral_host_plugins', array($this, 'attach_updraftcentral_host'));
588 - // if (file_exists(WPO_PLUGIN_MAIN_PATH.'central/factory.php')) include_once(WPO_PLUGIN_MAIN_PATH.'central/factory.php');
796 + $this->get_onboarding()->init();
589 797 }
590 798
591 799 /**
800 + * Loads the language file.
801 + *
802 + * @return void
803 + */
804 + private function load_language_file() {
805 + load_plugin_textdomain('wp-optimize', false, dirname(plugin_basename(__FILE__)) . '/languages');
806 + }
807 +
808 + /**
592 809 * Attach this wp-optimize plugin as host of the UpdraftCentral libraries
593 810 * (e.g. "central" folder)
594 811 *
595 812 * @param array $hosts List of plugins having the "central" library integrated into them
@@ -601,9 +818,9 @@
601 818 return $hosts;
602 819 }
603 820
604 821 /**
605 - * Filter cache tabs (when it is Kinsta)
822 + * Filter cache tabs (when the server handles it or do not allow it, like Kinsta)
606 823 *
607 824 * @param array $tabs An array of tabs
608 825 *
609 826 * @return array $tabs An array of tabs
@@ -618,18 +835,18 @@
618 835
619 836 /**
620 837 * Check whether one of free/Premium is active (whether it is this instance or not)
621 838 *
622 - * @param String $which - 'free' or 'premium'
839 + * @param string $which - 'free' or 'premium'
623 840 *
624 - * @return String|Boolean - plugin path (if installed) or false if not
841 + * @return string|boolean - plugin path (if installed) or false if not
625 842 */
626 - private function is_active($which = 'free') {
843 + public function is_active($which = 'free') {
627 844 $active_plugins = $this->get_active_plugins();
628 845 foreach ($active_plugins as $file) {
629 846 if ('wp-optimize.php' == basename($file)) {
630 847 $plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
631 - if (('free' == $which && !file_exists($plugin_dir.'/premium.php')) || ('free' != $which && file_exists($plugin_dir.'/premium.php'))) return $file;
848 + if (('free' === $which && !file_exists($plugin_dir.'/premium.php')) || ('free' !== $which && file_exists($plugin_dir.'/premium.php'))) return $file;
632 849 }
633 850 }
634 851 return false;
635 852 }
@@ -636,14 +853,13 @@
636 853
637 854 /**
638 855 * Gets an array of plugins active on either the current site, or site-wide
639 856 *
640 - * @return Array - a list of plugin paths (relative to the plugin directory)
857 + * @return array - a list of plugin paths (relative to the plugin directory)
641 858 */
642 859 private function get_active_plugins() {
643 -
644 860 // Gets all active plugins on the current site
645 - $active_plugins = get_option('active_plugins');
861 + $active_plugins = (array) get_option('active_plugins', array());
646 862
647 863 if (is_multisite()) {
648 864 $network_active_plugins = get_site_option('active_sitewide_plugins');
649 865 if (!empty($network_active_plugins)) {
@@ -677,9 +893,9 @@
677 893
678 894 // Loops around each plugin available.
679 895 foreach ($get_plugins as $key => $value) {
680 896 // If the plugin name matches that of the specified name, it will gather details.
681 - if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
897 + if ($value['Name'] !== $name && $value['TextDomain'] !== $name) continue;
682 898 $plugin_info['installed'] = true;
683 899 $plugin_info['name'] = $key;
684 900 $plugin_info['version'] = $value['Version'];
685 901 if (in_array($key, $active_plugins)) {
@@ -693,10 +909,10 @@
693 909 /**
694 910 * This is a notice to show users that premium is installed
695 911 */
696 912 public function show_admin_notice_premium() {
697 - echo '<div id="wp-optimize-premium-installed-warning" class="error"><p>'.__('WP-Optimize (Free) has been de-activated, because WP-Optimize Premium is active.', 'wp-optimize').'</p></div>';
698 - if (isset($_GET['activate'])) unset($_GET['activate']);
913 + echo '<div id="wp-optimize-premium-installed-warning" class="error"><p>'.esc_html__('WP-Optimize (Free) has been de-activated, because WP-Optimize Premium is active.', 'wp-optimize').'</p></div>';
914 + if (isset($_GET['activate'])) unset($_GET['activate']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only unsetting value, not using it.
699 915 }
700 916
701 917 /**
702 918 * Show update to Premium notice for non-premium multisite.
@@ -703,9 +919,9 @@
703 919 */
704 920 public function show_multisite_update_to_premium_notice() {
705 921 if (!is_multisite() || self::is_premium()) return;
706 922
707 - echo '<p><a href="'.$this->premium_version_link.'">'.__('New feature: WP-Optimize Premium can now optimize all sites within a multisite install, not just the main one.', 'wp-optimize').'</a></p>';
923 + echo '<p><a href="'.esc_url($this->premium_version_link). '&utm_content=multisite-upsell' .'">'.esc_html__('New feature: WP-Optimize Premium can now optimize all sites within a multisite install, not just the main one.', 'wp-optimize').'</a></p>';
708 924 }
709 925
710 926 public function admin_init() {
711 927 $pagenow = $GLOBALS['pagenow'];
@@ -711,9 +927,9 @@
711 927 $pagenow = $GLOBALS['pagenow'];
712 928
713 929 $this->register_template_directories();
714 930
715 - if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
931 + if (('index.php' === $pagenow && $this->current_user_can('update_plugins')) || ('index.php' === $pagenow && defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
716 932 $options = $this->get_options();
717 933
718 934 $dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);
719 935
@@ -729,8 +945,11 @@
729 945
730 946 if ($this->is_wp_smush_installed()) {
731 947 add_filter('transient_wp-smush-conflict_check', array($this, 'modify_wp_smush_conflict_check'), 9, 1);
732 948 }
949 + if ($this->get_options()->get_option('404_detector', 0)) {
950 + WP_Optimize_Performance::get_instance($this->get_404_detector())->init();
951 + }
733 952 }
734 953
735 954 /**
736 955 * Checks whether the WP Smush plugin is active or not
@@ -756,9 +975,9 @@
756 975 return $active_plugins;
757 976 }
758 977
759 978 /**
760 - * Get the install or update notice instance
979 + * Get the installation or update notice instance
761 980 *
762 981 * @return WP_Optimize_Install_Or_Update_Notice
763 982 */
764 983 public function get_install_or_update_notice() {
@@ -775,14 +994,42 @@
775 994 $this->include_template('notices/thanks-for-using-main-dash.php', false, array(
776 995 'is_premium' => WP_Optimize::is_premium()
777 996 ));
778 997 }
779 -
998 +
999 + /**
1000 + * Returns required capability string
1001 + *
1002 + * @return string
1003 + */
780 1004 public function capability_required() {
781 - return apply_filters('wp_optimize_capability_required', 'manage_options');
1005 + $capability = is_multisite() ? 'manage_network_options' : 'manage_options';
1006 +
1007 + $filtered_capability = apply_filters('wp_optimize_capability_required', $capability);
1008 +
1009 + return is_string($filtered_capability) ? $filtered_capability : $capability;
782 1010 }
783 1011
784 1012 /**
1013 + * Check if the current user has a given capability.
1014 + * If no capability is provided, it checks for the default capability required to access WP-Optimize.
1015 + *
1016 + * @param string|null $capability The capability to check. Null = use default.
1017 + * @return bool
1018 + */
1019 + public function current_user_can($capability = null) {
1020 + if (null === $capability) {
1021 + $capability = $this->capability_required(); // falls back to default
1022 + }
1023 +
1024 + if (current_user_can($capability)) {
1025 + return true;
1026 + }
1027 +
1028 + return false;
1029 + }
1030 +
1031 + /**
785 1032 * Returns array of translations used in javascript code.
786 1033 *
787 1034 * @return array
788 1035 */
@@ -787,9 +1034,9 @@
787 1034 * @return array
788 1035 */
789 1036 public function wpo_js_translations() {
790 1037 $log_message = __('For more details, please check your logs configured in logging destinations settings.', 'wp-optimize');
791 - return apply_filters('wpo_js_translations', array(
1038 + $translations = array(
792 1039 'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
793 1040 'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
794 1041 'optimization_complete' => __('Optimization complete', 'wp-optimize'),
795 1042 'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
@@ -803,10 +1050,13 @@
803 1050 'disable' => __('Disable', 'wp-optimize'),
804 1051 'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
805 1052 'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
806 1053 'fill_all_settings_fields' => __('Before saving, you need to complete the currently incomplete settings (or remove them).', 'wp-optimize'),
1054 + // translators: %s is the table name
807 1055 'table_was_not_repaired' => __('%s was not repaired.', 'wp-optimize') . ' ' . $log_message,
1056 + // translators: %s is the table name
808 1057 'table_was_not_deleted' => __('%s was not deleted.', 'wp-optimize') . ' ' . $log_message,
1058 + // translators: %s is the table name
809 1059 'table_was_not_converted' => __('%s was not converted to InnoDB.', 'wp-optimize') . ' ' . $log_message,
810 1060 'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
811 1061 'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
812 1062 'update' => __('Update', 'wp-optimize'),
@@ -816,19 +1066,26 @@
816 1066 'current_cache_size' => __('Current cache size:', 'wp-optimize'),
817 1067 'number_of_files' => __('Number of files:', 'wp-optimize'),
818 1068 'toggle_info' => __('Show information', 'wp-optimize'),
819 1069 'delete_file' => __('Delete', 'wp-optimize'),
1070 + 'deleting' => __('Deleting...', 'wp-optimize'),
820 1071 'added_to_list' => __('Added to the list', 'wp-optimize'),
821 1072 'added_notice' => __('The file was added to the list', 'wp-optimize'),
822 1073 'save_notice' => __('Save the changes', 'wp-optimize'),
1074 + 'saving' => __('Saving...', 'wp-optimize'),
1075 + 'clearing_cache' => __('Clearing cache...', 'wp-optimize'),
1076 + 'creating_cache' => __('Creating cache...', 'wp-optimize'),
823 1077 'page_refresh' => __('Refreshing the page to reflect changes...', 'wp-optimize'),
824 1078 'cache_file_not_found' => __('Cache file was not found.', 'wp-optimize'),
825 1079 'settings_have_been_deleted_successfully' => __('WP-Optimize settings have been deleted successfully.', 'wp-optimize'),
826 1080 'loading_data' => __('Loading data...', 'wp-optimize'),
827 - 'spinner_src' => esc_attr(admin_url('images/spinner-2x.gif')),
1081 + 'spinner_src' => esc_url(admin_url('images/spinner-2x.gif')),
1082 + 'logo_src' => esc_url(WPO_PLUGIN_URL.'images/notices/wp_optimize_logo.png'),
828 1083 'settings_page_url' => is_multisite() ? network_admin_url('admin.php?page=wpo_settings') : admin_url('admin.php?page=wpo_settings'),
829 1084 'sites' => $this->get_sites(),
830 - 'user_always_ignores_table_delete_warning' => (get_user_meta(get_current_user_id(), 'wpo-ignores-table-delete-warning', true)) ? true : false,
1085 + 'user_always_ignores_table_deletion_warning' => (bool) get_user_meta(get_current_user_id(), 'wpo-ignores-table-deletion-warning', true),
1086 + 'user_always_ignores_post_meta_deletion_warning' => (bool) get_user_meta(get_current_user_id(), 'wpo-ignores-post-meta-deletion-warning', true),
1087 + 'user_always_ignores_orphaned_relationship_data_deletion_warning' => (bool) get_user_meta(get_current_user_id(), 'wpo-ignores-orphaned-relationship-data-deletion-warning', true),
831 1088 'post_meta_tweak_completed' => __('The tweak has been performed.', 'wp-optimize'),
832 1089 'no_minified_assets' => __('No minified files are present', 'wp-optimize'),
833 1090 'network_site_url' => network_site_url(),
834 1091 'export_settings_file_name' => 'wpoptimize-settings-'.sanitize_title(get_bloginfo('name')).'.json',
@@ -838,67 +1095,57 @@
838 1095 'importing_data_from' => __('This will import data from:', 'wp-optimize'),
839 1096 'exported_on' => __('Which was exported on:', 'wp-optimize'),
840 1097 'continue_import' => __('Do you want to carry out the import?', 'wp-optimize'),
841 1098 'select_destination' => __('Select destination', 'wp-optimize'),
1099 + 'show' => __('Show', 'wp-optimize'),
1100 + 'hide' => __('Hide', 'wp-optimize'),
1101 + 'please_wait' => __('Please wait a moment...', 'wp-optimize'),
1102 + 'clipboard_failed' => __('Copy to clipboard failed, please do it manually', 'wp-optimize'),
1103 + 'clipboard_success' => __('System status has been copied to the clipboard', 'wp-optimize'),
1104 + 'high_table_count_threshold' => WP_Optimizer::HIGH_TABLE_COUNT_THRESHOLD,
1105 + // translators: 1: starting table count, 2: ending table count
1106 + 'loading_tables_in_batches' => esc_html__('Loading tables %1$s to %2$s', 'wp-optimize'),
1107 + // translators: %s time to finish
1108 + 'time_left' => esc_html__('Aproximate time to finish: %s', 'wp-optimize'),
1109 + 'done_reloading' => esc_html__('Done, reloading', 'wp-optimize'),
842 1110 'show_information' => __('Show information', 'wp-optimize'),
843 1111 'hide_information' => __('Hide information', 'wp-optimize'),
844 - ));
1112 + 'data_not_available' => __('Not available', 'wp-optimize'),
1113 + 'something_wrong_try_again' => __('Something went wrong; please try again.', 'wp-optimize'),
1114 + 'db_tables_scan_pending_list' => __('Your database tables need to be scanned before they can be listed.', 'wp-optimize'),
1115 + 'db_tables_scan_pending_optimize' => __('Your database tables need to be scanned before they can be optimized.', 'wp-optimize'),
1116 + 'db_tables_scan_button' => __('Scan tables', 'wp-optimize')
1117 + );
1118 + $filtered_translations = apply_filters('wpo_js_translations', $translations);
1119 + return is_array($filtered_translations) ? $filtered_translations : $translations;
845 1120 }
846 1121
847 1122 /**
848 - * Manages the admin bar menu for caching (currently page and minify)
849 - */
850 - public function cache_admin_bar($wp_admin_bar) {
851 -
852 - $options = $this->get_options();
853 - if (!$options->get_option('enable_cache_in_admin_bar', true)) return;
854 -
855 - /**
856 - * The "purge cache" menu items
857 - *
858 - * @param array $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
859 - * @param object $wp_admin_bar
860 - */
861 - $menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);
862 -
863 - if (empty($menu_items) || !is_array($menu_items)) return;
864 -
865 - $wp_admin_bar->add_menu(array(
866 - 'id' => 'wpo_purge_cache',
867 - 'title' => __('Purge cache', 'wp-optimize'),
868 - 'href' => '#',
869 - 'meta' => array(
870 - 'title' => __('Purge cache', 'wp-optimize'),
871 - ),
872 - 'parent' => false,
873 - ));
874 -
875 - foreach ($menu_items as $item) {
876 - $wp_admin_bar->add_menu($item);
877 - }
878 - }
879 -
880 - /**
881 1123 * Add settings link on plugin page
882 1124 *
883 - * @param string $links Passing through the URL to be used within the HREF.
884 - * @return string Returns the Links.
1125 + * @param array $links Passing through the URL to be used within the HREF.
1126 + * @return array Returns the Links.
885 1127 */
886 1128 public function plugin_settings_link($links) {
887 1129
888 1130 $admin_page_url = $this->get_options()->admin_page_url();
889 1131 $settings_page_url = $this->get_options()->admin_page_url('wpo_settings');
1132 + $database_page_url = $this->get_options()->admin_page_url('wpo_database');
890 1133
891 - if (false == self::is_premium()) {
892 - $premium_link = '<a href="' . esc_url($this->premium_version_link) . '" target="_blank">' . __('Premium', 'wp-optimize') . '</a>';
1134 + if (!self::is_premium()) {
1135 + $premium_link = '<a href="' . esc_url($this->premium_version_link) . '&utm_content=plugin-page' . '" target="_blank">' . esc_html__('Premium', 'wp-optimize') . '</a>';
893 1136 array_unshift($links, $premium_link);
894 1137 }
895 1138
896 - $settings_link = '<a href="' . esc_url($settings_page_url) . '">' . __('Settings', 'wp-optimize') . '</a>';
1139 + $settings_link = '<a href="' . esc_url($settings_page_url) . '">' . esc_html__('Settings', 'wp-optimize') . '</a>';
897 1140 array_unshift($links, $settings_link);
898 1141
899 - $optimize_link = '<a href="' . esc_url($admin_page_url) . '">' . __('Optimize', 'wp-optimize') . '</a>';
1142 + $optimize_link = '<a href="' . esc_url($database_page_url) . '">' . esc_html__('Optimize', 'wp-optimize') . '</a>';
900 1143 array_unshift($links, $optimize_link);
1144 +
1145 + $dashboard_link = '<a href="' . esc_url($admin_page_url) . '">' . esc_html__('Overview', 'wp-optimize') . '</a>';
1146 + array_unshift($links, $dashboard_link);
1147 +
901 1148 return $links;
902 1149 }
903 1150
904 1151 /**
@@ -912,9 +1159,9 @@
912 1159 public function tables_list_additional_column_data($content, $table_info) {
913 1160 if ($table_info->is_needing_repair) {
914 1161 $content .= '<div class="wpo_button_wrap">'
915 1162 . '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
916 - . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1163 + . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">' // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- N/A
917 1164 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
918 1165 . '</div>';
919 1166 }
920 1167
@@ -921,18 +1168,18 @@
921 1168 // table belongs to plugin.
922 1169 if ($table_info->can_be_removed) {
923 1170 $content .= '<div>'
924 1171 . '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
925 - . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1172 + . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">' // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- N/A
926 1173 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
927 1174 . '</div>';
928 1175 }
929 1176
930 1177 // Add option for MyISAM to InnoDB conversion.
931 - if ('MyISAM' == $table_info->Engine) {
1178 + if ('MyISAM' === $table_info->Engine) {
932 1179 $content .= '<div class="wpo_button_convert wpo_button_wrap">'
933 1180 . '<button class="button button-secondary toinnodb" data-table="' . esc_attr($table_info->Name) . '">' . __('Convert to InnoDB', 'wp-optimize') . '</button>'
934 - . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1181 + . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">' // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- N/A
935 1182 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
936 1183 . '</div>';
937 1184
938 1185 }
@@ -942,9 +1189,9 @@
942 1189
943 1190 /**
944 1191 * Initialize WP-Optimize page cache.
945 1192 */
946 - public function init_page_cache() {
1193 + private function init_page_cache() {
947 1194 if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
948 1195 if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
949 1196 $this->_cache_init_status = $this->get_page_cache()->enable();
950 1197 }
@@ -953,9 +1200,9 @@
953 1200
954 1201 /**
955 1202 * Get init_page_cache() status.
956 1203 *
957 - * @return bool
1204 + * @return bool|WP_Error
958 1205 */
959 1206 public function get_init_page_cache_status() {
960 1207 return $this->_cache_init_status;
961 1208 }
@@ -969,17 +1216,17 @@
969 1216 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
970 1217
971 1218 $options = $this->get_options();
972 1219
973 - if ($options->get_option('schedule') === false) {
1220 + if (false === $options->get_option('schedule')) {
974 1221 $options->set_default_options();
975 1222 } else {
976 - if ('true' == $options->get_option('schedule')) {
1223 + if ('true' === $options->get_option('schedule')) {
977 1224 if (!wp_next_scheduled('wpo_cron_event2')) {
978 1225 $schedule_type = $options->get_option('schedule-type', 'wpo_weekly');
979 1226
980 1227 // Backward compatibility
981 - if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';
1228 + if ('wpo_otherweekly' === $schedule_type) $schedule_type = 'wpo_fortnightly';
982 1229
983 1230 $this_time = (86400 * 7);
984 1231
985 1232 switch ($schedule_type) {
@@ -1001,15 +1248,15 @@
1001 1248 }
1002 1249
1003 1250 add_action('wpo_cron_event2', array($this, 'cron_action'));
1004 1251 $result = wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
1005 - WP_Optimize()->log('running wp_schedule_event()');
1252 + $this->log('running wp_schedule_event()');
1006 1253 if (is_wp_error($result)) {
1007 1254 $error_msg = $result->get_error_message();
1008 - WP_Optimize()->log($error_msg);
1009 - WP_Optimize()->log(print_r($result, true));
1255 + $this->log($error_msg);
1256 + $this->log(print_r($result, true)); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- Using for debugging purpose, logged into separate file
1010 1257 } else {
1011 - WP_Optimize()->log($result);
1258 + $this->log($result);
1012 1259 }
1013 1260 }
1014 1261 }
1015 1262 }
@@ -1015,13 +1262,31 @@
1015 1262 }
1016 1263 }
1017 1264
1018 1265 /**
1019 - * Clears all cron events
1266 + * Unschedules WP-Optimize cron events on deactivation.
1020 1267 *
1021 1268 * @return void
1022 1269 */
1023 1270 public function wpo_cron_deactivate() {
1271 + if (is_multisite()) {
1272 + $sites = $this->get_sites();
1273 + foreach ($sites as $site) {
1274 + switch_to_blog($site->blog_id);
1275 + $this->unschedule_wpo_cron_jobs();
1276 + restore_current_blog();
1277 + }
1278 + } else {
1279 + $this->unschedule_wpo_cron_jobs();
1280 + }
1281 + }
1282 +
1283 + /**
1284 + * Unschedules all WP-Optimize cron jobs on the current site.
1285 + *
1286 + * @return void
1287 + */
1288 + private function unschedule_wpo_cron_jobs() {
1024 1289 $cron_jobs = _get_cron_array();
1025 1290 foreach ($cron_jobs as $job) {
1026 1291 foreach (array_keys($job) as $hook) {
1027 1292 if (preg_match('/^wpo_/', $hook)) wp_unschedule_hook($hook);
@@ -1067,8 +1332,12 @@
1067 1332 /**
1068 1333 * Run updates on plugin activation.
1069 1334 */
1070 1335 public function run_updates() {
1336 +
1337 + if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache');
1338 +
1339 + require_once(WPO_PLUGIN_MAIN_PATH . 'cache/file-based-page-cache-functions.php');
1071 1340 include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-updates.php');
1072 1341 WP_Optimize_Updates::check_updates();
1073 1342 }
1074 1343
@@ -1079,13 +1348,21 @@
1079 1348 * @return string
1080 1349 */
1081 1350 public function show_admin_warning_overdue_crons($howmany) {
1082 1351 $ret = '<div class="updated below-h2"><p>';
1083 - $ret .= '<strong>'.__('Warning', 'wp-optimize').':</strong> '.sprintf(__('WordPress has a number (%d) of scheduled tasks which are overdue.', 'wp-optimize'), $howmany).' '. __('Unless this is a development site, this probably means that the scheduler in your WordPress install is not working.', 'wp-optimize').' <a href="'.apply_filters('wpoptimize_com_link', "https://getwpo.com/faqs/the-scheduler-in-my-wordpress-installation-is-not-working-what-should-i-do/").'">'.__('Read this page for a guide to possible causes and how to fix it.', 'wp-optimize').'</a>';
1352 + // translators: %d is number of overdue cron jobs
1353 + $ret .= '<strong>'.esc_html__('Warning', 'wp-optimize').':</strong> '.sprintf(esc_html__('WordPress has a number (%d) of scheduled tasks which are overdue.', 'wp-optimize'), $howmany).' '. esc_html__('Unless this is a development site, this probably means that the scheduler in your WordPress install is not working.', 'wp-optimize').' <a target="_blank" href="'.esc_url(apply_filters('wpoptimize_com_link', "https://teamupdraft.com/blog/the-scheduler-in-wordpress-is-not-working-what-should-i-do/")).'">'.esc_html__('Read this page for a guide to possible causes and how to fix it.', 'wp-optimize').'</a>';
1084 1354 $ret .= '</p></div>';
1085 1355 return $ret;
1086 1356 }
1087 1357
1358 + /**
1359 + * Normalizes path string
1360 + *
1361 + * @param string $path
1362 + *
1363 + * @return string
1364 + */
1088 1365 private function wp_normalize_path($path) {
1089 1366 // Wp_normalize_path is not present before WP 3.9.
1090 1367 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1091 1368 // Taken from WP 4.6.
@@ -1096,24 +1373,38 @@
1096 1373 }
1097 1374 return $path;
1098 1375 }
1099 1376
1377 + /**
1378 + * Returns templates directory path
1379 + *
1380 + * @return string
1381 + */
1100 1382 public function get_templates_dir() {
1101 - return apply_filters('wp_optimize_templates_dir', $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'templates'));
1383 + $templates_dir = $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'templates');
1384 + $filtered_templates_dir = apply_filters('wp_optimize_templates_dir', $templates_dir);
1385 + return is_string($filtered_templates_dir) ? $filtered_templates_dir : $templates_dir;
1102 1386 }
1103 1387
1388 + /**
1389 + * Returns templates URL
1390 + *
1391 + * @return string
1392 + */
1104 1393 public function get_templates_url() {
1105 - return apply_filters('wp_optimize_templates_url', WPO_PLUGIN_URL.'templates');
1394 + $templates_url = WPO_PLUGIN_URL . 'templates';
1395 + $filtered_templates_url = apply_filters('wp_optimize_templates_url', $templates_url);
1396 + return is_string($filtered_templates_url) ? $filtered_templates_url : $templates_url;
1106 1397 }
1107 1398
1108 1399 /**
1109 1400 * Return or output view content
1110 1401 *
1111 - * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1112 - * @param Boolean $return_instead_of_echo - what to do with the results
1113 - * @param Array $extract_these - key/value pairs for substitution into the scope of the template
1402 + * @param string $path - path to template, usually relative to templates/ within the WP-O directory
1403 + * @param boolean $return_instead_of_echo - what to do with the results
1404 + * @param array $extract_these - key/value pairs for substitution into the scope of the template
1114 1405 *
1115 - * @return String|Void
1406 + * @return string|void
1116 1407 */
1117 1408 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1118 1409 if ($return_instead_of_echo) ob_start();
1119 1410
@@ -1133,10 +1424,10 @@
1133 1424
1134 1425 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1135 1426
1136 1427 if (!file_exists($template_file)) {
1137 - error_log("WP Optimize: template not found: ".$template_file);
1138 - echo __('Error:', 'wp-optimize').' '.__('template not found', 'wp-optimize')." (".$path.")";
1428 + error_log("WP Optimize: template not found: ".$template_file); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Using for debugging purpose such as incomplete installation
1429 + echo esc_html__('Error:', 'wp-optimize').' '.esc_html__('template not found', 'wp-optimize')." (".esc_html($path).")";
1139 1430 } else {
1140 1431 extract($extract_these);
1141 1432 // The following are useful variables which can be used in the template.
1142 1433 // They appear as unused, but may be used in the $template_file.
@@ -1163,9 +1454,9 @@
1163 1454 $templates_dir = $this->get_templates_dir();
1164 1455
1165 1456 if ($dh = opendir($templates_dir)) {
1166 1457 while (($file = readdir($dh)) !== false) {
1167 - if ('.' == $file || '..' == $file) continue;
1458 + if ('.' === $file || '..' === $file) continue;
1168 1459 if (is_dir($templates_dir.'/'.$file)) {
1169 1460 $template_directories[$file] = $templates_dir.'/'.$file;
1170 1461 }
1171 1462 }
@@ -1195,9 +1486,9 @@
1195 1486 * Format Bytes Into KB/MB
1196 1487 *
1197 1488 * @param mixed $bytes Number of bytes to be converted.
1198 1489 * @param integer $decimals the number of decimal digits
1199 - * @return integer return the correct format size.
1490 + * @return string return the correct format size.
1200 1491 */
1201 1492 public function format_size($bytes, $decimals = 2) {
1202 1493 if (!is_numeric($bytes)) return __('N/A', 'wp-optimize');
1203 1494
@@ -1208,9 +1499,9 @@
1208 1499 } elseif (1024 <= $bytes) {
1209 1500 $bytes = number_format($bytes / 1024, $decimals) . ' KB';
1210 1501 } elseif (1 < $bytes) {
1211 1502 $bytes = $bytes . ' bytes';
1212 - } elseif (1 == $bytes) {
1503 + } elseif (1 === (int) $bytes) {
1213 1504 $bytes = $bytes . ' byte';
1214 1505 } else {
1215 1506 $bytes = '0 bytes';
1216 1507 }
@@ -1218,15 +1509,16 @@
1218 1509 return $bytes;
1219 1510 }
1220 1511
1221 1512 /**
1222 - * Format a timestamp into a juman readable date time
1513 + * Format a timestamp into a human-readable date time
1223 1514 *
1224 - * @param int $timestamp
1515 + * @param int $timestamp Epoch timestamp to convert
1516 + * @param string $separator String separator
1225 1517 * @return string
1226 1518 */
1227 - public function format_date_time($timestamp) {
1228 - return date_i18n(get_option('date_format').' @ '.get_option('time_format'), ($timestamp + get_option('gmt_offset') * 3600));
1519 + public function format_date_time($timestamp, $separator = ' @ ') {
1520 + return date_i18n(get_option('date_format'). $separator .get_option('time_format'), ($timestamp + get_option('gmt_offset') * 3600));
1229 1521 }
1230 1522
1231 1523 /**
1232 1524 * Executed this function on cron event.
@@ -1239,9 +1531,9 @@
1239 1531 $options = $this->get_options();
1240 1532
1241 1533 $this->log('WPO: Starting cron_action()');
1242 1534 $options->update_option('last-optimized', time());
1243 - if ('true' == $options->get_option('schedule')) {
1535 + if ('true' === $options->get_option('schedule')) {
1244 1536 $this_options = $options->get_option('auto');
1245 1537
1246 1538 // Currently the output of the optimizations is not saved/used/logged.
1247 1539 $optimizer->do_optimizations($this_options, 'auto');
@@ -1253,14 +1545,17 @@
1253 1545 * Schedule cron tasks used by plugin.
1254 1546 *
1255 1547 * @return void
1256 1548 */
1257 - public function schedule_plugin_cron_tasks() {
1549 + private function schedule_plugin_cron_tasks() {
1258 1550 if (!wp_next_scheduled('wpo_weekly_cron_tasks')) {
1259 - wp_schedule_event(current_time("timestamp", 0), 'weekly', 'wpo_weekly_cron_tasks');
1551 + wp_schedule_event(current_time("timestamp", 0), 'wpo_weekly', 'wpo_weekly_cron_tasks');
1260 1552 }
1261 1553
1262 1554 add_action('wpo_weekly_cron_tasks', array($this, 'do_weekly_cron_tasks'));
1555 +
1556 + // Run 404 detector cron.
1557 + $this->get_404_detector_cron();
1263 1558 }
1264 1559
1265 1560 /**
1266 1561 * Do plugin background tasks.
@@ -1273,16 +1568,16 @@
1273 1568 }
1274 1569
1275 1570 /**
1276 1571 * This will customize a URL with a correct Affiliate link
1277 - * This function can be update to suit any URL as longs as the URL is passed
1572 + * This function can be updated to suit any URL as longs as the URL is passed
1278 1573 *
1279 - * @param String $url - URL to be check to see if it an updraftplus match.
1280 - * @param String $text - Text to be entered within the href a tags.
1281 - * @param String $html - Any specific HTML to be added. Supplied parameter will not be escaped in this function. Provide escaped, safe HTML
1282 - * @param String|Array $attrs - Specify the HTML attributes as an array or string. Use the array format for multiple attributes (e.g., array( "class" => "lorem-ipsum", "title" => "Highlighting text" )), and use the string format for a single attribute (e.g., 'class="lorem-ipsum"').
1283 - * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1284 - * @return String|void
1574 + * @param string $url - URL to check to see if it is an updraftplus match.
1575 + * @param ?string $text - Text to be entered within the href a tags.
1576 + * @param ?string $html - Any specific HTML to be added. Supplied parameter will not be escaped in this function. Provide escaped, safe HTML
1577 + * @param string|array $attrs - Specify the HTML attributes as an array or string. Use the array format for multiple attributes (e.g., array( "class" => "lorem-ipsum", "title" => "Highlighting text" )), and use the string format for a single attribute (e.g., 'class="lorem-ipsum"').
1578 + * @param bool $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1579 + * @return string|void
1285 1580 */
1286 1581 public function wp_optimize_url($url, $text = '', $html = '', $attrs = '', $return_instead_of_echo = false) {
1287 1582 // Check if the URL is UpdraftPlus.
1288 1583 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
@@ -1296,9 +1591,9 @@
1296 1591 foreach ($attrs as $attr => $value) {
1297 1592 $str_attrs .= $attr . '="' . esc_attr($value) . '" ';
1298 1593 }
1299 1594 } else {
1300 - // If $attrs is empty, the explode function will only return an empty array.
1595 + // If $attrs is empty, the `explode` function will only return an empty array.
1301 1596 $attrs = explode('=', $attrs);
1302 1597 // Check if $attrs in positions 1 and 2 are not empty and exist; otherwise, return an empty string.
1303 1598 $str_attrs = !empty($attrs[0]) && !empty($attrs[1]) ? $attrs[0] . '="' . esc_attr(str_replace('"', '', $attrs[1])) . '"' : '';
1304 1599 }
@@ -1313,13 +1608,13 @@
1313 1608 $result = sprintf(
1314 1609 '<a href="%s" %s>%s</a>',
1315 1610 esc_url($url),
1316 1611 $str_attrs,
1317 - $content
1612 + wp_kses_post($content)
1318 1613 );
1319 1614
1320 1615 if ($return_instead_of_echo) return $result;
1321 - echo $result;
1616 + echo wp_kses_post($result);
1322 1617 }
1323 1618
1324 1619 /**
1325 1620 * Check if a URL is external
@@ -1324,9 +1619,9 @@
1324 1619 /**
1325 1620 * Check if a URL is external
1326 1621 *
1327 1622 * @param string $url
1328 - * @return string
1623 + * @return bool
1329 1624 */
1330 1625 public function is_external_url($url) {
1331 1626 if (empty($url)) {
1332 1627 return false;
@@ -1339,9 +1634,9 @@
1339 1634 return $current_domain !== $url;
1340 1635 }
1341 1636
1342 1637 /**
1343 - * Get an URL with an eventual affiliate ID
1638 + * Get a URL with an eventual affiliate ID
1344 1639 *
1345 1640 * @param string $url
1346 1641 * @return string
1347 1642 */
@@ -1353,9 +1648,10 @@
1353 1648
1354 1649 // Apply filters.
1355 1650 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1356 1651 }
1357 - return apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
1652 + $filtered_url = apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
1653 + return is_string($filtered_url) ? $filtered_url : $url;
1358 1654 }
1359 1655
1360 1656 /**
1361 1657 * Setup WPO logger(s)
@@ -1416,9 +1712,9 @@
1416 1712 // check for previous version options format.
1417 1713 $keys = array_keys($saved_loggers);
1418 1714
1419 1715 // if options stored in old format then reformat it.
1420 - if (false == is_numeric($keys[0])) {
1716 + if (false === is_numeric($keys[0])) {
1421 1717 $_saved_loggers = array();
1422 1718 foreach ($saved_loggers as $logger_id => $enabled) {
1423 1719 if ($enabled) {
1424 1720 $_saved_loggers[] = $logger_id;
@@ -1449,9 +1745,9 @@
1449 1745 foreach (array_keys($logger_options) as $option_name) {
1450 1746 if (array_key_exists($option_name, $options_keys)) {
1451 1747 $options_keys[$option_name]++;
1452 1748 } else {
1453 - $options_keys[$option_name] = 0;
1749 + $options_keys[$option_name] = 0;
1454 1750 }
1455 1751
1456 1752 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
1457 1753
@@ -1476,11 +1772,10 @@
1476 1772 $loggers[] = $logger;
1477 1773 }
1478 1774 }
1479 1775
1480 - $loggers = apply_filters('wp_optimize_loggers', $loggers);
1481 -
1482 - return $loggers;
1776 + $filtered_loggers = apply_filters('wp_optimize_loggers', $loggers);
1777 + return is_array($filtered_loggers) ? $filtered_loggers : $loggers;
1483 1778 }
1484 1779
1485 1780 /**
1486 1781 * Returns associative array with logger class name in a key and path to class file in a value.
@@ -1548,17 +1843,17 @@
1548 1843 return (is_multisite() && self::is_premium());
1549 1844 }
1550 1845
1551 1846 /**
1552 - * Returns true if current user can run optimizations.
1847 + * Returns true if the current user can run optimizations.
1553 1848 *
1554 1849 * @return bool
1555 1850 */
1556 - public function can_run_optimizations() {
1851 + public function can_run_optimizations(): bool {
1557 1852 // we don't check permissions for cron jobs.
1558 1853 if (defined('DOING_CRON') && DOING_CRON) return true;
1559 1854
1560 - if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
1855 + if (self::is_premium() && false === user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
1561 1856 return true;
1562 1857 }
1563 1858
1564 1859 /**
@@ -1577,13 +1872,10 @@
1577 1872 * @return array
1578 1873 */
1579 1874 public function get_sites() {
1580 1875 $sites = array();
1581 - // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
1582 1876 if (function_exists('get_sites')) {
1583 1877 $sites = get_sites(array('network_id' => null, 'deleted' => 0, 'number' => 999999));
1584 - } elseif (function_exists('wp_get_sites')) {
1585 - $sites = wp_get_sites(array('network_id' => null, 'deleted' => 0, 'limit' => 999999));
1586 1878 }
1587 1879 return $sites;
1588 1880 }
1589 1881
@@ -1589,9 +1881,9 @@
1589 1881
1590 1882 /**
1591 1883 * Returns script memory limit in megabytes.
1592 1884 *
1593 - * @param bool $memory_limit
1885 + * @param string|bool $memory_limit
1594 1886 * @return int
1595 1887 */
1596 1888 public function get_memory_limit($memory_limit = false) {
1597 1889 // Returns in megabytes
@@ -1661,8 +1953,10 @@
1661 1953 * Converts shorthand memory notation value to bytes.
1662 1954 * From http://php.net/manual/en/function.ini-get.php
1663 1955 *
1664 1956 * @param string $val shorthand memory notation value.
1957 + *
1958 + * @return string
1665 1959 */
1666 1960 public function return_bytes($val) {
1667 1961 $val = trim($val);
1668 1962 $last = strtolower($val[strlen($val)-1]);
@@ -1694,9 +1988,9 @@
1694 1988
1695 1989 /**
1696 1990 * Close browser connection and continue script work. - Taken from UpdraftPlus
1697 1991 *
1698 - * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
1992 + * @param string $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
1699 1993 * @return void
1700 1994 */
1701 1995 public function close_browser_connection($txt = '') {
1702 1996 if (!headers_sent()) {
@@ -1708,9 +2002,9 @@
1708 2002 }
1709 2003
1710 2004 if (session_id()) session_write_close();
1711 2005 echo "\r\n\r\n";
1712 - echo $txt;
2006 + echo $txt; // phpcs:ignore WordPress.Security.EscapeOutput -- Output is already escaped
1713 2007 // These two added - 19-Feb-15 - started being required on local dev machine, for unknown reason (probably some plugin that started an output buffer).
1714 2008 $ob_level = ob_get_level();
1715 2009 while ($ob_level > 0) {
1716 2010 ob_end_flush();
@@ -1721,46 +2015,18 @@
1721 2015 if (function_exists('litespeed_finish_request')) litespeed_finish_request();
1722 2016 }
1723 2017
1724 2018 /**
1725 - * Get the current theme's style.css headers
1726 - *
1727 - * @return array|WP_Error
1728 - */
1729 - public function get_stylesheet_headers() {
1730 - static $headers;
1731 - if (isset($headers)) return $headers;
1732 -
1733 - $style = get_template_directory_uri() . '/style.css';
1734 -
1735 - /**
1736 - * Filters wp_remote_get parameters, when checking if browser cache is enabled.
1737 - *
1738 - * @param array $request_params Default parameters
1739 - */
1740 - $request_params = apply_filters('wpoptimize_get_stylesheet_headers_args', array('timeout' => 10));
1741 -
1742 - // trying to load style.css.
1743 - $response = wp_remote_get($style, $request_params);
1744 -
1745 - if (is_a($response, 'WP_Error')) return $response;
1746 -
1747 - $headers = wp_remote_retrieve_headers($response);
1748 -
1749 - if (method_exists($headers, 'getAll')) {
1750 - $headers = $headers->getAll();
1751 - }
1752 -
1753 - return is_array($headers) ? $headers : array();
1754 - }
1755 -
1756 - /**
1757 2019 * Try to change PHP script time limit.
1758 2020 */
1759 2021 public function change_time_limit() {
1760 2022 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
1761 2023
1762 - @set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
2024 + // phpcs:disable
2025 + // Generic.PHP.NoSilencedErrors.Discouraged -- Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
2026 + // Squiz.PHP.DiscouragedFunctions.Discouraged -- Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
2027 + @set_time_limit($time_limit);
2028 + // phpcs:enable
1763 2029 }
1764 2030
1765 2031 /**
1766 2032 * Does the request come from UDC
@@ -1777,11 +2043,11 @@
1777 2043 * @return boolean
1778 2044 */
1779 2045 public function template_should_include_data() {
1780 2046 /**
1781 - * Filters wether data should be included in certain templates or not.
2047 + * Filters whether data should be included in certain templates or not.
1782 2048 */
1783 - return apply_filters('wpo_template_should_include_data', $this->is_updraft_central_request());
2049 + return (bool) apply_filters('wpo_template_should_include_data', $this->is_updraft_central_request());
1784 2050 }
1785 2051
1786 2052 /**
1787 2053 * Load the templates for the modal window
@@ -1790,8 +2056,18 @@
1790 2056 $this->include_template('modal.php');
1791 2057 }
1792 2058
1793 2059 /**
2060 + * Adds compress popup template
2061 + */
2062 + public function add_smush_popup_template() {
2063 + if ($this->current_user_can()) {
2064 + $compression_server_hint = Updraft_Smush_Manager()->get_compression_server_hint();
2065 + $this->include_template('images/smush-popup.php', false, array('compression_server_hint' => $compression_server_hint));
2066 + }
2067 + }
2068 +
2069 + /**
1794 2070 * Delete transients and semaphores data from options table.
1795 2071 */
1796 2072 public function delete_transients_and_semaphores() {
1797 2073 global $wpdb;
@@ -1815,19 +2091,23 @@
1815 2091 foreach ($masks as $mask) {
1816 2092 $where_parts[] = "(`option_name` LIKE '{$mask}')";
1817 2093 }
1818 2094
1819 - $wpdb->query("DELETE FROM {$wpdb->options} WHERE " . join(' OR ', $where_parts));
2095 + $where_clause = implode(' OR ', $where_parts);
2096 + $wpdb->query($wpdb->prepare("DELETE FROM `{$wpdb->options}` WHERE %s", $where_clause));
1820 2097 }
1821 2098
1822 2099 /**
1823 2100 * Prevents bots from indexing plugins list
2101 + *
2102 + * @param string $output
2103 + * @return string
1824 2104 */
1825 2105 public function robots_txt($output) {
1826 2106 $upload_dir = wp_upload_dir();
1827 - $path = parse_url($upload_dir['baseurl']);
2107 + $path = wp_parse_url($upload_dir['baseurl']);
1828 2108 $output .= "\nUser-agent: *";
1829 - $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo-plugins-tables-list.json\n";
2109 + $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo/wpo-plugins-tables-list.json\n";
1830 2110 return $output;
1831 2111 }
1832 2112
1833 2113 /**
@@ -1861,8 +2141,49 @@
1861 2141 * Instantiate Ajax handling class
1862 2142 */
1863 2143 private function load_ajax_handler() {
1864 2144 WPO_Ajax::get_instance();
2145 + }
2146 +
2147 + /**
2148 + * Get instance of WP_Optimize_Table_Management
2149 + *
2150 + * @return WP_Optimize_Table_Management
2151 + */
2152 + public function get_table_management() {
2153 + return WP_Optimize_Table_Management::get_instance();
2154 + }
2155 +
2156 + /**
2157 + * Get instance of WP_Optimize_404_Detector
2158 + *
2159 + * @return WP_Optimize_404_Detector
2160 + */
2161 + public function get_404_detector() {
2162 + return WP_Optimize_404_Detector::get_instance();
2163 + }
2164 +
2165 + /**
2166 + * Returns the message used to notify the user that the PHP version or WordPress version doesn't meet the requirements.
2167 + *
2168 + * @return string
2169 + */
2170 + public function get_minimum_requirements_notice_message() {
2171 + // translators: %1$s is minimum required PHP version, %2$s is minimum required WordPress version
2172 + return sprintf(esc_html__('WP-Optimize requires a minimum PHP version of %1$s and WordPress version of %2$s or higher', 'wp-optimize'), esc_html(WPO_REQUIRED_PHP_VERSION), esc_html(WPO_REQUIRED_WP_VERSION));
2173 + }
2174 +
2175 + /**
2176 + * Output notice when PHP version or WordPress version is not meet for WP-Optimize.
2177 + *
2178 + * @return void
2179 + */
2180 + public function output_minimum_requirements_notice() {
2181 + ?>
2182 + <div class="notice notice-error is-dismissible">
2183 + <p><?php echo $this->get_minimum_requirements_notice_message(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is already escaped ?></p>
2184 + </div>
2185 + <?php
1865 2186 }
1866 2187 }
1867 2188
1868 2189 /**