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 +739 -446 3.2.9 → 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.2.9
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,41 +17,82 @@
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.2.9');
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__));
24 +define('WPO_PLUGIN_SLUG', plugin_basename(__FILE__));
22 25 define('WPO_PREMIUM_NOTIFICATION', false);
23 -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');
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');
24 30
25 31 class WP_Optimize {
26 32
27 - 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';
28 34
29 35 private $template_directories;
30 36
31 37 protected static $_instance = null;
32 38
39 + protected $_cache_init_status = null;
40 +
33 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 + /**
34 64 * Class constructor
35 65 */
36 66 public function __construct() {
67 +
37 68 spl_autoload_register(array($this, 'loader'));
38 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 +
39 83 // Checks if premium is installed along with plugins needed.
40 84 add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
41 85
42 - register_activation_hook(__FILE__, 'wpo_activation_actions');
43 - register_deactivation_hook(__FILE__, 'wpo_deactivation_actions');
44 - register_uninstall_hook(__FILE__, 'wpo_uninstall_actions');
45 -
86 + register_activation_hook(__FILE__, array('WPO_Activation', 'actions'));
87 + register_deactivation_hook(__FILE__, array('WPO_Deactivation', 'actions'));
88 + register_uninstall_hook(__FILE__, array('WPO_Uninstall', 'actions'));
89 +
90 + WPO_Page_Optimizer::instance()->maybe_initialise();
91 +
46 92 $this->load_admin();
47 93 add_action('admin_init', array($this, 'admin_init'));
48 - add_action('admin_bar_menu', array($this, 'cache_admin_bar'), 100, 1);
49 94
50 - add_action('init', array($this, 'schedule_plugin_cron_tasks'));
51 -
52 95 add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
53 96 add_action('wpo_cron_event2', array($this, 'cron_action'));
54 97 add_filter('cron_schedules', array($this, 'cron_schedules'));
55 98
@@ -54,22 +97,24 @@
54 97 add_filter('cron_schedules', array($this, 'cron_schedules'));
55 98
56 99 if (!$this->get_options()->get_option('installed-for', false)) $this->get_options()->update_option('installed-for', time());
57 100
58 - if (!self::is_premium()) {
59 - add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
60 - }
101 + add_action('admin_footer-upload.php', array($this, 'add_smush_popup_template'));
61 102
62 103 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
63 104
64 105 add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_scripts'));
65 106
66 - add_action('wp_ajax_wp_optimize_ajax', array($this, 'wp_optimize_ajax_handler'));
107 + if ($this->get_options()->get_option('404_detector', 0)) {
108 + WP_Optimize_Performance::get_instance($this->get_404_detector())->hook_404_handler();
109 + }
67 110
111 + $this->load_ajax_handler();
112 +
68 113 // Show update to Premium notice for non-premium multisite.
69 114 add_action('wpo_additional_options', array($this, 'show_multisite_update_to_premium_notice'));
70 115
71 - // Action column (show repair button if need).
116 + // Action column (show repair button, if needed).
72 117 add_filter('wpo_tables_list_additional_column_data', array($this, 'tables_list_additional_column_data'), 15, 2);
73 118
74 119 /**
75 120 * Add action for display Images > Compress images tab.
@@ -75,9 +120,9 @@
75 120 * Add action for display Images > Compress images tab.
76 121 */
77 122 add_action('wp_optimize_admin_page_wpo_images_smush', array($this, 'admin_page_wpo_images_smush'));
78 123
79 - include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral.php');
124 + include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral/updraftcentral.php');
80 125
81 126 include_once(WPO_PLUGIN_MAIN_PATH.'includes/backward-compatibility-functions.php');
82 127
83 128 register_shutdown_function(array($this, 'log_fatal_errors'));
@@ -86,9 +131,9 @@
86 131
87 132 add_action('upgrader_process_complete', array($this, 'detect_active_plugins_and_themes_updates'), 10, 2);
88 133
89 134 $import_done_hooks = array(
90 - 'import_end', // wordpress importer
135 + 'import_end', // WordPress importer
91 136 'pmxi_after_xml_import', // wp all import
92 137 );
93 138
94 139 $db_update_hooks = apply_filters('wp_optimize_db_update_hooks', $import_done_hooks);
@@ -96,25 +141,117 @@
96 141 foreach ($db_update_hooks as $hook) {
97 142 add_action($hook, array($this, 'maybe_schedule_update_record_count_event'));
98 143 }
99 144 add_action('wpo_update_record_count_event', array($this->get_db_info(), 'wpo_update_record_count'));
145 +
146 + add_action('wpo_reset_stats_counter', array($this, 'reset_stats_counters'));
147 +
148 + $this->schedule_reset_stats_counters_event();
149 +
100 150 }
101 151
102 152 /**
103 - * 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
104 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 + *
105 222 * @param string $class_name The name of the class.
106 223 */
107 - private function loader($class_name) {
224 + public function loader($class_name) {
108 225 $dirs = $this->get_class_directories();
109 226
110 227 foreach ($dirs as $dir) {
111 - $class_file = WPO_PLUGIN_MAIN_PATH . $dir . '/class-' . str_replace('_', '-', strtolower($class_name)) . '.php';
228 + $class_file = WPO_PLUGIN_MAIN_PATH . trailingslashit($dir) . 'class-' . str_replace('_', '-', strtolower($class_name)) . '.php';
112 229 if (file_exists($class_file)) {
113 230 require_once($class_file);
114 231 return;
115 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 + }
116 239 }
240 +
241 + // Include PHP Minify - https://github.com/matthiasmullie/minify
242 + if (strpos($class_name, 'MatthiasMullie') !== false) {
243 + $class_name_parts = explode('\\', $class_name);
244 + $class_file = WPO_PLUGIN_MAIN_PATH.'vendor/'.strtolower($class_name_parts[0]).'/'.strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $class_name_parts[1])).'/src/'.implode('/', array_slice($class_name_parts, 2)).'.php';
245 + if (file_exists($class_file)) {
246 + require_once($class_file);
247 + return;
248 + }
249 + }
250 +
251 + if ('Minify_HTML' === $class_name) {
252 + require_once WPO_PLUGIN_MAIN_PATH.'vendor/mrclay/minify/lib/Minify/HTML.php';
253 + }
117 254 }
118 255
119 256 /**
120 257 * Returns an array of class directories
@@ -123,12 +260,19 @@
123 260 */
124 261 private function get_class_directories() {
125 262 return array(
126 263 'cache',
264 + 'compatibility',
127 265 'includes',
266 + 'includes/tables',
267 + 'includes/list-tables',
268 + 'includes/dashboard',
269 + 'includes/gravatars',
270 + 'includes/lcp',
128 271 'minify',
129 272 'optimizations',
130 273 'webp',
274 + 'includes/updraftcentral',
131 275 );
132 276 }
133 277
134 278 /**
@@ -138,8 +282,17 @@
138 282 $this->get_admin_instance();
139 283 }
140 284
141 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 + /**
142 295 * Returns Admin class instance
143 296 *
144 297 * @return WP_Optimize_Admin
145 298 */
@@ -160,19 +313,31 @@
160 313 $should_purge_cache = false;
161 314 $skin = $upgrader_object->skin;
162 315 if ('plugin' === $options['type']) {
163 316 // A plugin is updated using the default update system (upgrader_overwrote_package is used for the upload method)
164 - if (property_exists($skin, 'plugin_active') && $skin->plugin_active) {
165 - $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'];
166 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 + }
167 332 } elseif ('theme' === $options['type']) {
168 333 $active_theme = get_stylesheet();
169 334 $parent_theme = get_template();
170 335 // A theme is updated using the upload system
171 - if (isset($options['action']) && 'install' === $options['action'] && 'update-theme' === $skin->options['overwrite']) {
336 + if (isset($options['action']) && 'install' === $options['action'] && isset($skin->options['overwrite']) && 'update-theme' === $skin->options['overwrite']) {
172 337 $updated_theme = $upgrader_object->result['destination_name'];
173 338 // Check if the theme is in use
174 - if ($active_theme == $updated_theme || $parent_theme == $updated_theme) {
339 + if ($active_theme === $updated_theme || $parent_theme === $updated_theme) {
175 340 $should_purge_cache = true;
176 341 }
177 342 // A theme is updated using the classic update system
178 343 } elseif (isset($options['action']) && 'update' === $options['action'] && isset($options['themes']) && is_array($options['themes'])) {
@@ -200,10 +365,13 @@
200 365 }
201 366
202 367 public function admin_page_wpo_images_smush() {
203 368 $options = Updraft_Smush_Manager()->get_smush_options();
204 - $custom = 100 != $options['image_quality'] && 60 != $options['image_quality'] ? true : false;
205 - $this->include_template('images/smush.php', false, array('smush_options' => $options, 'custom' => $custom, 'does_server_allows_local_webp_conversion' => $this->does_server_allows_local_webp_conversion()));
369 + $custom = 90 >= $options['image_quality'] && 65 <= $options['image_quality'];
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();
206 374 }
207 375
208 376 public static function instance() {
209 377 if (empty(self::$_instance)) {
@@ -216,9 +384,37 @@
216 384 return WP_Optimizer::instance();
217 385 }
218 386
219 387 /**
220 - * Get and instanciate WP_Optimize_Minify
388 + * Adds 3rd party plugin compatibilities.
389 + */
390 + public function load_compatibilities() {
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 +
401 + WPO_Page_Builder_Compatibility::instance();
402 + WPO_KD_Submissions_Compatibility::instance();
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 +
412 + do_action('wpo_load_compatibilities');
413 + }
414 +
415 + /**
416 + * Get and instantiate WP_Optimize_Minify
221 417 *
222 418 * @return WP_Optimize_Minify
223 419 */
224 420 public function get_minify() {
@@ -233,58 +429,59 @@
233 429 return WP_Optimize_Notices::instance();
234 430 }
235 431
236 432 /**
237 - * Returns instance if WPO_Page_Cache class.
433 + * Get and instantiate WP_Optimize_Delay_JS
238 434 *
239 - * @return WPO_Page_Cache
435 + * @return WP_Optimize_Delay_JS
240 436 */
241 - public function get_page_cache() {
242 - return WPO_Page_Cache::instance();
437 + private function get_delay_js() {
438 + return WP_Optimize_Delay_JS::instance();
243 439 }
244 440
245 441 /**
246 - * Returns instance if WP_Optimize_WebP class.
442 + * Returns instance of WPO_Page_Optimizer class.
247 443 *
248 - * @return WP_Optimize_WebP
444 + * @return WPO_Page_Optimizer
249 445 */
250 - public function get_webp_instance() {
251 - return WP_Optimize_WebP::get_instance();
446 + public function get_page_optimizer() {
447 + return WPO_Page_Optimizer::instance();
252 448 }
253 449
254 450 /**
255 - * Detects if the platform is Kinsta or not
451 + * Returns instance 404 Detector Cron class.
256 452 *
257 - * @return bool Returns true if it is Kinsta platform, otherwise returns false
453 + * @return WP_Optimize_404_Detector_Cron
258 454 */
259 - private function is_kinsta() {
260 - return isset($_SERVER['KINSTA_CACHE_ZONE']);
455 + private function get_404_detector_cron() {
456 + return WP_Optimize_404_Detector_Cron::get_instance();
261 457 }
262 458
263 459 /**
264 - * Detects whether the server handles cache. eg. Nginx cache
460 + * Returns instance of WPO_Page_Cache class.
461 + *
462 + * @return WPO_Page_Cache
265 463 */
266 - public function does_server_handles_cache() {
267 - return $this->is_kinsta();
464 + public function get_page_cache() {
465 + return WPO_Page_Cache::instance();
268 466 }
269 467
270 468 /**
271 - * Detects whether the server supports table optimization.
469 + * Returns instance of WP_Optimize_WebP class.
272 470 *
273 - * Some servers prevent table optimization
274 - * because InnoDB engine does not optimize table
275 - * instead it drops tables and recreate them
276 - * which results in elevated disk write operations
471 + * @return WP_Optimize_WebP
277 472 */
278 - public function does_server_allows_table_optimization() {
279 - return !$this->is_kinsta();
473 + public function get_webp_instance() {
474 + return WP_Optimize_WebP::get_instance();
280 475 }
281 476
282 477 /**
283 - * 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
284 481 */
285 - private function does_server_allows_local_webp_conversion() {
286 - return !$this->is_kinsta();
482 + public function get_server_compatibility_instance(): WP_Optimize_Server_Compatibility {
483 + return WP_Optimize_Server_Compatibility::get_instance();
287 484 }
288 485
289 486 /**
290 487 * Create instance of WP_Optimize_Browser_Cache.
@@ -346,41 +543,63 @@
346 543 /**
347 544 * Enqueue scripts and styles on WP-Optimize pages.
348 545 */
349 546 public function admin_enqueue_scripts() {
350 - $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
351 - $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
352 - $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
547 + global $wp_version;
548 + $enqueue_version = $this->get_enqueue_version();
549 + $min_or_not = $this->get_min_or_not_string();
550 + $min_or_not_internal = $this->get_min_or_not_internal_string();
353 551
354 552 // Register or enqueue common scripts
355 553 wp_register_script('wp-optimize-send-command', WPO_PLUGIN_URL.'js/send-command'.$min_or_not_internal.'.js', array(), $enqueue_version);
356 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);
357 556 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
358 557
359 558 // load scripts and styles only on WP-Optimize pages.
360 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);
361 569
362 570 wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);
363 571
364 572 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
573 +
365 574 wp_enqueue_script('wp-optimize-modal', WPO_PLUGIN_URL.'js/modal'.$min_or_not_internal.'.js', array('jquery', 'backbone', 'wp-util'), $enqueue_version);
366 - wp_enqueue_script('wp-optimize-cache-js', WPO_PLUGIN_URL.'js/cache'.$min_or_not_internal.'.js', array('wp-optimize-send-command', 'smush-js'), $enqueue_version);
367 - 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'), $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);
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);
368 577 wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
369 - // Using tablesorter to help with organising the DB size on Table Information
370 - // https://github.com/Mottie/tablesorter
371 - 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);
372 582
373 - 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);
374 584
375 - // wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);
376 -
377 585 $js_variables = $this->wpo_js_translations();
378 586 $js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
379 -
380 587 wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
381 588
382 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 +
383 602 }
384 603
385 604 /**
386 605 * Enqueue any required front-end scripts
@@ -387,11 +606,11 @@
387 606 *
388 607 * @return void
389 608 */
390 609 public function frontend_enqueue_scripts() {
391 - if (!current_user_can('manage_options') || !is_admin_bar_showing()) return;
392 - $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
393 - $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
610 + if (!$this->current_user_can('manage_options') || !is_admin_bar_showing()) return;
611 + $enqueue_version = $this->get_enqueue_version();
612 + $min_or_not_internal = $this->get_min_or_not_internal_string();
394 613
395 614 // Register or enqueue common scripts
396 615 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
397 616 }
@@ -397,8 +616,10 @@
397 616 }
398 617
399 618 /**
400 619 * Load Task Manager
620 + *
621 + * @return Updraft_Smush_Manager
401 622 */
402 623 public function get_task_manager() {
403 624 include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
404 625
@@ -403,14 +624,14 @@
403 624 include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
404 625
405 626 Updraft_Tasks_Activation::check_updates();
406 627
407 - include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-meta.php');
408 - include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-options.php');
409 - include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
628 + include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-meta.php');
629 + include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-options.php');
630 + include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
410 631
411 - include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-task.php');
412 - include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-manager.php');
632 + include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-smush-task.php');
633 + include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-smush-manager.php');
413 634
414 635 return Updraft_Smush_Manager();
415 636 }
416 637
@@ -416,9 +637,9 @@
416 637
417 638 /**
418 639 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
419 640 *
420 - * @returns Boolean
641 + * @returns bool
421 642 */
422 643 public static function is_premium() {
423 644 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && function_exists('WP_Optimize_Premium')) {
424 645 $wp_optimize_premium = WP_Optimize_Premium();
@@ -433,9 +654,9 @@
433 654 * @return bool
434 655 */
435 656 public function is_apache_server() {
436 657 global $is_apache;
437 - return $is_apache;
658 + return (bool) $is_apache;
438 659 }
439 660
440 661 /**
441 662 * Check if script running on IIS web server.
@@ -479,12 +700,23 @@
479 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.
480 701 */
481 702 public function plugins_loaded() {
482 703
483 - 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()) {
484 716 add_filter('wp_optimize_admin_page_wpo_cache_tabs', array($this, 'filter_cache_tabs'), 99, 1);
485 717
486 - // If newly migrated to server that handles cache, disable wpo cache
718 + // If newly migrated to a server that handles cache, disable wpo cache
487 719 $cache = $this->get_page_cache();
488 720 if ($cache->is_enabled()) {
489 721 $cache->disable();
490 722 }
@@ -496,23 +728,28 @@
496 728 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && !class_exists('WP_Optimize_Premium')) {
497 729 include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
498 730 }
499 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 +
500 737 // load defaults
501 - WP_Optimize()->get_options()->set_default_options();
738 + $this->get_options()->set_default_options();
502 739
503 740 // Initialize loggers.
504 - $this->setup_loggers();
741 + add_action('init', array($this, 'setup_loggers'));
505 742
506 743 if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
507 744 if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
508 745 deactivate_plugins($free_plugin);
509 746
510 - // 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.
511 748 if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
512 749 $advanced_cache_filename = trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
513 750
514 - 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))) {
515 752 file_put_contents($advanced_cache_filename, '');
516 753 }
517 754 }
518 755
@@ -520,29 +757,71 @@
520 757 add_action('admin_notices', array($this, 'show_admin_notice_premium'));
521 758 return;
522 759 }
523 760
524 - // Loads the task manager
525 - $this->get_task_manager();
761 + add_action('init', array($this, 'init'));
526 762
527 - // Loads the language file.
528 - 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 + }
529 766
530 - // Load page cache.
531 - $this->get_page_cache();
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();
532 775 $this->init_page_cache();
776 + $this->get_minify();
777 + $this->get_delay_js();
533 778
534 - // Include minify
535 - $this->get_minify();
779 + // Load 3rd party plugin compatibilities.
780 + $this->load_compatibilities();
781 +
536 782 $this->run_updates();
537 783
784 + // We need this here because webp can be unavailable because of server moves
785 + // This deletes already converted webp images and original image file when a media is deleted
786 + WP_Optimize_WebP_Images::get_instance();
787 +
788 + // Loads the task manager
789 + $this->get_task_manager();
790 +
538 791 // Include WebP
539 - $this->get_webp_instance();
792 + if (WPO_USE_WEBP_CONVERSION) {
793 + $this->get_webp_instance();
794 + }
795 +
796 + $this->get_onboarding()->init();
540 797 }
541 798
542 799 /**
543 - * Filter cache tabs (when it is Kinsta)
800 + * Loads the language file.
544 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 + /**
809 + * Attach this wp-optimize plugin as host of the UpdraftCentral libraries
810 + * (e.g. "central" folder)
811 + *
812 + * @param array $hosts List of plugins having the "central" library integrated into them
813 + *
814 + * @return array
815 + */
816 + public function attach_updraftcentral_host($hosts) {
817 + $hosts[] = 'wp-optimize';
818 + return $hosts;
819 + }
820 +
821 + /**
822 + * Filter cache tabs (when the server handles it or do not allow it, like Kinsta)
823 + *
545 824 * @param array $tabs An array of tabs
546 825 *
547 826 * @return array $tabs An array of tabs
548 827 */
@@ -556,18 +835,18 @@
556 835
557 836 /**
558 837 * Check whether one of free/Premium is active (whether it is this instance or not)
559 838 *
560 - * @param String $which - 'free' or 'premium'
839 + * @param string $which - 'free' or 'premium'
561 840 *
562 - * @return String|Boolean - plugin path (if installed) or false if not
841 + * @return string|boolean - plugin path (if installed) or false if not
563 842 */
564 - private function is_active($which = 'free') {
843 + public function is_active($which = 'free') {
565 844 $active_plugins = $this->get_active_plugins();
566 845 foreach ($active_plugins as $file) {
567 846 if ('wp-optimize.php' == basename($file)) {
568 847 $plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
569 - 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;
570 849 }
571 850 }
572 851 return false;
573 852 }
@@ -574,14 +853,13 @@
574 853
575 854 /**
576 855 * Gets an array of plugins active on either the current site, or site-wide
577 856 *
578 - * @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)
579 858 */
580 859 private function get_active_plugins() {
581 -
582 860 // Gets all active plugins on the current site
583 - $active_plugins = get_option('active_plugins');
861 + $active_plugins = (array) get_option('active_plugins', array());
584 862
585 863 if (is_multisite()) {
586 864 $network_active_plugins = get_site_option('active_sitewide_plugins');
587 865 if (!empty($network_active_plugins)) {
@@ -615,9 +893,9 @@
615 893
616 894 // Loops around each plugin available.
617 895 foreach ($get_plugins as $key => $value) {
618 896 // If the plugin name matches that of the specified name, it will gather details.
619 - if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
897 + if ($value['Name'] !== $name && $value['TextDomain'] !== $name) continue;
620 898 $plugin_info['installed'] = true;
621 899 $plugin_info['name'] = $key;
622 900 $plugin_info['version'] = $value['Version'];
623 901 if (in_array($key, $active_plugins)) {
@@ -631,10 +909,10 @@
631 909 /**
632 910 * This is a notice to show users that premium is installed
633 911 */
634 912 public function show_admin_notice_premium() {
635 - 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>';
636 - 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.
637 915 }
638 916
639 917 /**
640 918 * Show update to Premium notice for non-premium multisite.
@@ -641,9 +919,9 @@
641 919 */
642 920 public function show_multisite_update_to_premium_notice() {
643 921 if (!is_multisite() || self::is_premium()) return;
644 922
645 - 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>';
646 924 }
647 925
648 926 public function admin_init() {
649 927 $pagenow = $GLOBALS['pagenow'];
@@ -649,26 +927,29 @@
649 927 $pagenow = $GLOBALS['pagenow'];
650 928
651 929 $this->register_template_directories();
652 930
653 - 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)) {
654 932 $options = $this->get_options();
655 933
656 934 $dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);
657 935
658 - if (file_exists(WPO_PLUGIN_MAIN_PATH . '/index.html')) {
659 - $installed = filemtime(WPO_PLUGIN_MAIN_PATH . '/index.html');
936 + if (file_exists(WPO_PLUGIN_MAIN_PATH . 'index.html')) {
937 + $installed = filemtime(WPO_PLUGIN_MAIN_PATH . 'index.html');
660 938 $installed_for = (time() - $installed);
661 939 }
662 940
663 941 if (($installed && time() > $dismissed_until && $installed_for > (14 * 86400) && !defined('WP_OPTIMIZE_NOADS_B')) || (defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
664 - add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead'));
942 + add_action('all_admin_notices', array($this, 'show_admin_notice_upgraded'));
665 943 }
666 944 }
667 - $this->install_or_update_notice = $this->get_install_or_update_notice();
945 +
668 946 if ($this->is_wp_smush_installed()) {
669 947 add_filter('transient_wp-smush-conflict_check', array($this, 'modify_wp_smush_conflict_check'), 9, 1);
670 948 }
949 + if ($this->get_options()->get_option('404_detector', 0)) {
950 + WP_Optimize_Performance::get_instance($this->get_404_detector())->init();
951 + }
671 952 }
672 953
673 954 /**
674 955 * Checks whether the WP Smush plugin is active or not
@@ -694,9 +975,9 @@
694 975 return $active_plugins;
695 976 }
696 977
697 978 /**
698 - * Get the install or update notice instance
979 + * Get the installation or update notice instance
699 980 *
700 981 * @return WP_Optimize_Install_Or_Update_Notice
701 982 */
702 983 public function get_install_or_update_notice() {
@@ -705,142 +986,47 @@
705 986 $instance = new WP_Optimize_Install_Or_Update_Notice();
706 987 return $instance;
707 988 }
708 989
709 - public function show_admin_notice_upgradead() {
710 - $this->include_template('notices/thanks-for-using-main-dash.php');
990 + /**
991 + * Display an admin notice for an upgraded version.
992 + */
993 + public function show_admin_notice_upgraded() {
994 + $this->include_template('notices/thanks-for-using-main-dash.php', false, array(
995 + 'is_premium' => WP_Optimize::is_premium()
996 + ));
711 997 }
712 -
998 +
999 + /**
1000 + * Returns required capability string
1001 + *
1002 + * @return string
1003 + */
713 1004 public function capability_required() {
714 - return apply_filters('wp_optimize_capability_required', 'manage_options');
715 - }
1005 + $capability = is_multisite() ? 'manage_network_options' : 'manage_options';
716 1006
717 - public function wp_optimize_ajax_handler() {
718 - $nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
1007 + $filtered_capability = apply_filters('wp_optimize_capability_required', $capability);
719 1008
720 - if (!wp_verify_nonce($nonce, 'wp-optimize-ajax-nonce') || empty($_POST['subaction'])) {
721 - wp_send_json(array(
722 - 'result' => false,
723 - 'error_code' => 'security_check',
724 - 'error_message' => __('The security check failed; try refreshing the page.', 'wp-optimize')
725 - ));
726 - }
1009 + return is_string($filtered_capability) ? $filtered_capability : $capability;
1010 + }
727 1011
728 - $subaction = $_POST['subaction'];
729 - $data = isset($_POST['data']) ? $_POST['data'] : null;
730 -
731 - if (!current_user_can($this->capability_required())) {
732 - wp_send_json(array(
733 - 'result' => false,
734 - 'error_code' => 'security_check',
735 - 'error_message' => __('You are not allowed to run this command.', 'wp-optimize')
736 - ));
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
737 1022 }
738 1023
739 -
740 - // Currently the settings are only available to network admins.
741 - if (is_multisite() && !current_user_can('manage_network_options')) {
742 - /**
743 - * Filters the commands allowed to the subsite admins. Other commands are only available to network admin. Only used in a multisite context.
744 - */
745 - $allowed_commands = apply_filters('wpo_multisite_allowed_commands', array('check_server_status', 'compress_single_image', 'restore_single_image'));
746 - if (!in_array($subaction, $allowed_commands)) wp_send_json(array(
747 - 'result' => false,
748 - 'error_code' => 'update_failed',
749 - 'error_message' => __('Options can only be saved by network admin', 'wp-optimize')
750 - ));
1024 + if (current_user_can($capability)) {
1025 + return true;
751 1026 }
752 -
753 - $options = $this->get_options();
754 1027
755 - $results = array();
756 -
757 - // Some commands that are available via AJAX only.
758 - if (in_array($subaction, array('dismiss_dash_notice_until', 'dismiss_season'))) {
759 - $options->update_option($subaction, (time() + 366 * 86400));
760 - } elseif (in_array($subaction, array('dismiss_page_notice_until', 'dismiss_notice'))) {
761 - $options->update_option($subaction, (time() + 84 * 86400));
762 - } elseif ('dismiss_review_notice' == $subaction) {
763 - if (empty($data['dismiss_forever'])) {
764 - $options->update_option($subaction, time() + 84*86400);
765 - } else {
766 - $options->update_option($subaction, 100 * (365.25 * 86400));
767 - }
768 - } else {
769 -
770 - $commands = new WP_Optimize_Commands();
771 - $minify_commands = new WP_Optimize_Minify_Commands();
772 -
773 -
774 - if (self::is_premium()) {
775 - $cache_commands = new WP_Optimize_Cache_Commands_Premium();
776 - } else {
777 - $cache_commands = new WP_Optimize_Cache_Commands();
778 - }
779 -
780 - // check if called command not in main commands class and exist in cache commands class then change class.
781 - if (!is_callable(array($commands, $subaction)) && is_callable(array($minify_commands, $subaction))) {
782 - $commands = $minify_commands;
783 - }
784 -
785 - // check if called command not in main commands class and exist in cache commands class then change class.
786 - if (!is_callable(array($commands, $subaction)) && is_callable(array($cache_commands, $subaction))) {
787 - $commands = $cache_commands;
788 - }
789 -
790 - if (!is_callable(array($commands, $subaction))) {
791 - error_log("WP-Optimize: ajax_handler: no such command (".$subaction.")");
792 - $results = array(
793 - 'result' => false,
794 - 'error_code' => 'command_not_found',
795 - 'error_message' => sprintf(__('The command "%s" was not found', 'wp-optimize'), $subaction)
796 - );
797 - } else {
798 - $results = call_user_func(array($commands, $subaction), $data);
799 -
800 - // clean status box content, it broke json sometimes.
801 - if (isset($results['status_box_contents'])) {
802 - $results['status_box_contents'] = str_replace(array("\n", "\t"), '', $results['status_box_contents']);
803 - }
804 -
805 - if (is_wp_error($results)) {
806 - $results = array(
807 - 'result' => false,
808 - 'error_code' => $results->get_error_code(),
809 - 'error_message' => $results->get_error_message(),
810 - 'error_data' => $results->get_error_data(),
811 - );
812 - }
813 -
814 - // if nothing was returned for some reason, set as result null.
815 - if (empty($results)) {
816 - $results = array(
817 - 'result' => null
818 - );
819 - }
820 - }
821 - }
822 -
823 - $result = json_encode($results);
824 -
825 - // Requires PHP 5.3+
826 - $json_last_error = function_exists('json_last_error') ? json_last_error() : false;
827 -
828 - // if json_encode returned error then return error.
829 - if ($json_last_error) {
830 - $result = array(
831 - 'result' => false,
832 - 'error_code' => $json_last_error,
833 - 'error_message' => 'json_encode error : '.$json_last_error,
834 - 'error_data' => '',
835 - );
836 -
837 - $result = json_encode($result);
838 - }
839 -
840 - echo $result;
841 -
842 - die;
1028 + return false;
843 1029 }
844 1030
845 1031 /**
846 1032 * Returns array of translations used in javascript code.
@@ -847,9 +1033,10 @@
847 1033 *
848 1034 * @return array
849 1035 */
850 1036 public function wpo_js_translations() {
851 - return apply_filters('wpo_js_translations', array(
1037 + $log_message = __('For more details, please check your logs configured in logging destinations settings.', 'wp-optimize');
1038 + $translations = array(
852 1039 'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
853 1040 'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
854 1041 'optimization_complete' => __('Optimization complete', 'wp-optimize'),
855 1042 'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
@@ -855,8 +1042,9 @@
855 1042 'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
856 1043 'optimizing_table' => __('Optimizing table:', 'wp-optimize'),
857 1044 'run_optimizations' => __('Run optimizations', 'wp-optimize'),
858 1045 'table_optimization_timeout' => 120000,
1046 + 'add' => __('Add', 'wp-optimize'),
859 1047 'cancel' => __('Cancel', 'wp-optimize'),
860 1048 'cancelling' => __('Cancelling...', 'wp-optimize'),
861 1049 'enable' => __('Enable', 'wp-optimize'),
862 1050 'disable' => __('Disable', 'wp-optimize'),
@@ -862,11 +1050,14 @@
862 1050 'disable' => __('Disable', 'wp-optimize'),
863 1051 'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
864 1052 'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
865 1053 'fill_all_settings_fields' => __('Before saving, you need to complete the currently incomplete settings (or remove them).', 'wp-optimize'),
866 - 'table_was_not_repaired' => __('%s was not repaired. For more details, please check the logs (configured in your logging destinations settings).', 'wp-optimize'),
867 - 'table_was_not_deleted' => __('%s was not deleted. For more details, please check your logs configured in logging destinations settings.', 'wp-optimize'),
868 - 'table_was_not_converted' => __('%s was not converted to InnoDB. For more details, please check your logs configured in logging destinations settings.', 'wp-optimize'),
1054 + // translators: %s is the table name
1055 + 'table_was_not_repaired' => __('%s was not repaired.', 'wp-optimize') . ' ' . $log_message,
1056 + // translators: %s is the table name
1057 + 'table_was_not_deleted' => __('%s was not deleted.', 'wp-optimize') . ' ' . $log_message,
1058 + // translators: %s is the table name
1059 + 'table_was_not_converted' => __('%s was not converted to InnoDB.', 'wp-optimize') . ' ' . $log_message,
869 1060 'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
870 1061 'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
871 1062 'update' => __('Update', 'wp-optimize'),
872 1063 'run_now' => __('Run now', 'wp-optimize'),
@@ -874,86 +1065,87 @@
874 1065 'loading_urls' => __('Loading URLs...', 'wp-optimize'),
875 1066 'current_cache_size' => __('Current cache size:', 'wp-optimize'),
876 1067 'number_of_files' => __('Number of files:', 'wp-optimize'),
877 1068 'toggle_info' => __('Show information', 'wp-optimize'),
1069 + 'delete_file' => __('Delete', 'wp-optimize'),
1070 + 'deleting' => __('Deleting...', 'wp-optimize'),
878 1071 'added_to_list' => __('Added to the list', 'wp-optimize'),
879 1072 'added_notice' => __('The file was added to the list', 'wp-optimize'),
880 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'),
881 1077 'page_refresh' => __('Refreshing the page to reflect changes...', 'wp-optimize'),
1078 + 'cache_file_not_found' => __('Cache file was not found.', 'wp-optimize'),
882 1079 'settings_have_been_deleted_successfully' => __('WP-Optimize settings have been deleted successfully.', 'wp-optimize'),
883 1080 'loading_data' => __('Loading data...', 'wp-optimize'),
884 - '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'),
885 1083 'settings_page_url' => is_multisite() ? network_admin_url('admin.php?page=wpo_settings') : admin_url('admin.php?page=wpo_settings'),
886 1084 'sites' => $this->get_sites(),
887 - '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),
888 1088 'post_meta_tweak_completed' => __('The tweak has been performed.', 'wp-optimize'),
889 1089 'no_minified_assets' => __('No minified files are present', 'wp-optimize'),
890 1090 'network_site_url' => network_site_url(),
891 1091 'export_settings_file_name' => 'wpoptimize-settings-'.sanitize_title(get_bloginfo('name')).'.json',
892 1092 'import_select_file' => __('You have not yet selected a file to import.', 'wp-optimize'),
893 - 'import_invalid_json_file' => __('Error: The chosen file is corrupt. Please choose a valid WP-Optimize export file.', 'wp-optimize'),
1093 + 'import_invalid_json_file' => __('Error: The chosen file is corrupt.', 'wp-optimize') . ' ' . __('Please choose a valid WP-Optimize export file.', 'wp-optimize'),
894 1094 'importing' => __('Importing...', 'wp-optimize'),
895 1095 'importing_data_from' => __('This will import data from:', 'wp-optimize'),
896 1096 'exported_on' => __('Which was exported on:', 'wp-optimize'),
897 1097 'continue_import' => __('Do you want to carry out the import?', 'wp-optimize'),
898 -
899 - ));
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'),
1110 + 'show_information' => __('Show information', 'wp-optimize'),
1111 + 'hide_information' => __('Hide information', 'wp-optimize'),
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;
900 1120 }
901 1121
902 1122 /**
903 - * Manages the admin bar menu for caching (currently page and minify)
904 - */
905 - public function cache_admin_bar($wp_admin_bar) {
906 -
907 - $options = $this->get_options();
908 - if (!$options->get_option('enable_cache_in_admin_bar', true)) return;
909 -
910 - /**
911 - * The "purge cache" menu items
912 - *
913 - * @param array $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
914 - * @param object $wp_admin_bar
915 - */
916 - $menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);
917 -
918 - if (empty($menu_items) || !is_array($menu_items)) return;
919 -
920 - $wp_admin_bar->add_menu(array(
921 - 'id' => 'wpo_purge_cache',
922 - 'title' => __('Purge cache', 'wp-optimize'),
923 - 'href' => '#',
924 - 'meta' => array(
925 - 'title' => __('Purge cache', 'wp-optimize'),
926 - ),
927 - 'parent' => false,
928 - ));
929 -
930 - foreach ($menu_items as $item) {
931 - $wp_admin_bar->add_menu($item);
932 - }
933 - }
934 -
935 - /**
936 1123 * Add settings link on plugin page
937 1124 *
938 - * @param string $links Passing through the URL to be used within the HREF.
939 - * @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.
940 1127 */
941 1128 public function plugin_settings_link($links) {
942 1129
943 1130 $admin_page_url = $this->get_options()->admin_page_url();
944 1131 $settings_page_url = $this->get_options()->admin_page_url('wpo_settings');
1132 + $database_page_url = $this->get_options()->admin_page_url('wpo_database');
945 1133
946 - if (false == self::is_premium()) {
947 - $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>';
948 1136 array_unshift($links, $premium_link);
949 1137 }
950 1138
951 - $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>';
952 1140 array_unshift($links, $settings_link);
953 1141
954 - $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>';
955 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 +
956 1148 return $links;
957 1149 }
958 1150
959 1151 /**
@@ -967,9 +1159,9 @@
967 1159 public function tables_list_additional_column_data($content, $table_info) {
968 1160 if ($table_info->is_needing_repair) {
969 1161 $content .= '<div class="wpo_button_wrap">'
970 1162 . '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
971 - . '<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
972 1164 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
973 1165 . '</div>';
974 1166 }
975 1167
@@ -976,18 +1168,18 @@
976 1168 // table belongs to plugin.
977 1169 if ($table_info->can_be_removed) {
978 1170 $content .= '<div>'
979 1171 . '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
980 - . '<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
981 1173 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
982 1174 . '</div>';
983 1175 }
984 1176
985 1177 // Add option for MyISAM to InnoDB conversion.
986 - if ('MyISAM' == $table_info->Engine) {
1178 + if ('MyISAM' === $table_info->Engine) {
987 1179 $content .= '<div class="wpo_button_convert wpo_button_wrap">'
988 1180 . '<button class="button button-secondary toinnodb" data-table="' . esc_attr($table_info->Name) . '">' . __('Convert to InnoDB', 'wp-optimize') . '</button>'
989 - . '<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
990 1182 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
991 1183 . '</div>';
992 1184
993 1185 }
@@ -997,15 +1189,26 @@
997 1189
998 1190 /**
999 1191 * Initialize WP-Optimize page cache.
1000 1192 */
1001 - public function init_page_cache() {
1193 + private function init_page_cache() {
1002 1194 if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
1003 - $this->get_page_cache()->enable();
1195 + if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
1196 + $this->_cache_init_status = $this->get_page_cache()->enable();
1197 + }
1004 1198 }
1005 1199 }
1006 1200
1007 1201 /**
1202 + * Get init_page_cache() status.
1203 + *
1204 + * @return bool|WP_Error
1205 + */
1206 + public function get_init_page_cache_status() {
1207 + return $this->_cache_init_status;
1208 + }
1209 +
1210 + /**
1008 1211 * Schedules cron event based on selected schedule type
1009 1212 *
1010 1213 * @return void
1011 1214 */
@@ -1013,17 +1216,17 @@
1013 1216 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
1014 1217
1015 1218 $options = $this->get_options();
1016 1219
1017 - if ($options->get_option('schedule') === false) {
1220 + if (false === $options->get_option('schedule')) {
1018 1221 $options->set_default_options();
1019 1222 } else {
1020 - if ('true' == $options->get_option('schedule')) {
1223 + if ('true' === $options->get_option('schedule')) {
1021 1224 if (!wp_next_scheduled('wpo_cron_event2')) {
1022 1225 $schedule_type = $options->get_option('schedule-type', 'wpo_weekly');
1023 1226
1024 1227 // Backward compatibility
1025 - if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';
1228 + if ('wpo_otherweekly' === $schedule_type) $schedule_type = 'wpo_fortnightly';
1026 1229
1027 1230 $this_time = (86400 * 7);
1028 1231
1029 1232 switch ($schedule_type) {
@@ -1045,15 +1248,15 @@
1045 1248 }
1046 1249
1047 1250 add_action('wpo_cron_event2', array($this, 'cron_action'));
1048 1251 $result = wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
1049 - WP_Optimize()->log('running wp_schedule_event()');
1252 + $this->log('running wp_schedule_event()');
1050 1253 if (is_wp_error($result)) {
1051 1254 $error_msg = $result->get_error_message();
1052 - WP_Optimize()->log($error_msg);
1053 - 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
1054 1257 } else {
1055 - WP_Optimize()->log($result);
1258 + $this->log($result);
1056 1259 }
1057 1260 }
1058 1261 }
1059 1262 }
@@ -1059,13 +1262,31 @@
1059 1262 }
1060 1263 }
1061 1264
1062 1265 /**
1063 - * Clears all cron events
1266 + * Unschedules WP-Optimize cron events on deactivation.
1064 1267 *
1065 1268 * @return void
1066 1269 */
1067 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() {
1068 1289 $cron_jobs = _get_cron_array();
1069 1290 foreach ($cron_jobs as $job) {
1070 1291 foreach (array_keys($job) as $hook) {
1071 1292 if (preg_match('/^wpo_/', $hook)) wp_unschedule_hook($hook);
@@ -1111,8 +1332,12 @@
1111 1332 /**
1112 1333 * Run updates on plugin activation.
1113 1334 */
1114 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');
1115 1340 include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-updates.php');
1116 1341 WP_Optimize_Updates::check_updates();
1117 1342 }
1118 1343
@@ -1123,13 +1348,21 @@
1123 1348 * @return string
1124 1349 */
1125 1350 public function show_admin_warning_overdue_crons($howmany) {
1126 1351 $ret = '<div class="updated below-h2"><p>';
1127 - $ret .= '<strong>'.__('Warning', 'wp-optimize').':</strong> '.sprintf(__('WordPress has a number (%d) of scheduled tasks which are overdue. Unless this is a development site, this probably means that the scheduler in your WordPress install is not working.', 'wp-optimize'), $howmany).' <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>';
1128 1354 $ret .= '</p></div>';
1129 1355 return $ret;
1130 1356 }
1131 1357
1358 + /**
1359 + * Normalizes path string
1360 + *
1361 + * @param string $path
1362 + *
1363 + * @return string
1364 + */
1132 1365 private function wp_normalize_path($path) {
1133 1366 // Wp_normalize_path is not present before WP 3.9.
1134 1367 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1135 1368 // Taken from WP 4.6.
@@ -1140,24 +1373,38 @@
1140 1373 }
1141 1374 return $path;
1142 1375 }
1143 1376
1377 + /**
1378 + * Returns templates directory path
1379 + *
1380 + * @return string
1381 + */
1144 1382 public function get_templates_dir() {
1145 - 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;
1146 1386 }
1147 1387
1388 + /**
1389 + * Returns templates URL
1390 + *
1391 + * @return string
1392 + */
1148 1393 public function get_templates_url() {
1149 - 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;
1150 1397 }
1151 1398
1152 1399 /**
1153 1400 * Return or output view content
1154 1401 *
1155 - * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1156 - * @param Boolean $return_instead_of_echo - what to do with the results
1157 - * @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
1158 1405 *
1159 - * @return String|Void
1406 + * @return string|void
1160 1407 */
1161 1408 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1162 1409 if ($return_instead_of_echo) ob_start();
1163 1410
@@ -1177,10 +1424,10 @@
1177 1424
1178 1425 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1179 1426
1180 1427 if (!file_exists($template_file)) {
1181 - error_log("WP Optimize: template not found: ".$template_file);
1182 - 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).")";
1183 1430 } else {
1184 1431 extract($extract_these);
1185 1432 // The following are useful variables which can be used in the template.
1186 1433 // They appear as unused, but may be used in the $template_file.
@@ -1207,9 +1454,9 @@
1207 1454 $templates_dir = $this->get_templates_dir();
1208 1455
1209 1456 if ($dh = opendir($templates_dir)) {
1210 1457 while (($file = readdir($dh)) !== false) {
1211 - if ('.' == $file || '..' == $file) continue;
1458 + if ('.' === $file || '..' === $file) continue;
1212 1459 if (is_dir($templates_dir.'/'.$file)) {
1213 1460 $template_directories[$file] = $templates_dir.'/'.$file;
1214 1461 }
1215 1462 }
@@ -1239,9 +1486,9 @@
1239 1486 * Format Bytes Into KB/MB
1240 1487 *
1241 1488 * @param mixed $bytes Number of bytes to be converted.
1242 1489 * @param integer $decimals the number of decimal digits
1243 - * @return integer return the correct format size.
1490 + * @return string return the correct format size.
1244 1491 */
1245 1492 public function format_size($bytes, $decimals = 2) {
1246 1493 if (!is_numeric($bytes)) return __('N/A', 'wp-optimize');
1247 1494
@@ -1252,9 +1499,9 @@
1252 1499 } elseif (1024 <= $bytes) {
1253 1500 $bytes = number_format($bytes / 1024, $decimals) . ' KB';
1254 1501 } elseif (1 < $bytes) {
1255 1502 $bytes = $bytes . ' bytes';
1256 - } elseif (1 == $bytes) {
1503 + } elseif (1 === (int) $bytes) {
1257 1504 $bytes = $bytes . ' byte';
1258 1505 } else {
1259 1506 $bytes = '0 bytes';
1260 1507 }
@@ -1262,15 +1509,16 @@
1262 1509 return $bytes;
1263 1510 }
1264 1511
1265 1512 /**
1266 - * Format a timestamp into a juman readable date time
1513 + * Format a timestamp into a human-readable date time
1267 1514 *
1268 - * @param int $timestamp
1515 + * @param int $timestamp Epoch timestamp to convert
1516 + * @param string $separator String separator
1269 1517 * @return string
1270 1518 */
1271 - public function format_date_time($timestamp) {
1272 - 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));
1273 1521 }
1274 1522
1275 1523 /**
1276 1524 * Executed this function on cron event.
@@ -1283,9 +1531,9 @@
1283 1531 $options = $this->get_options();
1284 1532
1285 1533 $this->log('WPO: Starting cron_action()');
1286 1534 $options->update_option('last-optimized', time());
1287 - if ('true' == $options->get_option('schedule')) {
1535 + if ('true' === $options->get_option('schedule')) {
1288 1536 $this_options = $options->get_option('auto');
1289 1537
1290 1538 // Currently the output of the optimizations is not saved/used/logged.
1291 1539 $optimizer->do_optimizations($this_options, 'auto');
@@ -1297,14 +1545,17 @@
1297 1545 * Schedule cron tasks used by plugin.
1298 1546 *
1299 1547 * @return void
1300 1548 */
1301 - public function schedule_plugin_cron_tasks() {
1549 + private function schedule_plugin_cron_tasks() {
1302 1550 if (!wp_next_scheduled('wpo_weekly_cron_tasks')) {
1303 - 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');
1304 1552 }
1305 1553
1306 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();
1307 1558 }
1308 1559
1309 1560 /**
1310 1561 * Do plugin background tasks.
@@ -1317,32 +1568,75 @@
1317 1568 }
1318 1569
1319 1570 /**
1320 1571 * This will customize a URL with a correct Affiliate link
1321 - * 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
1322 1573 *
1323 - * @param String $url - URL to be check to see if it an updraftplus match.
1324 - * @param String $text - Text to be entered within the href a tags.
1325 - * @param String $html - Any specific HTML to be added.
1326 - * @param String $class - Specify a class for the href (including the attribute label)
1327 - * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1328 - *
1329 - * @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
1330 1580 */
1331 - public function wp_optimize_url($url, $text, $html = '', $class = '', $return_instead_of_echo = false) {
1581 + public function wp_optimize_url($url, $text = '', $html = '', $attrs = '', $return_instead_of_echo = false) {
1332 1582 // Check if the URL is UpdraftPlus.
1333 1583 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
1334 - if ('' != $html) {
1335 - $result = '<a '.$class.' href="'.esc_attr($url).'">'.$html.'</a>';
1584 +
1585 + // Check if the variable $text is empty (null value included), otherwise assign $html.
1586 + $content = empty($text) ? $html : esc_html($text);
1587 +
1588 + // Check if $attrs is an array to convert the attributes into a string line.
1589 + $str_attrs = '';
1590 + if (is_array($attrs)) {
1591 + foreach ($attrs as $attr => $value) {
1592 + $str_attrs .= $attr . '="' . esc_attr($value) . '" ';
1593 + }
1336 1594 } else {
1337 - $result = '<a '.$class.' href="'.esc_attr($url).'">'.htmlspecialchars($text).'</a>';
1595 + // If $attrs is empty, the `explode` function will only return an empty array.
1596 + $attrs = explode('=', $attrs);
1597 + // Check if $attrs in positions 1 and 2 are not empty and exist; otherwise, return an empty string.
1598 + $str_attrs = !empty($attrs[0]) && !empty($attrs[1]) ? $attrs[0] . '="' . esc_attr(str_replace('"', '', $attrs[1])) . '"' : '';
1338 1599 }
1600 +
1601 + // Check if it is necessary to add a target value if the url is external
1602 + $is_external_url = $this->is_external_url($url);
1603 + if ($is_external_url) {
1604 + $str_attrs = preg_replace('/\s+target="_blank"/i', '', $str_attrs);
1605 + $str_attrs .= ' target="_blank"';
1606 + }
1607 +
1608 + $result = sprintf(
1609 + '<a href="%s" %s>%s</a>',
1610 + esc_url($url),
1611 + $str_attrs,
1612 + wp_kses_post($content)
1613 + );
1614 +
1339 1615 if ($return_instead_of_echo) return $result;
1340 - echo $result;
1616 + echo wp_kses_post($result);
1341 1617 }
1618 +
1619 + /**
1620 + * Check if a URL is external
1621 + *
1622 + * @param string $url
1623 + * @return bool
1624 + */
1625 + public function is_external_url($url) {
1626 + if (empty($url)) {
1627 + return false;
1628 + }
1629 +
1630 + $current_domain = wp_parse_url(home_url(), PHP_URL_HOST);
1631 + $url = wp_parse_url($url, PHP_URL_HOST);
1342 1632
1633 + // Compare the domains and return true if they are different
1634 + return $current_domain !== $url;
1635 + }
1636 +
1343 1637 /**
1344 - * Get an URL with an eventual affiliate ID
1638 + * Get a URL with an eventual affiliate ID
1345 1639 *
1346 1640 * @param string $url
1347 1641 * @return string
1348 1642 */
@@ -1354,9 +1648,10 @@
1354 1648
1355 1649 // Apply filters.
1356 1650 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1357 1651 }
1358 - 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;
1359 1654 }
1360 1655
1361 1656 /**
1362 1657 * Setup WPO logger(s)
@@ -1417,9 +1712,9 @@
1417 1712 // check for previous version options format.
1418 1713 $keys = array_keys($saved_loggers);
1419 1714
1420 1715 // if options stored in old format then reformat it.
1421 - if (false == is_numeric($keys[0])) {
1716 + if (false === is_numeric($keys[0])) {
1422 1717 $_saved_loggers = array();
1423 1718 foreach ($saved_loggers as $logger_id => $enabled) {
1424 1719 if ($enabled) {
1425 1720 $_saved_loggers[] = $logger_id;
@@ -1450,9 +1745,9 @@
1450 1745 foreach (array_keys($logger_options) as $option_name) {
1451 1746 if (array_key_exists($option_name, $options_keys)) {
1452 1747 $options_keys[$option_name]++;
1453 1748 } else {
1454 - $options_keys[$option_name] = 0;
1749 + $options_keys[$option_name] = 0;
1455 1750 }
1456 1751
1457 1752 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
1458 1753
@@ -1477,11 +1772,10 @@
1477 1772 $loggers[] = $logger;
1478 1773 }
1479 1774 }
1480 1775
1481 - $loggers = apply_filters('wp_optimize_loggers', $loggers);
1482 -
1483 - return $loggers;
1776 + $filtered_loggers = apply_filters('wp_optimize_loggers', $loggers);
1777 + return is_array($filtered_loggers) ? $filtered_loggers : $loggers;
1484 1778 }
1485 1779
1486 1780 /**
1487 1781 * Returns associative array with logger class name in a key and path to class file in a value.
@@ -1549,17 +1843,17 @@
1549 1843 return (is_multisite() && self::is_premium());
1550 1844 }
1551 1845
1552 1846 /**
1553 - * Returns true if current user can run optimizations.
1847 + * Returns true if the current user can run optimizations.
1554 1848 *
1555 1849 * @return bool
1556 1850 */
1557 - public function can_run_optimizations() {
1851 + public function can_run_optimizations(): bool {
1558 1852 // we don't check permissions for cron jobs.
1559 1853 if (defined('DOING_CRON') && DOING_CRON) return true;
1560 1854
1561 - 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;
1562 1856 return true;
1563 1857 }
1564 1858
1565 1859 /**
@@ -1572,21 +1866,8 @@
1572 1866 return true;
1573 1867 }
1574 1868
1575 1869 /**
1576 - * CHeck if current user can purge the cache.
1577 - *
1578 - * @return bool
1579 - */
1580 - public function can_purge_the_cache() {
1581 - if (self::is_premium()) {
1582 - return WP_Optimize_Premium()->can_purge_the_cache();
1583 - }
1584 -
1585 - return true;
1586 - }
1587 -
1588 - /**
1589 1870 * Returns list of all sites in multisite
1590 1871 *
1591 1872 * @return array
1592 1873 */
@@ -1591,13 +1872,10 @@
1591 1872 * @return array
1592 1873 */
1593 1874 public function get_sites() {
1594 1875 $sites = array();
1595 - // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
1596 1876 if (function_exists('get_sites')) {
1597 1877 $sites = get_sites(array('network_id' => null, 'deleted' => 0, 'number' => 999999));
1598 - } elseif (function_exists('wp_get_sites')) {
1599 - $sites = wp_get_sites(array('network_id' => null, 'deleted' => 0, 'limit' => 999999));
1600 1878 }
1601 1879 return $sites;
1602 1880 }
1603 1881
@@ -1603,9 +1881,9 @@
1603 1881
1604 1882 /**
1605 1883 * Returns script memory limit in megabytes.
1606 1884 *
1607 - * @param bool $memory_limit
1885 + * @param string|bool $memory_limit
1608 1886 * @return int
1609 1887 */
1610 1888 public function get_memory_limit($memory_limit = false) {
1611 1889 // Returns in megabytes
@@ -1659,9 +1937,9 @@
1659 1937 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
1660 1938 // 32MB
1661 1939 if ($mp < 33554432) {
1662 1940 $save = $wpdb->show_errors(false);
1663 - @$wpdb->query("SET GLOBAL max_allowed_packet=33554432");// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1941 + @$wpdb->query("SET GLOBAL max_allowed_packet=33554432");// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress errors from displaying
1664 1942 $wpdb->show_errors($save);
1665 1943
1666 1944 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
1667 1945 // Default to 1MB
@@ -1675,8 +1953,10 @@
1675 1953 * Converts shorthand memory notation value to bytes.
1676 1954 * From http://php.net/manual/en/function.ini-get.php
1677 1955 *
1678 1956 * @param string $val shorthand memory notation value.
1957 + *
1958 + * @return string
1679 1959 */
1680 1960 public function return_bytes($val) {
1681 1961 $val = trim($val);
1682 1962 $last = strtolower($val[strlen($val)-1]);
@@ -1708,9 +1988,9 @@
1708 1988
1709 1989 /**
1710 1990 * Close browser connection and continue script work. - Taken from UpdraftPlus
1711 1991 *
1712 - * @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)
1713 1993 * @return void
1714 1994 */
1715 1995 public function close_browser_connection($txt = '') {
1716 1996 if (!headers_sent()) {
@@ -1715,8 +1995,9 @@
1715 1995 public function close_browser_connection($txt = '') {
1716 1996 if (!headers_sent()) {
1717 1997 // Close browser connection so that it can resume AJAX polling
1718 1998 header('Content-Length: '.(empty($txt) ? '0' : 4+strlen($txt)));
1999 + header('Content-Type: application/json');
1719 2000 header('Connection: close');
1720 2001 header('Content-Encoding: none');
1721 2002 }
1722 2003
@@ -1721,9 +2002,9 @@
1721 2002 }
1722 2003
1723 2004 if (session_id()) session_write_close();
1724 2005 echo "\r\n\r\n";
1725 - echo $txt;
2006 + echo $txt; // phpcs:ignore WordPress.Security.EscapeOutput -- Output is already escaped
1726 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).
1727 2008 $ob_level = ob_get_level();
1728 2009 while ($ob_level > 0) {
1729 2010 ob_end_flush();
@@ -1730,50 +2011,22 @@
1730 2011 $ob_level--;
1731 2012 }
1732 2013 flush();
1733 2014 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
2015 + if (function_exists('litespeed_finish_request')) litespeed_finish_request();
1734 2016 }
1735 2017
1736 2018 /**
1737 - * Get the current theme's style.css headers
1738 - *
1739 - * @return array|WP_Error
1740 - */
1741 - public function get_stylesheet_headers() {
1742 - static $headers;
1743 - if (isset($headers)) return $headers;
1744 -
1745 - $style = get_template_directory_uri() . '/style.css';
1746 -
1747 - /**
1748 - * Filters wp_remote_get parameters, when checking if browser cache is enabled.
1749 - *
1750 - * @param array $request_params Default parameters
1751 - */
1752 - $request_params = apply_filters('wpoptimize_get_stylesheet_headers_args', array('timeout' => 10));
1753 -
1754 - // trying to load style.css.
1755 - $response = wp_remote_get($style, $request_params);
1756 -
1757 - if (is_a($response, 'WP_Error')) return $response;
1758 -
1759 - $headers = wp_remote_retrieve_headers($response);
1760 -
1761 - if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
1762 - $headers = $headers->getAll();
1763 - }
1764 -
1765 - return $headers;
1766 - }
1767 -
1768 - /**
1769 2019 * Try to change PHP script time limit.
1770 2020 */
1771 2021 public function change_time_limit() {
1772 2022 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
1773 2023
1774 - // Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
1775 - @set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
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
1776 2029 }
1777 2030
1778 2031 /**
1779 2032 * Does the request come from UDC
@@ -1790,11 +2043,11 @@
1790 2043 * @return boolean
1791 2044 */
1792 2045 public function template_should_include_data() {
1793 2046 /**
1794 - * Filters wether data should be included in certain templates or not.
2047 + * Filters whether data should be included in certain templates or not.
1795 2048 */
1796 - 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());
1797 2050 }
1798 2051
1799 2052 /**
1800 2053 * Load the templates for the modal window
@@ -1803,8 +2056,18 @@
1803 2056 $this->include_template('modal.php');
1804 2057 }
1805 2058
1806 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 + /**
1807 2070 * Delete transients and semaphores data from options table.
1808 2071 */
1809 2072 public function delete_transients_and_semaphores() {
1810 2073 global $wpdb;
@@ -1820,8 +2083,9 @@
1820 2083 'wpo_semaphore_%',
1821 2084 '_transient_timeout_wpo_%',
1822 2085 '_transient_wpo_%',
1823 2086 'updraft_lock_wpo_%',
2087 + 'wpo_last_scheduled_%',
1824 2088 );
1825 2089
1826 2090 $where_parts = array();
1827 2091 foreach ($masks as $mask) {
@@ -1827,84 +2091,113 @@
1827 2091 foreach ($masks as $mask) {
1828 2092 $where_parts[] = "(`option_name` LIKE '{$mask}')";
1829 2093 }
1830 2094
1831 - $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));
1832 2097 }
1833 2098
1834 2099 /**
1835 2100 * Prevents bots from indexing plugins list
2101 + *
2102 + * @param string $output
2103 + * @return string
1836 2104 */
1837 2105 public function robots_txt($output) {
1838 2106 $upload_dir = wp_upload_dir();
1839 - $path = parse_url($upload_dir['baseurl']);
1840 - $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo-plugins-tables-list.json\n";
2107 + $path = wp_parse_url($upload_dir['baseurl']);
2108 + $output .= "\nUser-agent: *";
2109 + $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo/wpo-plugins-tables-list.json\n";
1841 2110 return $output;
1842 2111 }
1843 -}
1844 2112
1845 -/**
1846 - * Plugin activation actions.
1847 - */
1848 -function wpo_activation_actions() {
1849 - // If plugin activated by not a Network Administrator then deactivate plugin and show message.
1850 - if (is_multisite() && !is_network_admin()) {
1851 - deactivate_plugins(plugin_basename(__FILE__));
1852 - wp_die(__('Only Network Administrator can activate WP-Optimize plugin.', 'wp-optimize').
1853 - ' <a href="'.admin_url('plugins.php').'">'.__('go back', 'wp-optimize').'</a>');
2113 + /**
2114 + * Returns desired enqueue version string
2115 + *
2116 + * @return string Enqueue version as string
2117 + */
2118 + public function get_enqueue_version() {
2119 + return (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
1854 2120 }
1855 2121
1856 - // On activation, check if last-optimized option exists. If not, add 'newly-activated' option.
1857 - if (!WP_Optimize()->get_options()->get_option('last-optimized', false)) {
1858 - WP_Optimize()->get_options()->update_option('newly-activated', true);
2122 + /**
2123 + * Returns script suffix string
2124 + *
2125 + * @return string empty or `.min` suffix string
2126 + */
2127 + public function get_min_or_not_string() {
2128 + return (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
1859 2129 }
1860 2130
1861 - WP_Optimize()->get_options()->set_default_options();
1862 - WP_Optimize()->get_minify()->plugin_activate();
2131 + /**
2132 + * Returns script suffix string with WPO_VERSION
2133 + *
2134 + * @return string empty or min suffix with wpo_version string
2135 + */
2136 + public function get_min_or_not_internal_string() {
2137 + return (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-' . str_replace('.', '-', WPO_VERSION) . '.min';
2138 + }
1863 2139
1864 - WP_Optimize()->get_gzip_compression()->restore();
1865 - WP_Optimize()->get_browser_cache()->restore();
2140 + /**
2141 + * Instantiate Ajax handling class
2142 + */
2143 + private function load_ajax_handler() {
2144 + WPO_Ajax::get_instance();
2145 + }
1866 2146
1867 - if (!class_exists('Updraft_Tasks_Activation')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
1868 - Updraft_Tasks_Activation::init_db();
1869 - Updraft_Tasks_Activation::reinstall_if_needed();
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 + }
1870 2155
1871 - // run premium activation actions.
1872 - if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php')) {
1873 - if (!class_exists('WP_Optimize_Premium')) {
1874 - include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
1875 - }
1876 - WP_Optimize_Premium()->plugin_activation_actions();
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();
1877 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
2186 + }
1878 2187 }
1879 2188
1880 2189 /**
1881 - * Plugin deactivation actions.
2190 + * Unschedule specific tasks:
2191 + * `wpo_cron_event2` => DB optimizations
2192 + * `wpo_weekly_cron_tasks` => ex: plugin.json auto update
2193 + *
2194 + * @return void
1882 2195 */
1883 -function wpo_deactivation_actions() {
1884 - WP_Optimize()->wpo_cron_deactivate();
1885 - WP_Optimize()->get_page_cache()->disable();
1886 - WP_Optimize()->get_minify()->plugin_deactivate();
1887 - WP_Optimize()->get_gzip_compression()->disable();
1888 - WP_Optimize()->get_browser_cache()->disable();
1889 -}
1890 -
1891 2196 function wpo_cron_deactivate() {
1892 2197 WP_Optimize()->log('running wpo_cron_deactivate()');
1893 2198 wp_clear_scheduled_hook('wpo_cron_event2');
1894 2199 wp_clear_scheduled_hook('wpo_weekly_cron_tasks');
1895 -}
1896 -
1897 -/**
1898 - * Plugin uninstall actions.
1899 - */
1900 -function wpo_uninstall_actions() {
1901 - WP_Optimize()->get_gzip_compression()->disable();
1902 - WP_Optimize()->get_browser_cache()->disable();
1903 - WP_Optimize()->get_options()->delete_all_options();
1904 - WP_Optimize()->get_minify()->plugin_uninstall();
1905 - WP_Optimize()->get_options()->wipe_settings();
1906 - WP_Optimize()->delete_transients_and_semaphores();
1907 2200 }
1908 2201
1909 2202 function WP_Optimize() {
1910 2203 return WP_Optimize::instance();