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 +554 -209 3.7.0 → 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.7.0
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 10 Author: TeamUpdraft, DavidAnderson
9 -Author URI: https://updraftplus.com
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.7.0');
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,12 +262,17 @@
146 262 return array(
147 263 'cache',
148 264 'compatibility',
149 265 'includes',
266 + 'includes/tables',
150 267 'includes/list-tables',
268 + 'includes/dashboard',
269 + 'includes/gravatars',
270 + 'includes/lcp',
151 271 'minify',
152 272 'optimizations',
153 273 'webp',
274 + 'includes/updraftcentral',
154 275 );
155 276 }
156 277
157 278 /**
@@ -161,8 +282,17 @@
161 282 $this->get_admin_instance();
162 283 }
163 284
164 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 + /**
165 295 * Returns Admin class instance
166 296 *
167 297 * @return WP_Optimize_Admin
168 298 */
@@ -183,11 +313,23 @@
183 313 $should_purge_cache = false;
184 314 $skin = $upgrader_object->skin;
185 315 if ('plugin' === $options['type']) {
186 316 // A plugin is updated using the default update system (upgrader_overwrote_package is used for the upload method)
187 - if (property_exists($skin, 'plugin_active') && $skin->plugin_active) {
188 - $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'];
189 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 + }
190 332 } elseif ('theme' === $options['type']) {
191 333 $active_theme = get_stylesheet();
192 334 $parent_theme = get_template();
193 335 // A theme is updated using the upload system
@@ -193,9 +335,9 @@
193 335 // A theme is updated using the upload system
194 336 if (isset($options['action']) && 'install' === $options['action'] && isset($skin->options['overwrite']) && 'update-theme' === $skin->options['overwrite']) {
195 337 $updated_theme = $upgrader_object->result['destination_name'];
196 338 // Check if the theme is in use
197 - if ($active_theme == $updated_theme || $parent_theme == $updated_theme) {
339 + if ($active_theme === $updated_theme || $parent_theme === $updated_theme) {
198 340 $should_purge_cache = true;
199 341 }
200 342 // A theme is updated using the classic update system
201 343 } elseif (isset($options['action']) && 'update' === $options['action'] && isset($options['themes']) && is_array($options['themes'])) {
@@ -224,11 +366,12 @@
224 366
225 367 public function admin_page_wpo_images_smush() {
226 368 $options = Updraft_Smush_Manager()->get_smush_options();
227 369 $custom = 90 >= $options['image_quality'] && 65 <= $options['image_quality'];
228 - $sites = WP_Optimize()->get_sites();
229 - $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()));
230 - $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();
231 374 }
232 375
233 376 public static function instance() {
234 377 if (empty(self::$_instance)) {
@@ -244,13 +387,29 @@
244 387 /**
245 388 * Adds 3rd party plugin compatibilities.
246 389 */
247 390 public function load_compatibilities() {
248 - 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 +
249 401 WPO_Page_Builder_Compatibility::instance();
250 - WPO_Custom_Permalink_Compatibility::instance();
251 - WPO_TranslatePress_Compatibility::instance();
402 + WPO_KD_Submissions_Compatibility::instance();
252 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 +
253 412 do_action('wpo_load_compatibilities');
254 413 }
255 414
256 415 /**
@@ -270,58 +429,59 @@
270 429 return WP_Optimize_Notices::instance();
271 430 }
272 431
273 432 /**
274 - * Returns instance if WPO_Page_Cache class.
433 + * Get and instantiate WP_Optimize_Delay_JS
275 434 *
276 - * @return WPO_Page_Cache
435 + * @return WP_Optimize_Delay_JS
277 436 */
278 - public function get_page_cache() {
279 - return WPO_Page_Cache::instance();
437 + private function get_delay_js() {
438 + return WP_Optimize_Delay_JS::instance();
280 439 }
281 440
282 441 /**
283 - * Returns instance if WP_Optimize_WebP class.
442 + * Returns instance of WPO_Page_Optimizer class.
284 443 *
285 - * @return WP_Optimize_WebP
444 + * @return WPO_Page_Optimizer
286 445 */
287 - public function get_webp_instance() {
288 - return WP_Optimize_WebP::get_instance();
446 + public function get_page_optimizer() {
447 + return WPO_Page_Optimizer::instance();
289 448 }
290 449
291 450 /**
292 - * Detects if the platform is Kinsta or not
451 + * Returns instance 404 Detector Cron class.
293 452 *
294 - * @return bool Returns true if it is Kinsta platform, otherwise returns false
453 + * @return WP_Optimize_404_Detector_Cron
295 454 */
296 - private function is_kinsta() {
297 - return isset($_SERVER['KINSTA_CACHE_ZONE']);
455 + private function get_404_detector_cron() {
456 + return WP_Optimize_404_Detector_Cron::get_instance();
298 457 }
299 458
300 459 /**
301 - * Detects whether the server handles cache. eg. Nginx cache
460 + * Returns instance of WPO_Page_Cache class.
461 + *
462 + * @return WPO_Page_Cache
302 463 */
303 - public function does_server_handles_cache() {
304 - return $this->is_kinsta();
464 + public function get_page_cache() {
465 + return WPO_Page_Cache::instance();
305 466 }
306 467
307 468 /**
308 - * Detects whether the server supports table optimization.
469 + * Returns instance of WP_Optimize_WebP class.
309 470 *
310 - * Some servers prevent table optimization
311 - * because InnoDB engine does not optimize table
312 - * instead it drops tables and recreate them
313 - * which results in elevated disk write operations
471 + * @return WP_Optimize_WebP
314 472 */
315 - public function does_server_allows_table_optimization() {
316 - return !$this->is_kinsta();
473 + public function get_webp_instance() {
474 + return WP_Optimize_WebP::get_instance();
317 475 }
318 476
319 477 /**
320 - * 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
321 481 */
322 - private function does_server_allows_local_webp_conversion() {
323 - return !$this->is_kinsta();
482 + public function get_server_compatibility_instance(): WP_Optimize_Server_Compatibility {
483 + return WP_Optimize_Server_Compatibility::get_instance();
324 484 }
325 485
326 486 /**
327 487 * Create instance of WP_Optimize_Browser_Cache.
@@ -383,8 +543,9 @@
383 543 /**
384 544 * Enqueue scripts and styles on WP-Optimize pages.
385 545 */
386 546 public function admin_enqueue_scripts() {
547 + global $wp_version;
387 548 $enqueue_version = $this->get_enqueue_version();
388 549 $min_or_not = $this->get_min_or_not_string();
389 550 $min_or_not_internal = $this->get_min_or_not_internal_string();
390 551
@@ -395,8 +556,17 @@
395 556 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
396 557
397 558 // load scripts and styles only on WP-Optimize pages.
398 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);
399 569
400 570 wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);
401 571
402 572 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
@@ -404,22 +574,32 @@
404 574 wp_enqueue_script('wp-optimize-modal', WPO_PLUGIN_URL.'js/modal'.$min_or_not_internal.'.js', array('jquery', 'backbone', 'wp-util'), $enqueue_version);
405 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);
406 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);
407 577 wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
408 - // Using tablesorter to help with organising the DB size on Table Information
409 - // https://github.com/Mottie/tablesorter
410 - 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);
411 582
412 - 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);
413 584
414 - // wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);
415 -
416 585 $js_variables = $this->wpo_js_translations();
417 586 $js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
418 -
419 587 wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
420 588
421 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 +
422 602 }
423 603
424 604 /**
425 605 * Enqueue any required front-end scripts
@@ -426,11 +606,11 @@
426 606 *
427 607 * @return void
428 608 */
429 609 public function frontend_enqueue_scripts() {
430 - if (!current_user_can('manage_options') || !is_admin_bar_showing()) return;
610 + if (!$this->current_user_can('manage_options') || !is_admin_bar_showing()) return;
431 611 $enqueue_version = $this->get_enqueue_version();
432 - $min_or_not_internal = WP_Optimize()->get_min_or_not_internal_string();
612 + $min_or_not_internal = $this->get_min_or_not_internal_string();
433 613
434 614 // Register or enqueue common scripts
435 615 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
436 616 }
@@ -436,8 +616,10 @@
436 616 }
437 617
438 618 /**
439 619 * Load Task Manager
620 + *
621 + * @return Updraft_Smush_Manager
440 622 */
441 623 public function get_task_manager() {
442 624 include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
443 625
@@ -455,9 +637,9 @@
455 637
456 638 /**
457 639 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
458 640 *
459 - * @returns Boolean
641 + * @returns bool
460 642 */
461 643 public static function is_premium() {
462 644 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && function_exists('WP_Optimize_Premium')) {
463 645 $wp_optimize_premium = WP_Optimize_Premium();
@@ -472,9 +654,9 @@
472 654 * @return bool
473 655 */
474 656 public function is_apache_server() {
475 657 global $is_apache;
476 - return $is_apache;
658 + return (bool) $is_apache;
477 659 }
478 660
479 661 /**
480 662 * Check if script running on IIS web server.
@@ -518,12 +700,23 @@
518 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.
519 701 */
520 702 public function plugins_loaded() {
521 703
522 - 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()) {
523 716 add_filter('wp_optimize_admin_page_wpo_cache_tabs', array($this, 'filter_cache_tabs'), 99, 1);
524 717
525 - // If newly migrated to server that handles cache, disable wpo cache
718 + // If newly migrated to a server that handles cache, disable wpo cache
526 719 $cache = $this->get_page_cache();
527 720 if ($cache->is_enabled()) {
528 721 $cache->disable();
529 722 }
@@ -535,23 +728,28 @@
535 728 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && !class_exists('WP_Optimize_Premium')) {
536 729 include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
537 730 }
538 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 +
539 737 // load defaults
540 - WP_Optimize()->get_options()->set_default_options();
738 + $this->get_options()->set_default_options();
541 739
542 740 // Initialize loggers.
543 - $this->setup_loggers();
741 + add_action('init', array($this, 'setup_loggers'));
544 742
545 743 if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
546 744 if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
547 745 deactivate_plugins($free_plugin);
548 746
549 - // 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.
550 748 if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
551 749 $advanced_cache_filename = trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
552 750
553 - 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))) {
554 752 file_put_contents($advanced_cache_filename, '');
555 753 }
556 754 }
557 755
@@ -559,23 +757,29 @@
559 757 add_action('admin_notices', array($this, 'show_admin_notice_premium'));
560 758 return;
561 759 }
562 760
563 - // Loads the task manager
564 - $this->get_task_manager();
761 + add_action('init', array($this, 'init'));
565 762
566 - // Loads the language file.
567 - 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 + }
568 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 +
569 779 // Load 3rd party plugin compatibilities.
570 780 $this->load_compatibilities();
571 781
572 - // Load page cache.
573 - $this->get_page_cache();
574 - $this->init_page_cache();
575 -
576 - // Include minify
577 - $this->get_minify();
578 782 $this->run_updates();
579 783
580 784 // We need this here because webp can be unavailable because of server moves
581 785 // This deletes already converted webp images and original image file when a media is deleted
@@ -580,18 +784,29 @@
580 784 // We need this here because webp can be unavailable because of server moves
581 785 // This deletes already converted webp images and original image file when a media is deleted
582 786 WP_Optimize_WebP_Images::get_instance();
583 787
788 + // Loads the task manager
789 + $this->get_task_manager();
790 +
584 791 // Include WebP
585 792 if (WPO_USE_WEBP_CONVERSION) {
586 793 $this->get_webp_instance();
587 794 }
588 795
589 - // add_filter('updraftcentral_host_plugins', array($this, 'attach_updraftcentral_host'));
590 - // if (file_exists(WPO_PLUGIN_MAIN_PATH.'central/factory.php')) include_once(WPO_PLUGIN_MAIN_PATH.'central/factory.php');
796 + $this->get_onboarding()->init();
591 797 }
592 798
593 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 + /**
594 809 * Attach this wp-optimize plugin as host of the UpdraftCentral libraries
595 810 * (e.g. "central" folder)
596 811 *
597 812 * @param array $hosts List of plugins having the "central" library integrated into them
@@ -603,9 +818,9 @@
603 818 return $hosts;
604 819 }
605 820
606 821 /**
607 - * Filter cache tabs (when it is Kinsta)
822 + * Filter cache tabs (when the server handles it or do not allow it, like Kinsta)
608 823 *
609 824 * @param array $tabs An array of tabs
610 825 *
611 826 * @return array $tabs An array of tabs
@@ -620,18 +835,18 @@
620 835
621 836 /**
622 837 * Check whether one of free/Premium is active (whether it is this instance or not)
623 838 *
624 - * @param String $which - 'free' or 'premium'
839 + * @param string $which - 'free' or 'premium'
625 840 *
626 - * @return String|Boolean - plugin path (if installed) or false if not
841 + * @return string|boolean - plugin path (if installed) or false if not
627 842 */
628 - private function is_active($which = 'free') {
843 + public function is_active($which = 'free') {
629 844 $active_plugins = $this->get_active_plugins();
630 845 foreach ($active_plugins as $file) {
631 846 if ('wp-optimize.php' == basename($file)) {
632 847 $plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
633 - 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;
634 849 }
635 850 }
636 851 return false;
637 852 }
@@ -638,14 +853,13 @@
638 853
639 854 /**
640 855 * Gets an array of plugins active on either the current site, or site-wide
641 856 *
642 - * @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)
643 858 */
644 859 private function get_active_plugins() {
645 -
646 860 // Gets all active plugins on the current site
647 - $active_plugins = get_option('active_plugins');
861 + $active_plugins = (array) get_option('active_plugins', array());
648 862
649 863 if (is_multisite()) {
650 864 $network_active_plugins = get_site_option('active_sitewide_plugins');
651 865 if (!empty($network_active_plugins)) {
@@ -679,9 +893,9 @@
679 893
680 894 // Loops around each plugin available.
681 895 foreach ($get_plugins as $key => $value) {
682 896 // If the plugin name matches that of the specified name, it will gather details.
683 - if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
897 + if ($value['Name'] !== $name && $value['TextDomain'] !== $name) continue;
684 898 $plugin_info['installed'] = true;
685 899 $plugin_info['name'] = $key;
686 900 $plugin_info['version'] = $value['Version'];
687 901 if (in_array($key, $active_plugins)) {
@@ -695,10 +909,10 @@
695 909 /**
696 910 * This is a notice to show users that premium is installed
697 911 */
698 912 public function show_admin_notice_premium() {
699 - 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>';
700 - 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.
701 915 }
702 916
703 917 /**
704 918 * Show update to Premium notice for non-premium multisite.
@@ -705,9 +919,9 @@
705 919 */
706 920 public function show_multisite_update_to_premium_notice() {
707 921 if (!is_multisite() || self::is_premium()) return;
708 922
709 - 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>';
710 924 }
711 925
712 926 public function admin_init() {
713 927 $pagenow = $GLOBALS['pagenow'];
@@ -713,9 +927,9 @@
713 927 $pagenow = $GLOBALS['pagenow'];
714 928
715 929 $this->register_template_directories();
716 930
717 - 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)) {
718 932 $options = $this->get_options();
719 933
720 934 $dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);
721 935
@@ -731,8 +945,11 @@
731 945
732 946 if ($this->is_wp_smush_installed()) {
733 947 add_filter('transient_wp-smush-conflict_check', array($this, 'modify_wp_smush_conflict_check'), 9, 1);
734 948 }
949 + if ($this->get_options()->get_option('404_detector', 0)) {
950 + WP_Optimize_Performance::get_instance($this->get_404_detector())->init();
951 + }
735 952 }
736 953
737 954 /**
738 955 * Checks whether the WP Smush plugin is active or not
@@ -758,9 +975,9 @@
758 975 return $active_plugins;
759 976 }
760 977
761 978 /**
762 - * Get the install or update notice instance
979 + * Get the installation or update notice instance
763 980 *
764 981 * @return WP_Optimize_Install_Or_Update_Notice
765 982 */
766 983 public function get_install_or_update_notice() {
@@ -777,14 +994,42 @@
777 994 $this->include_template('notices/thanks-for-using-main-dash.php', false, array(
778 995 'is_premium' => WP_Optimize::is_premium()
779 996 ));
780 997 }
781 -
998 +
999 + /**
1000 + * Returns required capability string
1001 + *
1002 + * @return string
1003 + */
782 1004 public function capability_required() {
783 - 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;
784 1010 }
785 1011
786 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 + /**
787 1032 * Returns array of translations used in javascript code.
788 1033 *
789 1034 * @return array
790 1035 */
@@ -789,9 +1034,9 @@
789 1034 * @return array
790 1035 */
791 1036 public function wpo_js_translations() {
792 1037 $log_message = __('For more details, please check your logs configured in logging destinations settings.', 'wp-optimize');
793 - return apply_filters('wpo_js_translations', array(
1038 + $translations = array(
794 1039 'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
795 1040 'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
796 1041 'optimization_complete' => __('Optimization complete', 'wp-optimize'),
797 1042 'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
@@ -805,10 +1050,13 @@
805 1050 'disable' => __('Disable', 'wp-optimize'),
806 1051 'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
807 1052 'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
808 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
809 1055 'table_was_not_repaired' => __('%s was not repaired.', 'wp-optimize') . ' ' . $log_message,
1056 + // translators: %s is the table name
810 1057 'table_was_not_deleted' => __('%s was not deleted.', 'wp-optimize') . ' ' . $log_message,
1058 + // translators: %s is the table name
811 1059 'table_was_not_converted' => __('%s was not converted to InnoDB.', 'wp-optimize') . ' ' . $log_message,
812 1060 'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
813 1061 'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
814 1062 'update' => __('Update', 'wp-optimize'),
@@ -833,9 +1081,11 @@
833 1081 'spinner_src' => esc_url(admin_url('images/spinner-2x.gif')),
834 1082 'logo_src' => esc_url(WPO_PLUGIN_URL.'images/notices/wp_optimize_logo.png'),
835 1083 'settings_page_url' => is_multisite() ? network_admin_url('admin.php?page=wpo_settings') : admin_url('admin.php?page=wpo_settings'),
836 1084 'sites' => $this->get_sites(),
837 - '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),
838 1088 'post_meta_tweak_completed' => __('The tweak has been performed.', 'wp-optimize'),
839 1089 'no_minified_assets' => __('No minified files are present', 'wp-optimize'),
840 1090 'network_site_url' => network_site_url(),
841 1091 'export_settings_file_name' => 'wpoptimize-settings-'.sanitize_title(get_bloginfo('name')).'.json',
@@ -845,68 +1095,57 @@
845 1095 'importing_data_from' => __('This will import data from:', 'wp-optimize'),
846 1096 'exported_on' => __('Which was exported on:', 'wp-optimize'),
847 1097 'continue_import' => __('Do you want to carry out the import?', 'wp-optimize'),
848 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'),
849 1110 'show_information' => __('Show information', 'wp-optimize'),
850 1111 'hide_information' => __('Hide information', 'wp-optimize'),
851 - 'please_wait' => __('Please wait...', 'wp-optimize')
852 - ));
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;
853 1120 }
854 1121
855 1122 /**
856 - * Manages the admin bar menu for caching (currently page and minify)
857 - */
858 - public function cache_admin_bar($wp_admin_bar) {
859 -
860 - $options = $this->get_options();
861 - if (!$options->get_option('enable_cache_in_admin_bar', true)) return;
862 -
863 - /**
864 - * The "purge cache" menu items
865 - *
866 - * @param array $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
867 - * @param object $wp_admin_bar
868 - */
869 - $menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);
870 -
871 - if (empty($menu_items) || !is_array($menu_items)) return;
872 -
873 - $wp_admin_bar->add_menu(array(
874 - 'id' => 'wpo_purge_cache',
875 - 'title' => __('Purge cache', 'wp-optimize'),
876 - 'href' => '#',
877 - 'meta' => array(
878 - 'title' => __('Purge cache', 'wp-optimize'),
879 - ),
880 - 'parent' => false,
881 - ));
882 -
883 - foreach ($menu_items as $item) {
884 - $wp_admin_bar->add_menu($item);
885 - }
886 - }
887 -
888 - /**
889 1123 * Add settings link on plugin page
890 1124 *
891 - * @param string $links Passing through the URL to be used within the HREF.
892 - * @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.
893 1127 */
894 1128 public function plugin_settings_link($links) {
895 1129
896 1130 $admin_page_url = $this->get_options()->admin_page_url();
897 1131 $settings_page_url = $this->get_options()->admin_page_url('wpo_settings');
1132 + $database_page_url = $this->get_options()->admin_page_url('wpo_database');
898 1133
899 - if (false == self::is_premium()) {
900 - $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>';
901 1136 array_unshift($links, $premium_link);
902 1137 }
903 1138
904 - $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>';
905 1140 array_unshift($links, $settings_link);
906 1141
907 - $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>';
908 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 +
909 1148 return $links;
910 1149 }
911 1150
912 1151 /**
@@ -920,9 +1159,9 @@
920 1159 public function tables_list_additional_column_data($content, $table_info) {
921 1160 if ($table_info->is_needing_repair) {
922 1161 $content .= '<div class="wpo_button_wrap">'
923 1162 . '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
924 - . '<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
925 1164 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
926 1165 . '</div>';
927 1166 }
928 1167
@@ -929,18 +1168,18 @@
929 1168 // table belongs to plugin.
930 1169 if ($table_info->can_be_removed) {
931 1170 $content .= '<div>'
932 1171 . '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
933 - . '<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
934 1173 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
935 1174 . '</div>';
936 1175 }
937 1176
938 1177 // Add option for MyISAM to InnoDB conversion.
939 - if ('MyISAM' == $table_info->Engine) {
1178 + if ('MyISAM' === $table_info->Engine) {
940 1179 $content .= '<div class="wpo_button_convert wpo_button_wrap">'
941 1180 . '<button class="button button-secondary toinnodb" data-table="' . esc_attr($table_info->Name) . '">' . __('Convert to InnoDB', 'wp-optimize') . '</button>'
942 - . '<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
943 1182 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
944 1183 . '</div>';
945 1184
946 1185 }
@@ -950,9 +1189,9 @@
950 1189
951 1190 /**
952 1191 * Initialize WP-Optimize page cache.
953 1192 */
954 - public function init_page_cache() {
1193 + private function init_page_cache() {
955 1194 if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
956 1195 if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
957 1196 $this->_cache_init_status = $this->get_page_cache()->enable();
958 1197 }
@@ -961,9 +1200,9 @@
961 1200
962 1201 /**
963 1202 * Get init_page_cache() status.
964 1203 *
965 - * @return bool
1204 + * @return bool|WP_Error
966 1205 */
967 1206 public function get_init_page_cache_status() {
968 1207 return $this->_cache_init_status;
969 1208 }
@@ -977,17 +1216,17 @@
977 1216 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
978 1217
979 1218 $options = $this->get_options();
980 1219
981 - if ($options->get_option('schedule') === false) {
1220 + if (false === $options->get_option('schedule')) {
982 1221 $options->set_default_options();
983 1222 } else {
984 - if ('true' == $options->get_option('schedule')) {
1223 + if ('true' === $options->get_option('schedule')) {
985 1224 if (!wp_next_scheduled('wpo_cron_event2')) {
986 1225 $schedule_type = $options->get_option('schedule-type', 'wpo_weekly');
987 1226
988 1227 // Backward compatibility
989 - if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';
1228 + if ('wpo_otherweekly' === $schedule_type) $schedule_type = 'wpo_fortnightly';
990 1229
991 1230 $this_time = (86400 * 7);
992 1231
993 1232 switch ($schedule_type) {
@@ -1009,15 +1248,15 @@
1009 1248 }
1010 1249
1011 1250 add_action('wpo_cron_event2', array($this, 'cron_action'));
1012 1251 $result = wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
1013 - WP_Optimize()->log('running wp_schedule_event()');
1252 + $this->log('running wp_schedule_event()');
1014 1253 if (is_wp_error($result)) {
1015 1254 $error_msg = $result->get_error_message();
1016 - WP_Optimize()->log($error_msg);
1017 - 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
1018 1257 } else {
1019 - WP_Optimize()->log($result);
1258 + $this->log($result);
1020 1259 }
1021 1260 }
1022 1261 }
1023 1262 }
@@ -1023,13 +1262,31 @@
1023 1262 }
1024 1263 }
1025 1264
1026 1265 /**
1027 - * Clears all cron events
1266 + * Unschedules WP-Optimize cron events on deactivation.
1028 1267 *
1029 1268 * @return void
1030 1269 */
1031 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() {
1032 1289 $cron_jobs = _get_cron_array();
1033 1290 foreach ($cron_jobs as $job) {
1034 1291 foreach (array_keys($job) as $hook) {
1035 1292 if (preg_match('/^wpo_/', $hook)) wp_unschedule_hook($hook);
@@ -1075,8 +1332,12 @@
1075 1332 /**
1076 1333 * Run updates on plugin activation.
1077 1334 */
1078 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');
1079 1340 include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-updates.php');
1080 1341 WP_Optimize_Updates::check_updates();
1081 1342 }
1082 1343
@@ -1087,13 +1348,21 @@
1087 1348 * @return string
1088 1349 */
1089 1350 public function show_admin_warning_overdue_crons($howmany) {
1090 1351 $ret = '<div class="updated below-h2"><p>';
1091 - $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>';
1092 1354 $ret .= '</p></div>';
1093 1355 return $ret;
1094 1356 }
1095 1357
1358 + /**
1359 + * Normalizes path string
1360 + *
1361 + * @param string $path
1362 + *
1363 + * @return string
1364 + */
1096 1365 private function wp_normalize_path($path) {
1097 1366 // Wp_normalize_path is not present before WP 3.9.
1098 1367 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1099 1368 // Taken from WP 4.6.
@@ -1104,24 +1373,38 @@
1104 1373 }
1105 1374 return $path;
1106 1375 }
1107 1376
1377 + /**
1378 + * Returns templates directory path
1379 + *
1380 + * @return string
1381 + */
1108 1382 public function get_templates_dir() {
1109 - 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;
1110 1386 }
1111 1387
1388 + /**
1389 + * Returns templates URL
1390 + *
1391 + * @return string
1392 + */
1112 1393 public function get_templates_url() {
1113 - 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;
1114 1397 }
1115 1398
1116 1399 /**
1117 1400 * Return or output view content
1118 1401 *
1119 - * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1120 - * @param Boolean $return_instead_of_echo - what to do with the results
1121 - * @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
1122 1405 *
1123 - * @return String|Void
1406 + * @return string|void
1124 1407 */
1125 1408 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1126 1409 if ($return_instead_of_echo) ob_start();
1127 1410
@@ -1141,10 +1424,10 @@
1141 1424
1142 1425 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1143 1426
1144 1427 if (!file_exists($template_file)) {
1145 - error_log("WP Optimize: template not found: ".$template_file);
1146 - 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).")";
1147 1430 } else {
1148 1431 extract($extract_these);
1149 1432 // The following are useful variables which can be used in the template.
1150 1433 // They appear as unused, but may be used in the $template_file.
@@ -1171,9 +1454,9 @@
1171 1454 $templates_dir = $this->get_templates_dir();
1172 1455
1173 1456 if ($dh = opendir($templates_dir)) {
1174 1457 while (($file = readdir($dh)) !== false) {
1175 - if ('.' == $file || '..' == $file) continue;
1458 + if ('.' === $file || '..' === $file) continue;
1176 1459 if (is_dir($templates_dir.'/'.$file)) {
1177 1460 $template_directories[$file] = $templates_dir.'/'.$file;
1178 1461 }
1179 1462 }
@@ -1203,9 +1486,9 @@
1203 1486 * Format Bytes Into KB/MB
1204 1487 *
1205 1488 * @param mixed $bytes Number of bytes to be converted.
1206 1489 * @param integer $decimals the number of decimal digits
1207 - * @return integer return the correct format size.
1490 + * @return string return the correct format size.
1208 1491 */
1209 1492 public function format_size($bytes, $decimals = 2) {
1210 1493 if (!is_numeric($bytes)) return __('N/A', 'wp-optimize');
1211 1494
@@ -1216,9 +1499,9 @@
1216 1499 } elseif (1024 <= $bytes) {
1217 1500 $bytes = number_format($bytes / 1024, $decimals) . ' KB';
1218 1501 } elseif (1 < $bytes) {
1219 1502 $bytes = $bytes . ' bytes';
1220 - } elseif (1 == $bytes) {
1503 + } elseif (1 === (int) $bytes) {
1221 1504 $bytes = $bytes . ' byte';
1222 1505 } else {
1223 1506 $bytes = '0 bytes';
1224 1507 }
@@ -1226,15 +1509,16 @@
1226 1509 return $bytes;
1227 1510 }
1228 1511
1229 1512 /**
1230 - * Format a timestamp into a juman readable date time
1513 + * Format a timestamp into a human-readable date time
1231 1514 *
1232 - * @param int $timestamp
1515 + * @param int $timestamp Epoch timestamp to convert
1516 + * @param string $separator String separator
1233 1517 * @return string
1234 1518 */
1235 - public function format_date_time($timestamp) {
1236 - 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));
1237 1521 }
1238 1522
1239 1523 /**
1240 1524 * Executed this function on cron event.
@@ -1247,9 +1531,9 @@
1247 1531 $options = $this->get_options();
1248 1532
1249 1533 $this->log('WPO: Starting cron_action()');
1250 1534 $options->update_option('last-optimized', time());
1251 - if ('true' == $options->get_option('schedule')) {
1535 + if ('true' === $options->get_option('schedule')) {
1252 1536 $this_options = $options->get_option('auto');
1253 1537
1254 1538 // Currently the output of the optimizations is not saved/used/logged.
1255 1539 $optimizer->do_optimizations($this_options, 'auto');
@@ -1261,14 +1545,17 @@
1261 1545 * Schedule cron tasks used by plugin.
1262 1546 *
1263 1547 * @return void
1264 1548 */
1265 - public function schedule_plugin_cron_tasks() {
1549 + private function schedule_plugin_cron_tasks() {
1266 1550 if (!wp_next_scheduled('wpo_weekly_cron_tasks')) {
1267 - 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');
1268 1552 }
1269 1553
1270 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();
1271 1558 }
1272 1559
1273 1560 /**
1274 1561 * Do plugin background tasks.
@@ -1281,16 +1568,16 @@
1281 1568 }
1282 1569
1283 1570 /**
1284 1571 * This will customize a URL with a correct Affiliate link
1285 - * 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
1286 1573 *
1287 - * @param String $url - URL to be check to see if it an updraftplus match.
1288 - * @param String $text - Text to be entered within the href a tags.
1289 - * @param String $html - Any specific HTML to be added. Supplied parameter will not be escaped in this function. Provide escaped, safe HTML
1290 - * @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"').
1291 - * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1292 - * @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
1293 1580 */
1294 1581 public function wp_optimize_url($url, $text = '', $html = '', $attrs = '', $return_instead_of_echo = false) {
1295 1582 // Check if the URL is UpdraftPlus.
1296 1583 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
@@ -1304,9 +1591,9 @@
1304 1591 foreach ($attrs as $attr => $value) {
1305 1592 $str_attrs .= $attr . '="' . esc_attr($value) . '" ';
1306 1593 }
1307 1594 } else {
1308 - // 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.
1309 1596 $attrs = explode('=', $attrs);
1310 1597 // Check if $attrs in positions 1 and 2 are not empty and exist; otherwise, return an empty string.
1311 1598 $str_attrs = !empty($attrs[0]) && !empty($attrs[1]) ? $attrs[0] . '="' . esc_attr(str_replace('"', '', $attrs[1])) . '"' : '';
1312 1599 }
@@ -1321,13 +1608,13 @@
1321 1608 $result = sprintf(
1322 1609 '<a href="%s" %s>%s</a>',
1323 1610 esc_url($url),
1324 1611 $str_attrs,
1325 - $content
1612 + wp_kses_post($content)
1326 1613 );
1327 1614
1328 1615 if ($return_instead_of_echo) return $result;
1329 - echo $result;
1616 + echo wp_kses_post($result);
1330 1617 }
1331 1618
1332 1619 /**
1333 1620 * Check if a URL is external
@@ -1332,9 +1619,9 @@
1332 1619 /**
1333 1620 * Check if a URL is external
1334 1621 *
1335 1622 * @param string $url
1336 - * @return string
1623 + * @return bool
1337 1624 */
1338 1625 public function is_external_url($url) {
1339 1626 if (empty($url)) {
1340 1627 return false;
@@ -1347,9 +1634,9 @@
1347 1634 return $current_domain !== $url;
1348 1635 }
1349 1636
1350 1637 /**
1351 - * Get an URL with an eventual affiliate ID
1638 + * Get a URL with an eventual affiliate ID
1352 1639 *
1353 1640 * @param string $url
1354 1641 * @return string
1355 1642 */
@@ -1361,9 +1648,10 @@
1361 1648
1362 1649 // Apply filters.
1363 1650 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1364 1651 }
1365 - 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;
1366 1654 }
1367 1655
1368 1656 /**
1369 1657 * Setup WPO logger(s)
@@ -1424,9 +1712,9 @@
1424 1712 // check for previous version options format.
1425 1713 $keys = array_keys($saved_loggers);
1426 1714
1427 1715 // if options stored in old format then reformat it.
1428 - if (false == is_numeric($keys[0])) {
1716 + if (false === is_numeric($keys[0])) {
1429 1717 $_saved_loggers = array();
1430 1718 foreach ($saved_loggers as $logger_id => $enabled) {
1431 1719 if ($enabled) {
1432 1720 $_saved_loggers[] = $logger_id;
@@ -1457,9 +1745,9 @@
1457 1745 foreach (array_keys($logger_options) as $option_name) {
1458 1746 if (array_key_exists($option_name, $options_keys)) {
1459 1747 $options_keys[$option_name]++;
1460 1748 } else {
1461 - $options_keys[$option_name] = 0;
1749 + $options_keys[$option_name] = 0;
1462 1750 }
1463 1751
1464 1752 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
1465 1753
@@ -1484,11 +1772,10 @@
1484 1772 $loggers[] = $logger;
1485 1773 }
1486 1774 }
1487 1775
1488 - $loggers = apply_filters('wp_optimize_loggers', $loggers);
1489 -
1490 - return $loggers;
1776 + $filtered_loggers = apply_filters('wp_optimize_loggers', $loggers);
1777 + return is_array($filtered_loggers) ? $filtered_loggers : $loggers;
1491 1778 }
1492 1779
1493 1780 /**
1494 1781 * Returns associative array with logger class name in a key and path to class file in a value.
@@ -1556,17 +1843,17 @@
1556 1843 return (is_multisite() && self::is_premium());
1557 1844 }
1558 1845
1559 1846 /**
1560 - * Returns true if current user can run optimizations.
1847 + * Returns true if the current user can run optimizations.
1561 1848 *
1562 1849 * @return bool
1563 1850 */
1564 - public function can_run_optimizations() {
1851 + public function can_run_optimizations(): bool {
1565 1852 // we don't check permissions for cron jobs.
1566 1853 if (defined('DOING_CRON') && DOING_CRON) return true;
1567 1854
1568 - 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;
1569 1856 return true;
1570 1857 }
1571 1858
1572 1859 /**
@@ -1585,13 +1872,10 @@
1585 1872 * @return array
1586 1873 */
1587 1874 public function get_sites() {
1588 1875 $sites = array();
1589 - // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
1590 1876 if (function_exists('get_sites')) {
1591 1877 $sites = get_sites(array('network_id' => null, 'deleted' => 0, 'number' => 999999));
1592 - } elseif (function_exists('wp_get_sites')) {
1593 - $sites = wp_get_sites(array('network_id' => null, 'deleted' => 0, 'limit' => 999999));
1594 1878 }
1595 1879 return $sites;
1596 1880 }
1597 1881
@@ -1597,9 +1881,9 @@
1597 1881
1598 1882 /**
1599 1883 * Returns script memory limit in megabytes.
1600 1884 *
1601 - * @param bool $memory_limit
1885 + * @param string|bool $memory_limit
1602 1886 * @return int
1603 1887 */
1604 1888 public function get_memory_limit($memory_limit = false) {
1605 1889 // Returns in megabytes
@@ -1669,8 +1953,10 @@
1669 1953 * Converts shorthand memory notation value to bytes.
1670 1954 * From http://php.net/manual/en/function.ini-get.php
1671 1955 *
1672 1956 * @param string $val shorthand memory notation value.
1957 + *
1958 + * @return string
1673 1959 */
1674 1960 public function return_bytes($val) {
1675 1961 $val = trim($val);
1676 1962 $last = strtolower($val[strlen($val)-1]);
@@ -1702,9 +1988,9 @@
1702 1988
1703 1989 /**
1704 1990 * Close browser connection and continue script work. - Taken from UpdraftPlus
1705 1991 *
1706 - * @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)
1707 1993 * @return void
1708 1994 */
1709 1995 public function close_browser_connection($txt = '') {
1710 1996 if (!headers_sent()) {
@@ -1716,9 +2002,9 @@
1716 2002 }
1717 2003
1718 2004 if (session_id()) session_write_close();
1719 2005 echo "\r\n\r\n";
1720 - echo $txt;
2006 + echo $txt; // phpcs:ignore WordPress.Security.EscapeOutput -- Output is already escaped
1721 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).
1722 2008 $ob_level = ob_get_level();
1723 2009 while ($ob_level > 0) {
1724 2010 ob_end_flush();
@@ -1734,9 +2020,13 @@
1734 2020 */
1735 2021 public function change_time_limit() {
1736 2022 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
1737 2023
1738 - @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
1739 2029 }
1740 2030
1741 2031 /**
1742 2032 * Does the request come from UDC
@@ -1753,11 +2043,11 @@
1753 2043 * @return boolean
1754 2044 */
1755 2045 public function template_should_include_data() {
1756 2046 /**
1757 - * Filters wether data should be included in certain templates or not.
2047 + * Filters whether data should be included in certain templates or not.
1758 2048 */
1759 - 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());
1760 2050 }
1761 2051
1762 2052 /**
1763 2053 * Load the templates for the modal window
@@ -1766,8 +2056,18 @@
1766 2056 $this->include_template('modal.php');
1767 2057 }
1768 2058
1769 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 + /**
1770 2070 * Delete transients and semaphores data from options table.
1771 2071 */
1772 2072 public function delete_transients_and_semaphores() {
1773 2073 global $wpdb;
@@ -1791,17 +2091,21 @@
1791 2091 foreach ($masks as $mask) {
1792 2092 $where_parts[] = "(`option_name` LIKE '{$mask}')";
1793 2093 }
1794 2094
1795 - $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));
1796 2097 }
1797 2098
1798 2099 /**
1799 2100 * Prevents bots from indexing plugins list
2101 + *
2102 + * @param string $output
2103 + * @return string
1800 2104 */
1801 2105 public function robots_txt($output) {
1802 2106 $upload_dir = wp_upload_dir();
1803 - $path = parse_url($upload_dir['baseurl']);
2107 + $path = wp_parse_url($upload_dir['baseurl']);
1804 2108 $output .= "\nUser-agent: *";
1805 2109 $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo/wpo-plugins-tables-list.json\n";
1806 2110 return $output;
1807 2111 }
@@ -1837,8 +2141,49 @@
1837 2141 * Instantiate Ajax handling class
1838 2142 */
1839 2143 private function load_ajax_handler() {
1840 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
1841 2186 }
1842 2187 }
1843 2188
1844 2189 /**