PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / wp-optimize.php

wp-optimize.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.3, at wp-optimize.php

2,525 lines 86.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 Plugin Name: WP-Optimize - Clean, Compress, Cache
4 Plugin URI: https://getwpo.com
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.3
7 Update URI: https://wordpress.org/plugins/wp-optimize/
8 Author: David Anderson, Ruhani Rabin, Team Updraft
9 Author URI: https://updraftplus.com
10 Text Domain: wp-optimize
11 Domain Path: /languages
12 License: GPLv2 or later
13 */
14
15 if (!defined('ABSPATH')) die('No direct access allowed');
16
17 // Check to make sure if WP_Optimize is already call and returns.
18 if (!class_exists('WP_Optimize')) :
19 define('WPO_VERSION', '3.2.3');
20 define('WPO_PLUGIN_URL', plugin_dir_url(__FILE__));
21 define('WPO_PLUGIN_MAIN_PATH', plugin_dir_path(__FILE__));
22 define('WPO_PREMIUM_NOTIFICATION', false);
23 define('WPO_MINIFY_PHP_VERSION_MET', version_compare(PHP_VERSION, '5.4', '>=') ? true : false);
24
25 class WP_Optimize {
26
27 public $premium_version_link = 'https://getwpo.com/buy/';
28
29 private $template_directories;
30
31 protected static $_instance = null;
32
33 protected static $_optimizer_instance = null;
34
35 protected static $_options_instance = null;
36
37 protected static $_minify_instance = null;
38
39 protected static $_notices_instance = null;
40
41 protected static $_logger_instance = null;
42
43 protected static $_browser_cache = null;
44
45 protected static $_db_info = null;
46
47 protected static $_cache = null;
48
49 protected static $_gzip_compression = null;
50
51 /**
52 * Class constructor
53 */
54 public function __construct() {
55
56 // Checks if premium is installed along with plugins needed.
57 add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
58
59 register_activation_hook(__FILE__, 'wpo_activation_actions');
60 register_deactivation_hook(__FILE__, 'wpo_deactivation_actions');
61 register_uninstall_hook(__FILE__, 'wpo_uninstall_actions');
62
63 add_action('admin_init', array($this, 'admin_init'));
64 add_action('admin_menu', array($this, 'admin_menu'));
65 add_action('admin_bar_menu', array($this, 'cache_admin_bar'), 100, 1);
66
67 add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
68 add_action('wpo_cron_event2', array($this, 'cron_action'));
69 add_filter('cron_schedules', array($this, 'cron_schedules'));
70
71 if (!$this->get_options()->get_option('installed-for', false)) $this->get_options()->update_option('installed-for', time());
72
73 if (!self::is_premium()) {
74 add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
75 }
76
77 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
78
79 add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_scripts'));
80
81 add_action('wp_ajax_wp_optimize_ajax', array($this, 'wp_optimize_ajax_handler'));
82
83 // Show update to Premium notice for non-premium multisite.
84 add_action('wpo_additional_options', array($this, 'show_multisite_update_to_premium_notice'));
85
86 // Action column (show repair button if need).
87 add_filter('wpo_tables_list_additional_column_data', array($this, 'tables_list_additional_column_data'), 15, 2);
88
89 /**
90 * Add action for display Images > Compress images tab.
91 */
92 add_action('wp_optimize_admin_page_wpo_images_smush', array($this, 'admin_page_wpo_images_smush'));
93
94 include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral.php');
95
96 include_once(WPO_PLUGIN_MAIN_PATH.'includes/backward-compatibility-functions.php');
97
98 register_shutdown_function(array($this, 'log_fatal_errors'));
99
100 $this->schedule_plugin_cron_tasks();
101
102 add_action('wpo_admin_before_closing_wrap', array($this, 'load_modal_template'), 20);
103
104 add_action('upgrader_process_complete', array($this, 'detect_active_plugins_and_themes_updates'), 10, 2);
105 }
106
107 /**
108 * Detect when an active plugin or theme is updated, and trigger an action
109 *
110 * @param object $upgrader_object
111 * @param array $options
112 * @return void
113 */
114 public function detect_active_plugins_and_themes_updates($upgrader_object, $options) {
115 if (empty($options) || !isset($options['type'])) return;
116
117 $should_purge_cache = false;
118 $skin = $upgrader_object->skin;
119 if ('plugin' === $options['type']) {
120 // A plugin is updated using the default update system (upgrader_overwrote_package is used for the upload method)
121 if (property_exists($skin, 'plugin_active') && $skin->plugin_active) {
122 $should_purge_cache = true;
123 }
124 } elseif ('theme' === $options['type']) {
125 $active_theme = get_stylesheet();
126 $parent_theme = get_template();
127 // A theme is updated using the upload system
128 if (isset($options['action']) && 'install' === $options['action'] && 'update-theme' === $skin->options['overwrite']) {
129 $updated_theme = $upgrader_object->result['destination_name'];
130 // Check if the theme is in use
131 if ($active_theme == $updated_theme || $parent_theme == $updated_theme) {
132 $should_purge_cache = true;
133 }
134 // A theme is updated using the classic update system
135 } elseif (isset($options['action']) && 'update' === $options['action'] && isset($options['themes']) && is_array($options['themes'])) {
136 // Check if the theme is in use
137 if (in_array($active_theme, $options['themes']) || in_array($parent_theme, $options['themes'])) {
138 $should_purge_cache = true;
139 }
140 }
141 }
142
143 /**
144 * Action executed when an active theme or plugin was updated
145 */
146 if ($should_purge_cache) do_action('wpo_active_plugin_or_theme_updated');
147
148 }
149
150 public function admin_page_wpo_images_smush() {
151 $options = Updraft_Smush_Manager()->get_smush_options();
152 $custom = 100 != $options['image_quality'] && 90 != $options['image_quality'] ? true : false;
153 $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()));
154 }
155
156 public static function instance() {
157 if (empty(self::$_instance)) {
158 self::$_instance = new self();
159 }
160 return self::$_instance;
161 }
162
163 public static function get_optimizer() {
164 if (empty(self::$_optimizer_instance)) {
165 if (!class_exists('WP_Optimizer')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimizer.php');
166 self::$_optimizer_instance = new WP_Optimizer();
167 }
168 return self::$_optimizer_instance;
169 }
170
171 /**
172 * Get and instanciate WP_Optimize_Minify
173 *
174 * @return WP_Optimize_Minify
175 */
176 public function get_minify() {
177 if (empty(self::$_minify_instance)) {
178 if (!class_exists('WP_Optimize_Minify')) {
179 include_once WPO_PLUGIN_MAIN_PATH.'minify/class-wp-optimize-minify.php';
180 }
181 self::$_minify_instance = new WP_Optimize_Minify();
182 }
183 return self::$_minify_instance;
184 }
185
186 public static function get_options() {
187 if (empty(self::$_options_instance)) {
188 if (!class_exists('WP_Optimize_Options')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-options.php');
189 self::$_options_instance = new WP_Optimize_Options();
190 }
191 return self::$_options_instance;
192 }
193
194 public static function get_notices() {
195 if (empty(self::$_notices_instance)) {
196 if (!class_exists('WP_Optimize_Notices')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/wp-optimize-notices.php');
197 self::$_notices_instance = new WP_Optimize_Notices();
198 }
199 return self::$_notices_instance;
200 }
201
202 /**
203 * Returns instance if WPO_Page_Cache class.
204 *
205 * @return WPO_Page_Cache
206 */
207 public function get_page_cache() {
208 if (!class_exists('WPO_Page_Cache')) include_once(WPO_PLUGIN_MAIN_PATH.'cache/class-wpo-page-cache.php');
209
210 return WPO_Page_Cache::instance();
211 }
212
213 /**
214 * Returns instance if WP_Optimize_WebP class.
215 *
216 * @return WP_Optimize_WebP
217 */
218 public function get_webp_instance() {
219 if (defined('WPO_USE_WEBP_CONVERSION') && true === WPO_USE_WEBP_CONVERSION) {
220 if (!class_exists('WP_Optimize_WebP')) {
221 include_once WPO_PLUGIN_MAIN_PATH . 'webp/class-wp-optimize-webp.php';
222 }
223 return WP_Optimize_WebP::get_instance();
224 }
225 }
226
227 /**
228 * Detects if the platform is Kinsta or not
229 *
230 * @return bool Returns true if it is Kinsta platform, otherwise returns false
231 */
232 private function is_kinsta() {
233 return isset($_SERVER['KINSTA_CACHE_ZONE']);
234 }
235
236 /**
237 * Detects whether the server handles cache. eg. Nginx cache
238 */
239 private function does_server_handles_cache() {
240 return $this->is_kinsta();
241 }
242
243 /**
244 * Detects whether the server supports table optimization.
245 *
246 * Some servers prevent table optimization
247 * because InnoDB engine does not optimize table
248 * instead it drops tables and recreate them
249 * which results in elevated disk write operations
250 */
251 public function does_server_allows_table_optimization() {
252 return !$this->is_kinsta();
253 }
254
255 /**
256 * Detects whether the server supports local webp conversion tools
257 */
258 private function does_server_allows_local_webp_conversion() {
259 return !$this->is_kinsta();
260 }
261
262 /**
263 * Create instance of WP_Optimize_Browser_Cache.
264 *
265 * @return WP_Optimize_Browser_Cache
266 */
267 public static function get_browser_cache() {
268 if (empty(self::$_browser_cache)) {
269 if (!class_exists('WP_Optimize_Browser_Cache')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-browser-cache.php');
270 self::$_browser_cache = new WP_Optimize_Browser_Cache();
271 }
272 return self::$_browser_cache;
273 }
274
275 /**
276 * Returns WP_Optimize_Database_Information instance.
277 *
278 * @return WP_Optimize_Database_Information
279 */
280 public function get_db_info() {
281 if (empty(self::$_db_info)) {
282 if (!class_exists('WP_Optimize_Database_Information')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/wp-optimize-database-information.php');
283 self::$_db_info = new WP_Optimize_Database_Information();
284 }
285 return self::$_db_info;
286 }
287
288 /**
289 * Returns instance of WP_Optimize_Gzip_Compression.
290 *
291 * @return WP_Optimize_Gzip_Compression
292 */
293 static public function get_gzip_compression() {
294 if (empty(self::$_gzip_compression)) {
295 if (!class_exists('WP_Optimize_Gzip_Compression')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-gzip-compression.php');
296 self::$_gzip_compression = new WP_Optimize_Gzip_Compression();
297 }
298 return self::$_gzip_compression;
299 }
300
301 /**
302 * Create instance of WP_Optimize_Htaccess.
303 *
304 * @param string $htaccess_file absolute path to htaccess file, by default it use .htaccess in WordPress root directory.
305 * @return WP_Optimize_Htaccess
306 */
307 public static function get_htaccess($htaccess_file = '') {
308 if (!class_exists('WP_Optimize_Cache')) {
309 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-wp-optimize-htaccess.php');
310 }
311
312 return new WP_Optimize_Htaccess($htaccess_file);
313
314 }
315
316 /**
317 * Return instance of Updraft_Logger
318 *
319 * @return Updraft_Logger
320 */
321 public static function get_logger() {
322 if (empty(self::$_logger_instance)) {
323 include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraft-logger.php');
324 self::$_logger_instance = new Updraft_Logger();
325 }
326 return self::$_logger_instance;
327 }
328
329 /**
330 * Check if the current page belongs to WP-Optimize.
331 *
332 * @return bool
333 */
334 public function is_wpo_page() {
335 $current_screen = get_current_screen();
336
337 return (bool) preg_match('/wp\-optimize/i', $current_screen->id);
338 }
339
340 /**
341 * Enqueue scripts and styles on WP-Optimize pages.
342 */
343 public function admin_enqueue_scripts() {
344 $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
345 $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
346 $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
347
348 // Register or enqueue common scripts
349 wp_register_script('wp-optimize-send-command', WPO_PLUGIN_URL.'js/send-command'.$min_or_not_internal.'.js', array(), $enqueue_version);
350 wp_localize_script('wp-optimize-send-command', 'wp_optimize_send_command_data', array('nonce' => wp_create_nonce('wp-optimize-ajax-nonce')));
351 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
352
353 // load scripts and styles only on WP-Optimize pages.
354 if (!$this->is_wpo_page()) return;
355
356 wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);
357
358 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
359 wp_enqueue_script('wp-optimize-modal', WPO_PLUGIN_URL.'js/modal'.$min_or_not_internal.'.js', array('jquery', 'backbone', 'wp-util'), $enqueue_version);
360 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);
361 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'), $enqueue_version);
362 wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
363 // Using tablesorter to help with organising the DB size on Table Information
364 // https://github.com/Mottie/tablesorter
365 wp_enqueue_script('tablesorter-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter'.$min_or_not.'.js', array('jquery', 'wp-optimize-send-command'), $enqueue_version);
366
367 wp_enqueue_script('tablesorter-widgets-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter.widgets'.$min_or_not.'.js', array('jquery'), $enqueue_version);
368
369 // wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);
370
371 $js_variables = $this->wpo_js_translations();
372 $js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
373
374 wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
375
376 do_action('wpo_premium_scripts_styles', $min_or_not_internal, $min_or_not, $enqueue_version);
377 }
378
379 /**
380 * Enqueue any required front-end scripts
381 *
382 * @return void
383 */
384 public function frontend_enqueue_scripts() {
385 if (!current_user_can('manage_options') || !is_admin_bar_showing()) return;
386 $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
387 $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
388
389 // Register or enqueue common scripts
390 wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
391 }
392
393 /**
394 * Load Task Manager
395 */
396 public function get_task_manager() {
397 include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
398
399 Updraft_Tasks_Activation::check_updates();
400
401 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-meta.php');
402 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-options.php');
403 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
404
405 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-task.php');
406 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-manager.php');
407
408 return Updraft_Smush_Manager();
409 }
410
411 /**
412 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
413 *
414 * @returns Boolean
415 */
416 public static function is_premium() {
417 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && function_exists('WP_Optimize_Premium')) {
418 $wp_optimize_premium = WP_Optimize_Premium();
419 if (is_a($wp_optimize_premium, 'WP_Optimize_Premium')) return true;
420 }
421 return false;
422 }
423
424 /**
425 * Check if script running on Apache web server. $is_apache is set in wp-includes/vars.php. Also returns true if the server uses litespeed.
426 *
427 * @return bool
428 */
429 public function is_apache_server() {
430 global $is_apache;
431 return $is_apache;
432 }
433
434 /**
435 * Check if script running on IIS web server.
436 *
437 * @return bool
438 */
439 public function is_IIS_server() {
440 global $is_IIS, $is_iis7;
441 return $is_IIS || $is_iis7;
442 }
443
444 /**
445 * Check if Apache module or modules active.
446 *
447 * @param string|array $module - single Apache module name or list of Apache module names.
448 *
449 * @return bool|null - if null, the result was indeterminate
450 */
451 public function is_apache_module_loaded($module) {
452 if (!$this->is_apache_server()) return false;
453
454 if (!function_exists('apache_get_modules')) return null;
455
456 $module_loaded = true;
457
458 if (is_array($module)) {
459 foreach ($module as $single_module) {
460 if (!in_array($single_module, apache_get_modules())) {
461 $module_loaded = false;
462 break;
463 }
464 }
465 } else {
466 $module_loaded = in_array($module, apache_get_modules());
467 }
468
469 return $module_loaded;
470 }
471
472 /**
473 * 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.
474 */
475 public function plugins_loaded() {
476
477 if (is_multisite()) {
478 add_action('network_admin_menu', array($this, 'admin_menu'));
479 }
480
481 if ($this->does_server_handles_cache()) {
482 add_filter('wp_optimize_admin_page_wpo_cache_tabs', array($this, 'filter_cache_tabs'), 99, 1);
483
484 // If newly migrated to server that handles cache, disable wpo cache
485 $cache = $this->get_page_cache();
486 if ($cache->is_enabled()) {
487 $cache->disable();
488 }
489 }
490
491 add_filter('robots_txt', array($this, 'robots_txt'), 99, 1);
492
493 // Run Premium loader if it exists
494 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && !class_exists('WP_Optimize_Premium')) {
495 include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
496 }
497
498 // load defaults
499 WP_Optimize()->get_options()->set_default_options();
500
501 // Initialize loggers.
502 $this->setup_loggers();
503
504 if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
505 if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
506 deactivate_plugins($free_plugin);
507
508 // If WPO_ADVANCED_CACHE is defined, we empty advanced-cache.php to regenerate later. Otherwise it contains the path to free.
509 if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
510 $advanced_cache_filename = trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
511
512 if (!is_file($advanced_cache_filename) && is_writable(dirname($advanced_cache_filename)) || (is_file($advanced_cache_filename) && is_writable($advanced_cache_filename))) {
513 file_put_contents($advanced_cache_filename, '');
514 }
515 }
516
517 // Registers the notice letting the user know it cannot be active if premium is active.
518 add_action('admin_notices', array($this, 'show_admin_notice_premium'));
519 return;
520 }
521
522 // Loads the task manager
523 $this->get_task_manager();
524
525 // Loads the language file.
526 load_plugin_textdomain('wp-optimize', false, dirname(plugin_basename(__FILE__)) . '/languages');
527
528 // Load page cache.
529 $this->get_page_cache();
530 $this->init_page_cache();
531
532 // Include minify
533 $this->get_minify();
534 $this->run_updates();
535 $this->get_webp_instance();
536 }
537
538 /**
539 * Filter cache tabs (when it is Kinsta)
540 *
541 * @param array $tabs An array of tabs
542 *
543 * @return array $tabs An array of tabs
544 */
545 public function filter_cache_tabs($tabs) {
546 unset($tabs['preload']);
547 unset($tabs['advanced']);
548 unset($tabs['gzip']);
549 unset($tabs['settings']);
550 return $tabs;
551 }
552
553 /**
554 * Check whether one of free/Premium is active (whether it is this instance or not)
555 *
556 * @param String $which - 'free' or 'premium'
557 *
558 * @return String|Boolean - plugin path (if installed) or false if not
559 */
560 private function is_active($which = 'free') {
561 $active_plugins = $this->get_active_plugins();
562 foreach ($active_plugins as $file) {
563 if ('wp-optimize.php' == basename($file)) {
564 $plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
565 if (('free' == $which && !file_exists($plugin_dir.'/premium.php')) || ('free' != $which && file_exists($plugin_dir.'/premium.php'))) return $file;
566 }
567 }
568 return false;
569 }
570
571 /**
572 * Gets an array of plugins active on either the current site, or site-wide
573 *
574 * @return Array - a list of plugin paths (relative to the plugin directory)
575 */
576 private function get_active_plugins() {
577
578 // Gets all active plugins on the current site
579 $active_plugins = get_option('active_plugins');
580
581 if (is_multisite()) {
582 $network_active_plugins = get_site_option('active_sitewide_plugins');
583 if (!empty($network_active_plugins)) {
584 $network_active_plugins = array_keys($network_active_plugins);
585 $active_plugins = array_merge($active_plugins, $network_active_plugins);
586 }
587 }
588
589 return $active_plugins;
590 }
591
592 /**
593 * This function checks whether a specific plugin is installed, and returns information about it
594 *
595 * @param string $name Specify "Plugin Name" to return details about it.
596 * @return array Returns an array of details such as if installed, the name of the plugin and if it is active.
597 */
598 public function is_installed($name) {
599
600 // Needed to have the 'get_plugins()' function
601 include_once(ABSPATH.'wp-admin/includes/plugin.php');
602
603 // Gets all plugins available
604 $get_plugins = get_plugins();
605
606 $active_plugins = $this->get_active_plugins();
607
608 $plugin_info = array();
609 $plugin_info['installed'] = false;
610 $plugin_info['active'] = false;
611
612 // Loops around each plugin available.
613 foreach ($get_plugins as $key => $value) {
614 // If the plugin name matches that of the specified name, it will gather details.
615 if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
616 $plugin_info['installed'] = true;
617 $plugin_info['name'] = $key;
618 $plugin_info['version'] = $value['Version'];
619 if (in_array($key, $active_plugins)) {
620 $plugin_info['active'] = true;
621 }
622 break;
623 }
624 return $plugin_info;
625 }
626
627 /**
628 * This is a notice to show users that premium is installed
629 */
630 public function show_admin_notice_premium() {
631 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>';
632 if (isset($_GET['activate'])) unset($_GET['activate']);
633 }
634
635 /**
636 * Show update to Premium notice for non-premium multisite.
637 */
638 public function show_multisite_update_to_premium_notice() {
639 if (!is_multisite() || self::is_premium()) return;
640
641 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>';
642 }
643
644 public function admin_init() {
645 $pagenow = $GLOBALS['pagenow'];
646
647 $this->register_template_directories();
648
649 if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
650 $options = $this->get_options();
651
652 $dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);
653
654 if (file_exists(WPO_PLUGIN_MAIN_PATH . '/index.html')) {
655 $installed = filemtime(WPO_PLUGIN_MAIN_PATH . '/index.html');
656 $installed_for = (time() - $installed);
657 }
658
659 if (($installed && time() > $dismissed_until && $installed_for > (14 * 86400) && !defined('WP_OPTIMIZE_NOADS_B')) || (defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
660 add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead'));
661 }
662 }
663 $this->install_or_update_notice = $this->get_install_or_update_notice();
664 }
665
666 /**
667 * Get the install or update notice instance
668 *
669 * @return WP_Optimize_Install_Or_Update_Notice
670 */
671 private function get_install_or_update_notice() {
672 static $instance = null;
673 if (is_a($instance, 'WP_Optimize_Install_Or_Update_Notice')) return $instance;
674 include_once WPO_PLUGIN_MAIN_PATH . 'includes/class-wp-optimize-install-or-update-notice.php';
675 $instance = new WP_Optimize_Install_Or_Update_Notice();
676 return $instance;
677 }
678
679 public function show_admin_notice_upgradead() {
680 $this->include_template('notices/thanks-for-using-main-dash.php');
681 }
682
683 public function capability_required() {
684 return apply_filters('wp_optimize_capability_required', 'manage_options');
685 }
686
687 public function wp_optimize_ajax_handler() {
688 $nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
689
690 if (!wp_verify_nonce($nonce, 'wp-optimize-ajax-nonce') || empty($_POST['subaction'])) {
691 wp_send_json(array(
692 'result' => false,
693 'error_code' => 'security_check',
694 'error_message' => __('The security check failed; try refreshing the page.', 'wp-optimize')
695 ));
696 }
697
698 $subaction = $_POST['subaction'];
699 $data = isset($_POST['data']) ? $_POST['data'] : null;
700
701 if (!current_user_can($this->capability_required())) {
702 wp_send_json(array(
703 'result' => false,
704 'error_code' => 'security_check',
705 'error_message' => __('You are not allowed to run this command.', 'wp-optimize')
706 ));
707 }
708
709
710 // Currently the settings are only available to network admins.
711 if (is_multisite() && !current_user_can('manage_network_options')) {
712 /**
713 * Filters the commands allowed to the subsite admins. Other commands are only available to network admin. Only used in a multisite context.
714 */
715 $allowed_commands = apply_filters('wpo_multisite_allowed_commands', array('check_server_status', 'compress_single_image', 'restore_single_image'));
716 if (!in_array($subaction, $allowed_commands)) wp_send_json(array(
717 'result' => false,
718 'error_code' => 'update_failed',
719 'error_message' => __('Options can only be saved by network admin', 'wp-optimize')
720 ));
721 }
722
723 $options = $this->get_options();
724
725 $results = array();
726
727 // Some commands that are available via AJAX only.
728 if (in_array($subaction, array('dismiss_dash_notice_until', 'dismiss_season'))) {
729 $options->update_option($subaction, (time() + 366 * 86400));
730 } elseif (in_array($subaction, array('dismiss_page_notice_until', 'dismiss_notice'))) {
731 $options->update_option($subaction, (time() + 84 * 86400));
732 } elseif ('dismiss_review_notice' == $subaction) {
733 if (empty($data['dismiss_forever'])) {
734 $options->update_option($subaction, time() + 84*86400);
735 } else {
736 $options->update_option($subaction, 100 * (365.25 * 86400));
737 }
738 } else {
739 // Other commands, available for any remote method.
740 if (!class_exists('WP_Optimize_Commands')) include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-commands.php');
741 if (!class_exists('WP_Optimize_Minify_Commands')) include_once(WPO_PLUGIN_MAIN_PATH . 'minify/class-wp-optimize-minify-commands.php');
742 if (!class_exists('WP_Optimize_Cache_Commands')) include_once(WPO_PLUGIN_MAIN_PATH . 'cache/class-cache-commands.php');
743
744 $commands = new WP_Optimize_Commands();
745 $minify_commands = new WP_Optimize_Minify_Commands();
746
747
748 if (self::is_premium()) {
749 if (!class_exists('WP_Optimize_Cache_Commands_Premium')) include_once(WPO_PLUGIN_MAIN_PATH . 'cache/class-cache-commands-premium.php');
750 $cache_commands = new WP_Optimize_Cache_Commands_Premium();
751 } else {
752 $cache_commands = new WP_Optimize_Cache_Commands();
753 }
754
755 // check if called command not in main commands class and exist in cache commands class then change class.
756 if (!is_callable(array($commands, $subaction)) && is_callable(array($minify_commands, $subaction))) {
757 $commands = $minify_commands;
758 }
759
760 // check if called command not in main commands class and exist in cache commands class then change class.
761 if (!is_callable(array($commands, $subaction)) && is_callable(array($cache_commands, $subaction))) {
762 $commands = $cache_commands;
763 }
764
765 if (!is_callable(array($commands, $subaction))) {
766 error_log("WP-Optimize: ajax_handler: no such command (".$subaction.")");
767 $results = array(
768 'result' => false,
769 'error_code' => 'command_not_found',
770 'error_message' => sprintf(__('The command "%s" was not found', 'wp-optimize'), $subaction)
771 );
772 } else {
773 $results = call_user_func(array($commands, $subaction), $data);
774
775 // clean status box content, it broke json sometimes.
776 if (isset($results['status_box_contents'])) {
777 $results['status_box_contents'] = str_replace(array("\n", "\t"), '', $results['status_box_contents']);
778 }
779
780 if (is_wp_error($results)) {
781 $results = array(
782 'result' => false,
783 'error_code' => $results->get_error_code(),
784 'error_message' => $results->get_error_message(),
785 'error_data' => $results->get_error_data(),
786 );
787 }
788
789 // if nothing was returned for some reason, set as result null.
790 if (empty($results)) {
791 $results = array(
792 'result' => null
793 );
794 }
795 }
796 }
797
798 $result = json_encode($results);
799
800 // Requires PHP 5.3+
801 $json_last_error = function_exists('json_last_error') ? json_last_error() : false;
802
803 // if json_encode returned error then return error.
804 if ($json_last_error) {
805 $result = array(
806 'result' => false,
807 'error_code' => $json_last_error,
808 'error_message' => 'json_encode error : '.$json_last_error,
809 'error_data' => '',
810 );
811
812 $result = json_encode($result);
813 }
814
815 echo $result;
816
817 die;
818 }
819
820 /**
821 * Builds the Tabs that should be displayed
822 *
823 * @return array Returns all tabs specified
824 */
825 public function get_tabs($page) {
826 // define tabs for pages.
827 $pages_tabs = array(
828 'WP-Optimize' => array(
829 'optimize' => __('Optimizations', 'wp-optimize'),
830 'tables' => __('Tables', 'wp-optimize'),
831 'settings' => __('Settings', 'wp-optimize'),
832 ),
833 'wpo_images' => array(
834 'smush' => __('Compress images', 'wp-optimize'),
835 'unused' => __('Unused images and sizes', 'wp-optimize').'<span class="menu-pill premium-only">Premium</span>',
836 'lazyload' => __('Lazy-load', 'wp-optimize').'<span class="menu-pill premium-only">Premium</span>',
837 ),
838 'wpo_cache' => array(
839 'cache' => __('Page cache', 'wp-optimize'),
840 'preload' => __('Preload', 'wp-optimize'),
841 'advanced' => __('Advanced settings', 'wp-optimize'),
842 'gzip' => __('Gzip compression', 'wp-optimize'),
843 'settings' => __('Static file headers', 'wp-optimize') // Adds a settings tab
844 ),
845 'wpo_minify' => array(
846 "status" => __('Minify status', 'wp-optimize'),
847 "js" => __('JavaScript', 'wp-optimize').'<span class="menu-pill disabled hidden">'.__('Disabled', 'wp-optimize').'</span>',
848 "css" => __('CSS', 'wp-optimize').'<span class="menu-pill disabled hidden">'.__('Disabled', 'wp-optimize').'</span>',
849 "font" => __('Fonts', 'wp-optimize'),
850 "preload" => __('Preload', 'wp-optimize'),
851 "settings" => __('Settings', 'wp-optimize'),
852 "advanced" => __('Advanced', 'wp-optimize')
853 ),
854 'wpo_settings' => array(
855 'settings' => array(
856 'title' => __('Settings', 'wp-optimize'),
857 ),
858 ),
859 'wpo_support' => array('support' => __('Support / FAQs', 'wp-optimize')),
860 'wpo_mayalso' => array('may_also' => __('Premium / Plugin family', 'wp-optimize')),
861 );
862
863 $tabs = (array_key_exists($page, $pages_tabs)) ? $pages_tabs[$page] : array();
864
865 return apply_filters('wp_optimize_admin_page_'.$page.'_tabs', $tabs);
866 }
867
868 /**
869 * Main page structure.
870 */
871 public function display_admin() {
872 $capability_required = $this->capability_required();
873
874 if (!current_user_can($capability_required) || (!$this->can_run_optimizations() && !$this->can_manage_options())) {
875 echo "Permission denied.";
876 return;
877 }
878
879 $this->register_admin_content();
880
881 echo '<div id="wp-optimize-wrap">';
882
883 $this->include_template('admin-page-header.php', false, array('show_notices' => !($this->get_install_or_update_notice()->show_current_notice())));
884
885 do_action('wpo_admin_after_header');
886
887 echo '<div id="actions-results-area"></div>';
888
889 $pages = $this->get_submenu_items();
890
891 foreach ($pages as $page) {
892 if (isset($page['menu_slug'])) {
893 $this->display_admin_page($page['menu_slug']);
894 }
895 }
896
897 do_action('wpo_admin_before_closing_wrap');
898
899 // closes main plugin wrapper div. #wp-optimize-wrap
900 echo '</div><!-- END #wp-optimize-wrap -->';
901
902 }
903
904 /**
905 * Prepare and display admin page with $page id.
906 *
907 * @param string $page wp-optimize page id i.e. dashboard, database, images, cache, ...
908 */
909 public function display_admin_page($page) {
910
911 $active_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
912
913 echo '<div class="wpo-page' . ($active_page == $page ? ' active' : '') . '" data-whichpage="'.$page.'">';
914
915 echo '<div class="wpo-main">';
916
917 // get defined tabs for $page.
918 $tabs = $this->get_tabs($page);
919
920 // if no tabs defined for $page then use $page as $active_tab for load template, doing related actions e t.c.
921 if (empty($tabs)) {
922 $active_tab = $page;
923 } else {
924 $tab_keys = array_keys($tabs);
925 $default_tab = apply_filters('wp_optimize_admin_'.$page.'_default_tab', $tab_keys[0]);
926 $active_tab = isset($_GET['tab']) ? substr($_GET['tab'], 12) : $default_tab;
927 if (!in_array($active_tab, array_keys($tabs))) $active_tab = $default_tab;
928 }
929
930 do_action('wp_optimize_admin_page_'.$page, $active_tab);
931
932 // if tabs defined then display
933 if (!empty($tabs)) {
934 $this->include_template('admin-page-header-tabs.php', false, array('page' => $page, 'active_tab' => $active_tab, 'tabs' => $tabs, 'wpo_is_premium' => self::is_premium()));
935 }
936
937 foreach ($tabs as $tab_id => $tab_description) {
938 // output wrap div for tab with id #wp-optimize-nav-tab-contents-'.$page.'-'.$tab_id
939 echo '<div class="wp-optimize-nav-tab-contents" id="wp-optimize-nav-tab-'.$page.'-'.$tab_id.'-contents" '.(($tab_id == $active_tab) ? '' : 'style="display:none;"').'>';
940
941 echo '<div class="postbox wpo-tab-postbox">';
942 // call action for generate tab content.
943
944 do_action('wp_optimize_admin_page_'.$page.'_'.$tab_id);
945
946 // closes postbox.
947 echo '</div><!-- END .postbox -->';
948 // closes tab wrapper.
949 echo '</div><!-- END .wp-optimize-nav-tab-contents -->';
950 }
951
952 echo '</div><!-- END .wpo-main -->';
953
954 do_action('wp_optimize_admin_after_page_'.$page, $active_tab);
955
956 echo '</div><!-- END .wpo-page -->';
957
958 }
959
960 /**
961 * Define required actions for admin pages.
962 */
963 public function register_admin_content() {
964
965 do_action('wp_optimize_register_admin_content');
966
967 /**
968 * SETTINGS
969 */
970 add_action('wp_optimize_admin_page_wpo_settings_settings', array($this, 'output_dashboard_settings_tab'), 20);
971
972 /**
973 * Premium / other plugins
974 */
975 add_action('wp_optimize_admin_page_wpo_mayalso_may_also', array($this, 'output_dashboard_other_plugins_tab'), 20);
976
977 /**
978 * DATABASE
979 */
980 add_action('wp_optimize_admin_page_WP-Optimize_optimize', array($this, 'output_database_optimize_tab'), 20);
981 add_action('wp_optimize_admin_page_WP-Optimize_tables', array($this, 'output_database_tables_tab'), 20);
982 add_action('wp_optimize_admin_page_WP-Optimize_settings', array($this, 'output_database_settings_tab'), 20);
983
984 /**
985 * CACHE
986 */
987 add_action('wp_optimize_admin_page_wpo_cache_cache', array($this, 'output_page_cache_tab'), 20);
988 if (!$this->does_server_handles_cache()) {
989 add_action('wp_optimize_admin_page_wpo_cache_preload', array($this, 'output_page_cache_preload_tab'), 20);
990 add_action('wp_optimize_admin_page_wpo_cache_advanced', array($this, 'output_page_cache_advanced_tab'), 20);
991 }
992 add_action('wp_optimize_admin_page_wpo_cache_gzip', array($this, 'output_cache_gzip_tab'), 20);
993 add_action('wp_optimize_admin_page_wpo_cache_settings', array($this, 'output_cache_settings_tab'), 20);
994 add_action('wpo_page_cache_advanced_settings', array($this, 'output_cloudflare_settings'), 20);
995 /**
996 * SUPPORT
997 */
998 add_action('wp_optimize_admin_page_wpo_support_support', array($this, 'output_dashboard_support_tab'), 20);
999 // Display Support page.
1000
1001 if (!self::is_premium()) {
1002 /**
1003 * Add action for display Images > Unused images and sizes tab.
1004 */
1005 add_action('wp_optimize_admin_page_wpo_images_unused', array($this, 'admin_page_wpo_images_unused'));
1006
1007 /**
1008 * Add action for display Dashboard > Lazyload tab.
1009 */
1010 add_action('wp_optimize_admin_page_wpo_images_lazyload', array($this, 'admin_page_wpo_images_lazyload'));
1011 } else {
1012 /**
1013 * Add filter for display footer review message and link.
1014 */
1015 add_filter('admin_footer_text', array($this, 'display_footer_review_message'));
1016 }
1017 }
1018
1019 /**
1020 * Database settings
1021 */
1022 public function output_database_settings_tab() {
1023
1024 if ($this->can_manage_options()) {
1025 $this->include_template('database/settings.php');
1026 } else {
1027 $this->prevent_manage_options_info();
1028 }
1029 }
1030
1031 /**
1032 * Dashboard settings
1033 */
1034 public function output_dashboard_settings_tab() {
1035 $options = $this->get_options();
1036
1037 if ('POST' == $_SERVER['REQUEST_METHOD']) {
1038 // Nonce check.
1039 check_admin_referer('wpo_settings');
1040
1041 $output = $options->save_settings($_POST);
1042
1043 if (isset($_POST['wp-optimize-settings'])) {
1044 // save settings request sent.
1045 $output = $options->save_settings($_POST);
1046 }
1047
1048 $this->wpo_render_output_messages($output);
1049 }
1050
1051 if ($this->can_manage_options()) {
1052 $this->include_template('settings/settings.php');
1053 } else {
1054 $this->prevent_manage_options_info();
1055 }
1056 }
1057
1058 /**
1059 * Dashboard support tab
1060 */
1061 public function output_dashboard_support_tab() {
1062 WP_Optimize()->include_template('settings/support-and-faqs.php');
1063 }
1064
1065 /**
1066 * Dashboard Other plugins / premium tab
1067 */
1068 public function output_dashboard_other_plugins_tab() {
1069 $this->include_template('settings/may-also-like.php');
1070 }
1071
1072 /**
1073 * Cache tab
1074 */
1075 public function output_page_cache_tab() {
1076 $wpo_cache = $this->get_page_cache();
1077 $wpo_cache_options = $wpo_cache->config->get();
1078 $display = $wpo_cache->is_enabled() ? "style='display:block'" : "style='display:none'";
1079
1080 WP_Optimize()->include_template('cache/page-cache.php', false, array(
1081 'wpo_cache' => $wpo_cache,
1082 'active_cache_plugins' => WP_Optimize_Detect_Cache_Plugins::instance()->get_active_cache_plugins(),
1083 'wpo_cache_options' => $wpo_cache_options,
1084 'cache_size' => $this->get_page_cache()->get_cache_size(),
1085 'display' => $display,
1086 'can_purge_the_cache' => $this->can_purge_the_cache(),
1087 'does_server_handles_cache' => $this->does_server_handles_cache(),
1088 ));
1089 }
1090
1091 /**
1092 * Preload tab
1093 */
1094 public function output_page_cache_preload_tab() {
1095 $wpo_cache = $this->get_page_cache();
1096 $wpo_cache_options = $wpo_cache->config->get();
1097 $wpo_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance();
1098 $is_running = $wpo_cache_preloader->is_running();
1099 $status = $wpo_cache_preloader->get_status_info();
1100
1101 WP_Optimize()->include_template('cache/page-cache-preload.php', false, array(
1102 'wpo_cache_options' => $wpo_cache_options,
1103 'is_running' => $is_running,
1104 'status_message' => isset($status['message']) ? $status['message'] : '',
1105 'schedule_options' => array(
1106 'wpo_use_cache_lifespan' => __('Same as cache lifespan', 'wp-optimize'),
1107 'wpo_daily' => __('Daily', 'wp-optimize'),
1108 'wpo_weekly' => __('Weekly', 'wp-optimize'),
1109 'wpo_fortnightly' => __('Fortnightly', 'wp-optimize'),
1110 'wpo_monthly' => __('Monthly (approx. - every 30 days)', 'wp-optimize')
1111 )
1112 ));
1113 }
1114
1115 /**
1116 * Advanced tab
1117 */
1118 public function output_page_cache_advanced_tab() {
1119 $wpo_cache = $this->get_page_cache();
1120 $wpo_cache_options = $wpo_cache->config->get();
1121
1122 $cache_exception_urls = is_array($wpo_cache_options['cache_exception_urls']) ? join("\n", $wpo_cache_options['cache_exception_urls']) : '';
1123 $cache_exception_cookies = is_array($wpo_cache_options['cache_exception_cookies']) ? join("\n", $wpo_cache_options['cache_exception_cookies']) : '';
1124 $cache_exception_browser_agents = is_array($wpo_cache_options['cache_exception_browser_agents']) ? join("\n", $wpo_cache_options['cache_exception_browser_agents']) : '';
1125
1126 WP_Optimize()->include_template('cache/page-cache-advanced.php', false, array(
1127 'wpo_cache' => $this->get_page_cache(),
1128 'wpo_cache_options' => $wpo_cache_options,
1129 'cache_exception_urls' => $cache_exception_urls,
1130 'cache_exception_cookies' => $cache_exception_cookies,
1131 'cache_exception_browser_agents' => $cache_exception_browser_agents,
1132 ));
1133 }
1134
1135 /**
1136 * Gzip tab
1137 */
1138 public function output_cache_gzip_tab() {
1139 $wpo_gzip_compression = $this->get_gzip_compression();
1140 $wpo_gzip_compression_enabled = $wpo_gzip_compression->is_gzip_compression_enabled(true);
1141 $wpo_gzip_headers_information = $wpo_gzip_compression->get_headers_information();
1142 $is_cloudflare_site = $this->is_cloudflare_site();
1143 $is_gzip_compression_section_exists = $wpo_gzip_compression->is_gzip_compression_section_exists();
1144 $wpo_gzip_compression_enabled_by_wpo = $is_gzip_compression_section_exists && $wpo_gzip_compression_enabled && !$is_cloudflare_site && !(is_array($wpo_gzip_headers_information) && 'brotli' == $wpo_gzip_headers_information['compression']);
1145
1146 WP_Optimize()->include_template('cache/gzip-compression.php', false, array(
1147 'wpo_gzip_headers_information' => $wpo_gzip_headers_information,
1148 'wpo_gzip_compression_enabled' => $wpo_gzip_compression_enabled,
1149 'is_cloudflare_site' => $is_cloudflare_site,
1150 'wpo_gzip_compression_enabled_by_wpo' => $wpo_gzip_compression_enabled_by_wpo,
1151 'wpo_gzip_compression_settings_added' => $is_gzip_compression_section_exists,
1152 'info_link' => 'https://getwpo.com/gzip-compression-explained/',
1153 'faq_link' => 'https://getwpo.com/gzip-faq-link/',
1154 'class_name' => (!is_wp_error($wpo_gzip_compression_enabled) && $wpo_gzip_compression_enabled ? 'wpo-enabled' : 'wpo-disabled')
1155 ));
1156 }
1157
1158 /**
1159 * Cache tab
1160 */
1161 public function output_cache_settings_tab() {
1162
1163 $wpo_browser_cache = $this->get_browser_cache();
1164 $wpo_browser_cache_enabled = $wpo_browser_cache->is_enabled();
1165
1166 WP_Optimize()->include_template('cache/browser-cache.php', false, array(
1167 'wpo_browser_cache_enabled' => $wpo_browser_cache_enabled,
1168 'is_cloudflare_site' => $this->is_cloudflare_site(),
1169 'wpo_browser_cache_settings_added' => $wpo_browser_cache->is_browser_cache_section_exists(),
1170 'class_name' => (true === $wpo_browser_cache_enabled ? 'wpo-enabled' : 'wpo-disabled'),
1171 'wpo_browser_cache_expire_days' => $this->get_options()->get_option('browser_cache_expire_days', '28'),
1172 'wpo_browser_cache_expire_hours' => $this->get_options()->get_option('browser_cache_expire_hours', '0'),
1173 'info_link' => 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching',
1174 'faq_link' => 'https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04',
1175 ));
1176 }
1177
1178 /**
1179 * Check if is the current site handled with Cloudflare.
1180 *
1181 * @return bool
1182 */
1183 public function is_cloudflare_site() {
1184 return isset($_SERVER['HTTP_CF_RAY']);
1185 }
1186
1187 /**
1188 * Include Cloudflare settings template.
1189 */
1190 public function output_cloudflare_settings() {
1191 if (self::is_premium() || !apply_filters('show_cloudflare_settings', $this->is_cloudflare_site())) return;
1192
1193 WP_Optimize()->include_template('cache/page-cache-cloudflare-placeholder.php');
1194 }
1195
1196 /**
1197 * Outputs the DB optimize Tab
1198 */
1199 public function output_database_optimize_tab() {
1200 $optimizer = $this->get_optimizer();
1201 $options = $this->get_options();
1202
1203 // check if nonce passed.
1204 $nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
1205
1206 // save options.
1207 if ($nonce_passed && isset($_POST['wp-optimize'])) $options->save_sent_manual_run_optimization_options($_POST, true);
1208
1209 $optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
1210
1211 $optimization_results = (($nonce_passed) ? $optimizer->do_optimizations($_POST) : false);
1212
1213 // display optimizations table or restricted access message.
1214 if ($this->can_run_optimizations()) {
1215 $this->include_template('database/optimize-table.php', false, array('optimize_db' => $optimize_db, 'optimization_results' => $optimization_results, 'load_data' => false, 'does_server_allows_table_optimization' => $this->does_server_allows_table_optimization()));
1216 } else {
1217 $this->prevent_run_optimizations_message();
1218 }
1219 }
1220
1221 /**
1222 * Outputs the DB Tables Tab
1223 */
1224 public function output_database_tables_tab() {
1225 // check if nonce passed.
1226 $nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
1227
1228 $optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
1229
1230 if (!$this->does_server_allows_table_optimization()) {
1231 $message = __('Your server takes care of table optimization', 'wp-optimize');
1232 $this->prevent_run_optimizations_message($message);
1233 } elseif ($this->can_run_optimizations()) {
1234 $this->include_template('database/tables.php', false, array('optimize_db' => $optimize_db, 'load_data' => WP_Optimize()->template_should_include_data()));
1235 } else {
1236 $this->prevent_run_optimizations_message();
1237 }
1238 }
1239
1240 /**
1241 * Runs upon the WP action admin_page_wpo_images_unused
1242 */
1243 public function admin_page_wpo_images_unused() {
1244 WP_Optimize()->include_template('images/unused.php');
1245 }
1246
1247 /**
1248 * Runs upon the WP action wp_optimize_admin_page_wpo_images_lazyload
1249 */
1250 public function admin_page_wpo_images_lazyload() {
1251 WP_Optimize()->include_template('images/lazyload.php');
1252 }
1253
1254 /**
1255 * Show footer review message and link.
1256 *
1257 * @return string
1258 */
1259 public function display_footer_review_message() {
1260 $message = sprintf(
1261 __('Enjoyed %s? Please leave us a %s rating. We really appreciate your support!', 'wp-optimize'),
1262 '<b>WP-Optimize</b>',
1263 '<a href="https://www.g2.com/products/wp-optimize/reviews" target="_blank">&starf;&starf;&starf;&starf;&starf;</a>'
1264 );
1265 return $message;
1266 }
1267
1268 /**
1269 * Returns array of translations used in javascript code.
1270 *
1271 * @return array
1272 */
1273 public function wpo_js_translations() {
1274 return apply_filters('wpo_js_translations', array(
1275 'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
1276 'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
1277 'optimization_complete' => __('Optimization complete', 'wp-optimize'),
1278 'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
1279 'optimizing_table' => __('Optimizing table:', 'wp-optimize'),
1280 'run_optimizations' => __('Run optimizations', 'wp-optimize'),
1281 'table_optimization_timeout' => 120000,
1282 'cancel' => __('Cancel', 'wp-optimize'),
1283 'cancelling' => __('Cancelling...', 'wp-optimize'),
1284 'enable' => __('Enable', 'wp-optimize'),
1285 'disable' => __('Disable', 'wp-optimize'),
1286 'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
1287 'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
1288 'fill_all_settings_fields' => __('Before saving, you need to complete the currently incomplete settings (or remove them).', 'wp-optimize'),
1289 'table_was_not_repaired' => __('%s was not repaired. For more details, please check the logs (configured in your logging destinations settings).', 'wp-optimize'),
1290 'table_was_not_deleted' => __('%s was not deleted. For more details, please check your logs configured in logging destinations settings.', 'wp-optimize'),
1291 'table_was_not_converted' => __('%s was not converted to InnoDB. For more details, please check your logs configured in logging destinations settings.', 'wp-optimize'),
1292 'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
1293 'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
1294 'update' => __('Update', 'wp-optimize'),
1295 'run_now' => __('Run now', 'wp-optimize'),
1296 'starting_preload' => __('Started preload...', 'wp-optimize'),
1297 'loading_urls' => __('Loading URLs...', 'wp-optimize'),
1298 'current_cache_size' => __('Current cache size:', 'wp-optimize'),
1299 'number_of_files' => __('Number of files:', 'wp-optimize'),
1300 'toggle_info' => __('Show information', 'wp-optimize'),
1301 'added_to_list' => __('Added to the list', 'wp-optimize'),
1302 'added_notice' => __('The file was added to the list', 'wp-optimize'),
1303 'save_notice' => __('Save the changes', 'wp-optimize'),
1304 'page_refresh' => __('Refreshing the page to reflect changes...', 'wp-optimize'),
1305 'settings_have_been_deleted_successfully' => __('WP-Optimize settings have been deleted successfully.', 'wp-optimize'),
1306 'loading_data' => __('Loading data...', 'wp-optimize'),
1307 'spinner_src' => esc_attr(admin_url('images/spinner-2x.gif')),
1308 'settings_page_url' => is_multisite() ? network_admin_url('admin.php?page=wpo_settings') : admin_url('admin.php?page=wpo_settings'),
1309 'sites' => $this->get_sites(),
1310 'user_always_ignores_table_delete_warning' => (get_user_meta(get_current_user_id(), 'wpo-ignores-table-delete-warning', true)) ? true : false,
1311 'post_meta_tweak_completed' => __('The tweak has been performed.', 'wp-optimize'),
1312 'no_minified_assets' => __('No minified files are present', 'wp-optimize'),
1313 ));
1314 }
1315
1316 public function wpo_admin_bar() {
1317 $wp_admin_bar = $GLOBALS['wp_admin_bar'];
1318
1319 if (defined('WPOPTIMIZE_ADMINBAR_DISABLE') && WPOPTIMIZE_ADMINBAR_DISABLE) return;
1320
1321 // Show menu item in top bar only for super admins.
1322 if (is_multisite() & !is_super_admin(get_current_user_id())) return;
1323
1324 // Add a link called at the top admin bar.
1325 $args = array(
1326 'id' => 'wp-optimize-node',
1327 'title' => apply_filters('wpoptimize_admin_node_title', 'WP-Optimize')
1328 );
1329 $wp_admin_bar->add_node($args);
1330
1331 $pages = $this->get_submenu_items();
1332
1333 foreach ($pages as $page_id => $page) {
1334
1335 if (!isset($page['create_submenu']) || !$page['create_submenu']) {
1336 if (isset($page['icon']) && 'separator' == $page['icon']) {
1337 $args = array(
1338 'id' => 'wpo-separator-'.$page_id,
1339 'parent' => 'wp-optimize-node',
1340 'meta' => array(
1341 'class' => 'separator',
1342 ),
1343 );
1344 $wp_admin_bar->add_node($args);
1345 }
1346 continue;
1347 }
1348
1349 // 'menu_slug' => 'WP-Optimize',
1350
1351 $menu_page_url = menu_page_url($page['menu_slug'], false);
1352
1353 if (is_multisite()) {
1354 $menu_page_url = network_admin_url('admin.php?page='.$page['menu_slug']);
1355 }
1356
1357 $args = array(
1358 'id' => 'wpoptimize_admin_node_'.$page_id,
1359 'title' => $page['menu_title'],
1360 'parent' => 'wp-optimize-node',
1361 'href' => $menu_page_url,
1362 );
1363 $wp_admin_bar->add_node($args);
1364 }
1365
1366 }
1367
1368 /**
1369 * Manages the admin bar menu for caching (currently page and minify)
1370 */
1371 public function cache_admin_bar($wp_admin_bar) {
1372
1373 $options = $this->get_options();
1374 if (!$options->get_option('enable_cache_in_admin_bar', true)) return;
1375
1376 /**
1377 * The "purge cache" menu items
1378 *
1379 * @param array $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
1380 * @param object $wp_admin_bar
1381 */
1382 $menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);
1383
1384 if (empty($menu_items) || !is_array($menu_items)) return;
1385
1386 $wp_admin_bar->add_menu(array(
1387 'id' => 'wpo_purge_cache',
1388 'title' => __('Purge cache', 'wp-optimize'),
1389 'href' => '#',
1390 'meta' => array(
1391 'title' => __('Purge cache', 'wp-optimize'),
1392 ),
1393 'parent' => false,
1394 ));
1395
1396 foreach ($menu_items as $item) {
1397 $wp_admin_bar->add_menu($item);
1398 }
1399 }
1400
1401 /**
1402 * Add settings link on plugin page
1403 *
1404 * @param string $links Passing through the URL to be used within the HREF.
1405 * @return string Returns the Links.
1406 */
1407 public function plugin_settings_link($links) {
1408
1409 $admin_page_url = $this->get_options()->admin_page_url();
1410 $settings_page_url = $this->get_options()->admin_page_url('wpo_settings');
1411
1412 if (false == self::is_premium()) {
1413 $premium_link = '<a href="' . esc_url($this->premium_version_link) . '" target="_blank">' . __('Premium', 'wp-optimize') . '</a>';
1414 array_unshift($links, $premium_link);
1415 }
1416
1417 $settings_link = '<a href="' . esc_url($settings_page_url) . '">' . __('Settings', 'wp-optimize') . '</a>';
1418 array_unshift($links, $settings_link);
1419
1420 $optimize_link = '<a href="' . esc_url($admin_page_url) . '">' . __('Optimize', 'wp-optimize') . '</a>';
1421 array_unshift($links, $optimize_link);
1422 return $links;
1423 }
1424
1425 /**
1426 * Action wpo_tables_list_additional_column_data. Output button Optimize in the action column.
1427 *
1428 * @param string $content String for output to column
1429 * @param object $table_info Object with table info.
1430 *
1431 * @return string
1432 */
1433 public function tables_list_additional_column_data($content, $table_info) {
1434 if ($table_info->is_needing_repair) {
1435 $content .= '<div class="wpo_button_wrap">'
1436 . '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
1437 . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1438 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
1439 . '</div>';
1440 }
1441
1442 // table belongs to plugin.
1443 if ($table_info->can_be_removed) {
1444 $content .= '<div>'
1445 . '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
1446 . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1447 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
1448 . '</div>';
1449 }
1450
1451 // Add option for MyISAM to InnoDB conversion.
1452 if ('MyISAM' == $table_info->Engine) {
1453 $content .= '<div class="wpo_button_convert wpo_button_wrap">'
1454 . '<button class="button button-secondary toinnodb" data-table="' . esc_attr($table_info->Name) . '">' . __('Convert to InnoDB', 'wp-optimize') . '</button>'
1455 . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1456 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
1457 . '</div>';
1458
1459 }
1460
1461 return $content;
1462 }
1463
1464 /**
1465 * Initialize WP-Optimize page cache.
1466 */
1467 public function init_page_cache() {
1468 if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
1469 $this->get_page_cache()->enable();
1470 }
1471 }
1472
1473 /**
1474 * Schedules cron event based on selected schedule type
1475 *
1476 * @return void
1477 */
1478 public function cron_activate() {
1479 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
1480
1481 $options = $this->get_options();
1482
1483 if ($options->get_option('schedule') === false) {
1484 $options->set_default_options();
1485 } else {
1486 if ('true' == $options->get_option('schedule')) {
1487 if (!wp_next_scheduled('wpo_cron_event2')) {
1488 $schedule_type = $options->get_option('schedule-type', 'wpo_weekly');
1489
1490 // Backward compatibility
1491 if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';
1492
1493 $this_time = (86400 * 7);
1494
1495 switch ($schedule_type) {
1496 case "wpo_daily":
1497 $this_time = 86400;
1498 break;
1499
1500 case "wpo_weekly":
1501 $this_time = (86400 * 7);
1502 break;
1503
1504 case "wpo_fortnightly":
1505 $this_time = (86400 * 14);
1506 break;
1507
1508 case "wpo_monthly":
1509 $this_time = (86400 * 30);
1510 break;
1511 }
1512
1513 add_action('wpo_cron_event2', array($this, 'cron_action'));
1514 wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
1515 WP_Optimize()->log('running wp_schedule_event()');
1516 }
1517 }
1518 }
1519 }
1520
1521 /**
1522 * Clears all cron events
1523 *
1524 * @return void
1525 */
1526 public function wpo_cron_deactivate() {
1527 $cron_jobs = _get_cron_array();
1528 foreach ($cron_jobs as $job) {
1529 foreach (array_keys($job) as $hook) {
1530 if (preg_match('/^wpo_/', $hook)) wp_unschedule_hook($hook);
1531 }
1532 }
1533 }
1534
1535 /**
1536 * Scheduler public functions to update schedulers
1537 *
1538 * @param array $schedules An array of schedules being passed.
1539 * @return array An array of schedules being returned.
1540 */
1541 public function cron_schedules($schedules) {
1542 $schedules['wpo_daily'] = array('interval' => 86400, 'display' => 'Once Daily');
1543 $schedules['wpo_weekly'] = array('interval' => 86400 * 7, 'display' => 'Once Weekly');
1544 $schedules['wpo_fortnightly'] = array('interval' => 86400 * 14, 'display' => 'Once Every Fortnight');
1545 $schedules['wpo_monthly'] = array('interval' => 86400 * 30, 'display' => 'Once Every Month');
1546 return $schedules;
1547 }
1548
1549 /**
1550 * Returns count of overdue cron jobs.
1551 *
1552 * @return integer
1553 */
1554 public function howmany_overdue_crons() {
1555 $how_many_overdue = 0;
1556 if (function_exists('_get_cron_array') || (is_file(ABSPATH.WPINC.'/cron.php') && include_once(ABSPATH.WPINC.'/cron.php') && function_exists('_get_cron_array'))) {
1557 $crons = _get_cron_array();
1558 if (is_array($crons)) {
1559 $timenow = time();
1560 foreach ($crons as $jt => $job) {
1561 if ($jt < $timenow) {
1562 $how_many_overdue++;
1563 }
1564 }
1565 }
1566 }
1567 return $how_many_overdue;
1568 }
1569
1570 /**
1571 * Run updates on plugin activation.
1572 */
1573 public function run_updates() {
1574 include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-updates.php');
1575 WP_Optimize_Updates::check_updates();
1576 }
1577
1578 /**
1579 * Returns warning about overdue crons.
1580 *
1581 * @param int $howmany count of overdue crons
1582 * @return string
1583 */
1584 public function show_admin_warning_overdue_crons($howmany) {
1585 $ret = '<div class="updated below-h2"><p>';
1586 $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>';
1587 $ret .= '</p></div>';
1588 return $ret;
1589 }
1590
1591 public function admin_menu() {
1592
1593 $capability_required = $this->capability_required();
1594
1595 if (!current_user_can($capability_required) || (!$this->can_run_optimizations() && !$this->can_manage_options())) return;
1596
1597 $icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDE2IDE2IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc0MzE2IgogICBoZWlnaHQ9IjE2IgogICB3aWR0aD0iMTYiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0MzE4IiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQzMjEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSI+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2EwYTVhYTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTciCiAgICAgICBkPSJtIDEwLjc2ODgwOSw2Ljc2MTYwNTEgMCwwIGMgLTAuMDE2ODgsLTAuMDE2ODc4IC0wLjAyNTMxLC0wLjA0MjE4MSAtMC4wMzM3NCwtMC4wNjc0OTkgLTAuMDA4NCwtMC4wMDgzOSAtMC4wMDg0LC0wLjAxNjg3OCAtMC4wMTY4OCwtMC4wMzM3NDMgQyA5Ljk5MjYxMTIsNS4xOTIzMzY2IDguMjIwODU1Nyw0LjU4NDg3ODEgNi43NDQzOTEyLDUuMjkzNTc5NyA1LjY3MjkwMDUsNS44MDgyMzI4IDUuMDU3MDA0Myw2Ljg4ODE2MTMgNS4wNjU0NDIsOC4wMDE4MzY1IDQuNDU3OTgyMiw3LjMxMDAwNzYgMy42OTg2NTg0LDYuNzk1MzU0NSAyLjg1NDk2NDIsNi40OTE2MjUzIDMuMjY4Mzc0Myw1LjA2NTc4MzEgNC4yNTU0OTYsMy44MTcxMTY2IDUuNjg5Nzc0NiwzLjEyNTI4NzggOC4zNjQyODMyLDEuODM0NDM2OCAxMS41NzAzMTksMi45Mzk2NzQ0IDEyLjg4NjQ4MSw1LjU4ODg3MjYgMTMuNDUxNzU1LDYuNzI3ODU5NiAxNC42NDk4MDEsNy4zNTIxOTIxIDE1Ljg0Nzg0Niw3LjIzNDA3NSAxNS43NjM0ODIsNi4zMzk3NiAxNS41MTg4MDUsNS40MzcwMDg2IDE1LjEwNTM5Niw0LjU3NjQ0MDQgMTMuMjE1NTIxLDAuNjg3MDEzNCA4LjUzMzAyMjYsLTAuOTQxMzE2MjcgNC42NDM1OTQzLDAuOTQwMTIxNzkgMi4zMjM0MzcsMi4wNjIyMzM0IDAuODA0Nzg4MTQsNC4xNzk5MDQ0IDAuMzU3NjMxMzIsNi41MzM4MDk4IDIuNDE2MjQzOCw2LjQyNDEyOSA0LjQzMjY3MTcsNy41MDQwNTc0IDUuNDM2NjY2Miw5LjQzNjExNjcgbCAwLjAwODM5LDAgYyAwLjc1OTMxOTIsMS4zNzUyMjAzIDIuNDcyMDE3OCwxLjk0MDQ5NTMgMy45MDYyOTYsMS4yNDg2NjczIDEuMDQ2MTc5OCwtMC41MDYyMTggMS42NTM2NDA4LC0xLjUzNTUyMzggMS42Nzg5NTA4LC0yLjYxNTQ1MTIgMC41ODIxNDgsMC43MDg3MDE4IDEuMzMzMDM1LDEuMjQ4NjY2OCAyLjE1OTg1NiwxLjU3NzcwNjQgLTAuNDM4NzIxLDEuMzU4MzQ3OCAtMS40MDA1MzMsMi41NDc5NTQ4IC0yLjc5MjYyNywzLjIxNDQ3ODggLTIuNTkwMTM4NywxLjI0ODY1OCAtNS42NzgwNTc0LDAuMjUzMTA0IC03LjA2MTcxNTEsLTIuMjI3MzU3IGwgMCwwIEMgMi43NjIxMDQ4LDkuNDUyOTg5NCAxLjUxMzQzODMsOC44MjAyMTkxIDAuMjgxNjQ1OTIsOC45NzIwODQ0IDAuMzgyODg3NjUsOS43OTg5MDQ2IDAuNjE5MTIzMzEsMTAuNjE3Mjg3IDAuOTk4Nzg1MiwxMS40MDE5MjIgYyAxLjg4MTQzNjgsMy44OTc4NjQgNi41NjM5MzcsNS41MjYxOTggMTAuNDYxODAwOCwzLjY0NDc2IDIuMjQ0MjI2LC0xLjA4ODM2OSAzLjczNzU2MiwtMy4xMDQ3OTYgNC4yMzUzNDIsLTUuMzc0MzMyMyAtMS45OTk1NTQsMC4wNDIxODEgLTMuOTQ4NDg2LC0xLjAyOTMwNjMgLTQuOTI3MTcsLTIuOTEwNzQzMyB6IgogICAgICAgY2xhc3M9InN0MTciIC8+CiAgPC9nPgo8L3N2Zz4K';
1598
1599 // Removes the admin menu items on the left WP bar.
1600 if (!is_multisite() || (is_multisite() && is_network_admin())) {
1601 add_menu_page("WP-Optimize", "WP-Optimize", $capability_required, "WP-Optimize", array($this, "display_admin"), $icon_svg);
1602
1603 $sub_menu_items = $this->get_submenu_items();
1604
1605 foreach ($sub_menu_items as $menu_item) {
1606 if ($menu_item['create_submenu']) add_submenu_page('WP-Optimize', $menu_item['page_title'], $menu_item['menu_title'], $capability_required, $menu_item['menu_slug'], $menu_item['function']);
1607 }
1608 }
1609
1610 $options = $this->get_options();
1611
1612 if ($options->get_option('enable-admin-menu', 'false') == 'true') {
1613 add_action('wp_before_admin_bar_render', array($this, 'wpo_admin_bar'));
1614 }
1615 }
1616
1617 /**
1618 * Get the submenu items
1619 *
1620 * @return array
1621 */
1622 public function get_submenu_items() {
1623 $sub_menu_items = array(
1624 array(
1625 'page_title' => __('Database', 'wp-optimize'),
1626 'menu_title' => __('Database', 'wp-optimize'),
1627 'menu_slug' => 'WP-Optimize',
1628 'function' => array($this, 'display_admin'),
1629 'icon' => 'cloud',
1630 'create_submenu' => true,
1631 'order' => 20,
1632 ),
1633 array(
1634 'page_title' => __('Images', 'wp-optimize'),
1635 'menu_title' => __('Images', 'wp-optimize'),
1636 'menu_slug' => 'wpo_images',
1637 'function' => array($this, 'display_admin'),
1638 'icon' => 'images-alt2',
1639 'create_submenu' => true,
1640 'order' => 30,
1641 ),
1642 array(
1643 'page_title' => __('Cache', 'wp-optimize'),
1644 'menu_title' => __('Cache', 'wp-optimize'),
1645 'menu_slug' => 'wpo_cache',
1646 'function' => array($this, 'display_admin'),
1647 'icon' => 'archive',
1648 'create_submenu' => true,
1649 'order' => 40,
1650 ),
1651 array(
1652 'page_title' => __('Minify', 'wp-optimize'),
1653 'menu_title' => __('Minify', 'wp-optimize'),
1654 'menu_slug' => 'wpo_minify',
1655 'function' => array($this, 'display_admin'),
1656 'icon' => 'dashboard',
1657 'create_submenu' => true,
1658 'order' => 50,
1659 ),
1660 array(
1661 'create_submenu' => false,
1662 'order' => 55,
1663 'icon' => 'separator',
1664 ),
1665 array(
1666 'page_title' => __('Settings', 'wp-optimize'),
1667 'menu_title' => __('Settings', 'wp-optimize'),
1668 'menu_slug' => 'wpo_settings',
1669 'function' => array($this, 'display_admin'),
1670 'icon' => 'admin-settings',
1671 'create_submenu' => true,
1672 'order' => 60,
1673 ),
1674 array(
1675 'page_title' => __('Support & FAQs', 'wp-optimize'),
1676 'menu_title' => __('Help', 'wp-optimize'),
1677 'menu_slug' => 'wpo_support',
1678 'function' => array($this, 'display_admin'),
1679 'icon' => 'sos',
1680 'create_submenu' => true,
1681 'order' => 60,
1682 ),
1683 array(
1684 'page_title' => __('Premium Upgrade', 'wp-optimize'),
1685 'menu_title' => __('Premium Upgrade', 'wp-optimize'),
1686 'menu_slug' => 'wpo_mayalso',
1687 'function' => array($this, 'display_admin'),
1688 'icon' => 'admin-plugins',
1689 'create_submenu' => true,
1690 'order' => 70,
1691 ),
1692 );
1693
1694 $sub_menu_items = apply_filters('wp_optimize_sub_menu_items', $sub_menu_items);
1695
1696 usort($sub_menu_items, array($this, 'order_sort'));
1697
1698 return $sub_menu_items;
1699 }
1700
1701 public function order_sort($a, $b) {
1702 if ($a['order'] == $b['order']) return 0;
1703 return ($a['order'] > $b['order']) ? 1 : -1;
1704 }
1705
1706 private function wp_normalize_path($path) {
1707 // Wp_normalize_path is not present before WP 3.9.
1708 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1709 // Taken from WP 4.6.
1710 $path = str_replace('\\', '/', $path);
1711 $path = preg_replace('|(?<=.)/+|', '/', $path);
1712 if (':' === substr($path, 1, 1)) {
1713 $path = ucfirst($path);
1714 }
1715 return $path;
1716 }
1717
1718 public function get_templates_dir() {
1719 return apply_filters('wp_optimize_templates_dir', $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'templates'));
1720 }
1721
1722 public function get_templates_url() {
1723 return apply_filters('wp_optimize_templates_url', WPO_PLUGIN_URL.'/templates');
1724 }
1725
1726 /**
1727 * Return or output view content
1728 *
1729 * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1730 * @param Boolean $return_instead_of_echo - what to do with the results
1731 * @param Array $extract_these - key/value pairs for substitution into the scope of the template
1732 *
1733 * @return String|Void
1734 */
1735 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1736 if ($return_instead_of_echo) ob_start();
1737
1738 if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
1739 $prefix = $matches[1];
1740 $suffix = $matches[2];
1741 if (isset($this->template_directories[$prefix])) {
1742 $template_file = $this->template_directories[$prefix].'/'.$suffix;
1743 }
1744 }
1745
1746 if (!isset($template_file)) {
1747 $template_file = WPO_PLUGIN_MAIN_PATH.'templates/'.$path;
1748 }
1749
1750 $template_file = apply_filters('wp_optimize_template', $template_file, $path);
1751
1752 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1753
1754 if (!file_exists($template_file)) {
1755 error_log("WP Optimize: template not found: ".$template_file);
1756 echo __('Error:', 'wp-optimize').' '.__('template not found', 'wp-optimize')." (".$path.")";
1757 } else {
1758 extract($extract_these);
1759 // The following are useful variables which can be used in the template.
1760 // They appear as unused, but may be used in the $template_file.
1761 $wpdb = $GLOBALS['wpdb'];// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wpdb might be used in the included template
1762 $wp_optimize = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wp_optimize might be used in the included template
1763 $optimizer = $this->get_optimizer();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $optimizer might be used in the included template
1764 $options = $this->get_options();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $options might be used in the included template
1765 $wp_optimize_notices = $this->get_notices();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wp_optimize_notices might be used in the included template
1766 include $template_file;
1767 }
1768
1769 do_action('wp_optimize_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1770
1771 if ($return_instead_of_echo) return ob_get_clean();
1772 }
1773
1774 /**
1775 * Build a list of template directories (stored in self::$template_directories)
1776 */
1777 private function register_template_directories() {
1778
1779 $template_directories = array();
1780
1781 $templates_dir = $this->get_templates_dir();
1782
1783 if ($dh = opendir($templates_dir)) {
1784 while (($file = readdir($dh)) !== false) {
1785 if ('.' == $file || '..' == $file) continue;
1786 if (is_dir($templates_dir.'/'.$file)) {
1787 $template_directories[$file] = $templates_dir.'/'.$file;
1788 }
1789 }
1790 closedir($dh);
1791 }
1792
1793 // Optimal hook for most extensions to hook into.
1794 $this->template_directories = apply_filters('wp_optimize_template_directories', $template_directories);
1795
1796 }
1797
1798 /**
1799 * Message to debug
1800 *
1801 * @param string $message Message to insert into the log.
1802 * @param array $context array with variables used in $message like in template,
1803 * for ex.
1804 * $message = 'Hello {message}';
1805 * $context = ['message' => 'world']
1806 * 'Hello world' string will be saved in log.
1807 */
1808 public function log($message, $context = array()) {
1809 $this->get_logger()->debug($message, $context);
1810 }
1811
1812 /**
1813 * Format Bytes Into KB/MB
1814 *
1815 * @param mixed $bytes Number of bytes to be converted.
1816 * @param integer $decimals the number of decimal digits
1817 * @return integer return the correct format size.
1818 */
1819 public function format_size($bytes, $decimals = 2) {
1820 if (!is_numeric($bytes)) return __('N/A', 'wp-optimize');
1821
1822 if (1073741824 <= $bytes) {
1823 $bytes = number_format($bytes / 1073741824, $decimals) . ' GB';
1824 } elseif (1048576 <= $bytes) {
1825 $bytes = number_format($bytes / 1048576, $decimals) . ' MB';
1826 } elseif (1024 <= $bytes) {
1827 $bytes = number_format($bytes / 1024, $decimals) . ' KB';
1828 } elseif (1 < $bytes) {
1829 $bytes = $bytes . ' bytes';
1830 } elseif (1 == $bytes) {
1831 $bytes = $bytes . ' byte';
1832 } else {
1833 $bytes = '0 bytes';
1834 }
1835
1836 return $bytes;
1837 }
1838
1839 /**
1840 * Format a timestamp into a juman readable date time
1841 *
1842 * @param int $timestamp
1843 * @return string
1844 */
1845 public function format_date_time($timestamp) {
1846 return date_i18n(get_option('date_format').' @ '.get_option('time_format'), ($timestamp + get_option('gmt_offset') * 3600));
1847 }
1848
1849 /**
1850 * Executed this function on cron event.
1851 *
1852 * @return void
1853 */
1854 public function cron_action() {
1855
1856 $optimizer = $this->get_optimizer();
1857 $options = $this->get_options();
1858
1859 $this->log('WPO: Starting cron_action()');
1860
1861 if ('true' == $options->get_option('schedule')) {
1862 $this_options = $options->get_option('auto');
1863
1864 // Currently the output of the optimizations is not saved/used/logged.
1865 $optimizer->do_optimizations($this_options, 'auto');
1866 }
1867
1868 }
1869
1870 /**
1871 * Schedule cron tasks used by plugin.
1872 *
1873 * @return void
1874 */
1875 public function schedule_plugin_cron_tasks() {
1876 if (!wp_next_scheduled('wpo_weekly_cron_tasks')) {
1877 wp_schedule_event(current_time("timestamp", 0), 'weekly', 'wpo_weekly_cron_tasks');
1878 }
1879
1880 add_action('wpo_weekly_cron_tasks', array($this, 'do_weekly_cron_tasks'));
1881 }
1882
1883 /**
1884 * Do plugin background tasks.
1885 *
1886 * @return void
1887 */
1888 public function do_weekly_cron_tasks() {
1889 // add tasks here.
1890 $this->get_db_info()->update_plugin_json();
1891 }
1892
1893 /**
1894 * This will customize a URL with a correct Affiliate link
1895 * This function can be update to suit any URL as longs as the URL is passed
1896 *
1897 * @param String $url - URL to be check to see if it an updraftplus match.
1898 * @param String $text - Text to be entered within the href a tags.
1899 * @param String $html - Any specific HTML to be added.
1900 * @param String $class - Specify a class for the href (including the attribute label)
1901 * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1902 *
1903 * @return String|void
1904 */
1905 public function wp_optimize_url($url, $text, $html = '', $class = '', $return_instead_of_echo = false) {
1906 // Check if the URL is UpdraftPlus.
1907 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
1908 if ('' != $html) {
1909 $result = '<a '.$class.' href="'.esc_attr($url).'">'.$html.'</a>';
1910 } else {
1911 $result = '<a '.$class.' href="'.esc_attr($url).'">'.htmlspecialchars($text).'</a>';
1912 }
1913 if ($return_instead_of_echo) return $result;
1914 echo $result;
1915 }
1916
1917 /**
1918 * Get an URL with an eventual affiliate ID
1919 *
1920 * @param string $url
1921 * @return string
1922 */
1923 public function maybe_add_affiliate_params($url) {
1924 // Check if the URL is UpdraftPlus.
1925 if (false !== strpos($url, '//updraftplus.com')) {
1926 // Set URL with Affiliate ID.
1927 $url = add_query_arg(array('afref' => $this->get_notices()->get_affiliate_id()), $url);
1928
1929 // Apply filters.
1930 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1931 }
1932 return apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
1933 }
1934
1935 /**
1936 * Setup WPO logger(s)
1937 */
1938 public function setup_loggers() {
1939
1940 $logger = $this->get_logger();
1941 $loggers = $this->wpo_loggers();
1942
1943 if (!empty($loggers)) {
1944 foreach ($loggers as $_logger) {
1945 $logger->add_logger($_logger);
1946 }
1947 }
1948
1949 add_action('wp_optimize_after_optimizations', array($this, 'after_optimizations_logger_action'));
1950 }
1951
1952 /**
1953 * Run logger actions after all optimizations done
1954 */
1955 public function after_optimizations_logger_action() {
1956 $loggers = $this->get_logger()->get_loggers();
1957 if (!empty($loggers)) {
1958 foreach ($loggers as $logger) {
1959 if (is_a($logger, 'Updraft_Email_Logger')) {
1960 $logger->flush_log();
1961 }
1962 }
1963 }
1964 }
1965
1966 /**
1967 * Returns list of WPO loggers instances
1968 * Apply filter wp_optimize_loggers
1969 *
1970 * @return array
1971 */
1972 public function wpo_loggers() {
1973
1974 $loggers = array();
1975 $loggers_classes_by_id = array();
1976 $options_keys = array();
1977
1978 $loggers_classes = $this->get_loggers_classes();
1979
1980 foreach ($loggers_classes as $logger_class => $source) {
1981 $loggers_classes_by_id[strtolower($logger_class)] = $logger_class;
1982 }
1983
1984 $options = $this->get_options();
1985
1986 $saved_loggers = $options->get_option('logging');
1987 $logger_additional_options = $options->get_option('logging-additional');
1988
1989 // create loggers classes instances.
1990 if (!empty($saved_loggers)) {
1991 // check for previous version options format.
1992 $keys = array_keys($saved_loggers);
1993
1994 // if options stored in old format then reformat it.
1995 if (false == is_numeric($keys[0])) {
1996 $_saved_loggers = array();
1997 foreach ($saved_loggers as $logger_id => $enabled) {
1998 if ($enabled) {
1999 $_saved_loggers[] = $logger_id;
2000 }
2001 }
2002
2003 // fill email with admin.
2004 if (array_key_exists('updraft_email_logger', $saved_loggers) && $saved_loggers['updraft_email_logger']) {
2005 $logger_additional_options['updraft_email_logger'] = array(
2006 get_option('admin_email')
2007 );
2008 }
2009
2010 $saved_loggers = $_saved_loggers;
2011 }
2012
2013 foreach ($saved_loggers as $i => $logger_id) {
2014
2015 if (!array_key_exists($logger_id, $loggers_classes_by_id)) continue;
2016
2017 $logger_class = $loggers_classes_by_id[$logger_id];
2018
2019 $logger = new $logger_class();
2020
2021 $logger_options = $logger->get_options_list();
2022
2023 if (!empty($logger_options)) {
2024 foreach (array_keys($logger_options) as $option_name) {
2025 if (array_key_exists($option_name, $options_keys)) {
2026 $options_keys[$option_name]++;
2027 } else {
2028 $options_keys[$option_name] = 0;
2029 }
2030
2031 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
2032
2033 // if options in old format then get correct value.
2034 if ('' === $option_value && array_key_exists($logger_id, $logger_additional_options)) {
2035 $option_value = array_shift($logger_additional_options[$logger_id]);
2036 }
2037
2038 $logger->set_option($option_name, $option_value);
2039 }
2040 }
2041
2042 // check if logger is active.
2043 $active = (!is_array($logger_additional_options) || (array_key_exists('active', $logger_additional_options) && empty($logger_additional_options['active'][$i]))) ? false : true;
2044
2045 if ($active) {
2046 $logger->enable();
2047 } else {
2048 $logger->disable();
2049 }
2050
2051 $loggers[] = $logger;
2052 }
2053 }
2054
2055 $loggers = apply_filters('wp_optimize_loggers', $loggers);
2056
2057 return $loggers;
2058 }
2059
2060 /**
2061 * Returns associative array with logger class name in a key and path to class file in a value.
2062 *
2063 * @return array
2064 */
2065 public function get_loggers_classes() {
2066 $loggers_classes = array(
2067 'Updraft_PHP_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-php-logger.php',
2068 'Updraft_Email_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-email-logger.php',
2069 'Updraft_Ring_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-ring-logger.php'
2070 );
2071
2072 $loggers_classes = apply_filters('wp_optimize_loggers_classes', $loggers_classes);
2073
2074 if (!empty($loggers_classes)) {
2075 foreach ($loggers_classes as $logger_class => $logger_file) {
2076 if (!class_exists($logger_class)) {
2077 if (is_file($logger_file)) {
2078 include_once($logger_file);
2079 }
2080 }
2081 }
2082 }
2083
2084 return $loggers_classes;
2085 }
2086
2087 /**
2088 * Returns information about all loggers classes.
2089 *
2090 * @return array
2091 */
2092 public function get_loggers_classes_info() {
2093 $loggers_classes = $this->get_loggers_classes();
2094
2095 $loggers_classes_info = array();
2096
2097 if (!empty($loggers_classes)) {
2098 foreach (array_keys($loggers_classes) as $logger_class_name) {
2099
2100 if (!class_exists($logger_class_name)) continue;
2101
2102 $logger_id = strtolower($logger_class_name);
2103 $logger_class = new $logger_class_name();
2104
2105 $loggers_classes_info[$logger_id] = array(
2106 'description' => $logger_class->get_description(),
2107 'available' => $logger_class->is_available(),
2108 'allow_multiple' => $logger_class->is_allow_multiple(),
2109 'options' => $logger_class->get_options_list()
2110 );
2111 }
2112 }
2113
2114 return $loggers_classes_info;
2115 }
2116
2117 /**
2118 * Returns true if optimization works in multisite mode
2119 *
2120 * @return boolean
2121 */
2122 public function is_multisite_mode() {
2123 return (is_multisite() && self::is_premium());
2124 }
2125
2126 /**
2127 * Returns true if current user can run optimizations.
2128 *
2129 * @return bool
2130 */
2131 public function can_run_optimizations() {
2132 // we don't check permissions for cron jobs.
2133 if (defined('DOING_CRON') && DOING_CRON) return true;
2134
2135 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
2136 return true;
2137 }
2138
2139 /**
2140 * Returns true if current user can manage plugin options.
2141 *
2142 * @return bool
2143 */
2144 public function can_manage_options() {
2145 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_manage_settings')) return false;
2146 return true;
2147 }
2148
2149 /**
2150 * CHeck if current user can purge the cache.
2151 *
2152 * @return bool
2153 */
2154 public function can_purge_the_cache() {
2155 if (self::is_premium()) {
2156 return WP_Optimize_Premium()->can_purge_the_cache();
2157 }
2158
2159 return true;
2160 }
2161
2162 /**
2163 * Output information message for users who have no permissions to run optimizations.
2164 *
2165 * @param string $message Message to display
2166 */
2167 public function prevent_run_optimizations_message($message = '') {
2168 if (empty($message)) {
2169 $message = __('You have no permissions to run optimizations.', 'wp-optimize');
2170 }
2171 $this->include_template('info-message.php', false, array('message' => $message));
2172 }
2173
2174 /**
2175 * Output information message for users who have no permissions to manage settings.
2176 */
2177 public function prevent_manage_options_info() {
2178 $this->include_template('info-message.php', false, array('message' => __('You have no permissions to manage WP-Optimize settings.', 'wp-optimize')));
2179 }
2180
2181 /**
2182 * Returns list of all sites in multisite
2183 *
2184 * @return array
2185 */
2186 public function get_sites() {
2187 $sites = array();
2188 // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
2189 if (function_exists('get_sites')) {
2190 $sites = get_sites(array('network_id' => null, 'deleted' => 0, 'number' => 999999));
2191 } elseif (function_exists('wp_get_sites')) {
2192 $sites = wp_get_sites(array('network_id' => null, 'deleted' => 0, 'limit' => 999999));
2193 }
2194 return $sites;
2195 }
2196
2197 /**
2198 * Output success/error messages from $output array.
2199 *
2200 * @param array $output ['messages' => success messages, 'errors' => error messages]
2201 */
2202 private function wpo_render_output_messages($output) {
2203 foreach ($output['messages'] as $item) {
2204 echo '<div class="updated fade below-h2"><strong>'.$item.'</strong></div>';
2205 }
2206
2207 foreach ($output['errors'] as $item) {
2208 echo '<div class="error fade below-h2"><strong>'.$item.'</strong></div>';
2209 }
2210 }
2211
2212 /**
2213 * Returns script memory limit in megabytes.
2214 *
2215 * @param bool $memory_limit
2216 * @return int
2217 */
2218 public function get_memory_limit($memory_limit = false) {
2219 // Returns in megabytes
2220 if (false == $memory_limit) $memory_limit = ini_get('memory_limit');
2221 $memory_limit = rtrim($memory_limit);
2222
2223 return $this->return_bytes($memory_limit);
2224 }
2225
2226 /**
2227 * Returns free memory in bytes.
2228 *
2229 * @return int
2230 */
2231 public function get_free_memory() {
2232 return $this->get_memory_limit() - memory_get_usage();
2233 }
2234
2235 /**
2236 * Checks PHP memory_limit and WP_MAX_MEMORY_LIMIT values and return minimal.
2237 *
2238 * @return int memory limit in bytes.
2239 */
2240 public function get_script_memory_limit() {
2241 $memory_limit = $this->get_memory_limit();
2242
2243 if (defined('WP_MAX_MEMORY_LIMIT')) {
2244 $wp_memory_limit = $this->get_memory_limit(WP_MAX_MEMORY_LIMIT);
2245
2246 if ($wp_memory_limit > 0 && $wp_memory_limit < $memory_limit) {
2247 $memory_limit = $wp_memory_limit;
2248 }
2249 }
2250
2251 return $memory_limit;
2252 }
2253
2254 /**
2255 * Returns max packet size for database.
2256 *
2257 * @return int|string
2258 */
2259 public function get_max_packet_size() {
2260 global $wpdb;
2261 static $mp = 0;
2262
2263 if ($mp > 0) return $mp;
2264
2265 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
2266 // Default to 1MB
2267 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
2268 // 32MB
2269 if ($mp < 33554432) {
2270 $save = $wpdb->show_errors(false);
2271 @$wpdb->query("SET GLOBAL max_allowed_packet=33554432");// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
2272 $wpdb->show_errors($save);
2273
2274 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
2275 // Default to 1MB
2276 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
2277 }
2278
2279 return $mp;
2280 }
2281
2282 /**
2283 * Converts shorthand memory notation value to bytes.
2284 * From http://php.net/manual/en/function.ini-get.php
2285 *
2286 * @param string $val shorthand memory notation value.
2287 */
2288 public function return_bytes($val) {
2289 $val = trim($val);
2290 $last = strtolower($val[strlen($val)-1]);
2291 $val = (int) $val;
2292 switch ($last) {
2293 case 'g':
2294 $val *= 1024;
2295 // no break
2296 case 'm':
2297 $val *= 1024;
2298 // no break
2299 case 'k':
2300 $val *= 1024;
2301 }
2302
2303 return $val;
2304 }
2305
2306 /**
2307 * Log fatal errors to defined log destinations.
2308 */
2309 public function log_fatal_errors() {
2310 $last_error = error_get_last();
2311
2312 if (isset($last_error['type']) && E_ERROR === $last_error['type']) {
2313 $this->get_logger()->critical($last_error['message']);
2314 }
2315 }
2316
2317 /**
2318 * Close browser connection and continue script work. - Taken from UpdraftPlus
2319 *
2320 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
2321 * @return void
2322 */
2323 public function close_browser_connection($txt = '') {
2324 if (!headers_sent()) {
2325 // Close browser connection so that it can resume AJAX polling
2326 header('Content-Length: '.(empty($txt) ? '0' : 4+strlen($txt)));
2327 header('Connection: close');
2328 header('Content-Encoding: none');
2329 }
2330
2331 if (session_id()) session_write_close();
2332 echo "\r\n\r\n";
2333 echo $txt;
2334 // These two added - 19-Feb-15 - started being required on local dev machine, for unknown reason (probably some plugin that started an output buffer).
2335 $ob_level = ob_get_level();
2336 while ($ob_level > 0) {
2337 ob_end_flush();
2338 $ob_level--;
2339 }
2340 flush();
2341 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
2342 }
2343
2344 /**
2345 * Get the current theme's style.css headers
2346 *
2347 * @return array|WP_Error
2348 */
2349 public function get_stylesheet_headers() {
2350 static $headers;
2351 if (isset($headers)) return $headers;
2352
2353 $style = get_template_directory_uri() . '/style.css';
2354
2355 /**
2356 * Filters wp_remote_get parameters, when checking if browser cache is enabled.
2357 *
2358 * @param array $request_params Default parameters
2359 */
2360 $request_params = apply_filters('wpoptimize_get_stylesheet_headers_args', array('timeout' => 10));
2361
2362 // trying to load style.css.
2363 $response = wp_remote_get($style, $request_params);
2364
2365 if (is_a($response, 'WP_Error')) return $response;
2366
2367 $headers = wp_remote_retrieve_headers($response);
2368
2369 if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
2370 $headers = $headers->getAll();
2371 }
2372
2373 return $headers;
2374 }
2375
2376 /**
2377 * Try to change PHP script time limit.
2378 */
2379 public function change_time_limit() {
2380 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
2381
2382 // Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
2383 @set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
2384 }
2385
2386 /**
2387 * Does the request come from UDC
2388 *
2389 * @return boolean
2390 */
2391 public function is_updraft_central_request() {
2392 return defined('UPDRAFTCENTRAL_COMMAND') && UPDRAFTCENTRAL_COMMAND;
2393 }
2394
2395 /**
2396 * Does the data need to be included in this request. Currently only true if the request is made from UpdraftCentral.
2397 *
2398 * @return boolean
2399 */
2400 public function template_should_include_data() {
2401 /**
2402 * Filters wether data should be included in certain templates or not.
2403 */
2404 return apply_filters('wpo_template_should_include_data', $this->is_updraft_central_request());
2405 }
2406
2407 /**
2408 * Load the templates for the modal window
2409 */
2410 public function load_modal_template() {
2411 $this->include_template('modal.php');
2412 }
2413
2414 /**
2415 * Delete transients and semaphores data from options table.
2416 */
2417 public function delete_transients_and_semaphores() {
2418 global $wpdb;
2419
2420 $masks = array(
2421 'updraft_locked_wpo_%',
2422 'updraft_unlocked_wpo_%',
2423 'updraft_last_lock_time_wpo_%',
2424 'updraft_semaphore_wpo_%',
2425 'wpo_locked_%',
2426 'wpo_unlocked_%',
2427 'wpo_last_lock_time_%',
2428 'wpo_semaphore_%',
2429 '_transient_timeout_wpo_%',
2430 '_transient_wpo_%',
2431 'updraft_lock_wpo_%',
2432 );
2433
2434 $where_parts = array();
2435 foreach ($masks as $mask) {
2436 $where_parts[] = "(`option_name` LIKE '{$mask}')";
2437 }
2438
2439 $wpdb->query("DELETE FROM {$wpdb->options} WHERE " . join(' OR ', $where_parts));
2440 }
2441
2442 /**
2443 * Prevents bots from indexing plugins list
2444 */
2445 public function robots_txt($output) {
2446 $upload_dir = wp_upload_dir();
2447 $path = parse_url($upload_dir['baseurl']);
2448 $output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo-plugins-tables-list.json\n";
2449 return $output;
2450 }
2451 }
2452
2453 /**
2454 * Plugin activation actions.
2455 */
2456 function wpo_activation_actions() {
2457 // If plugin activated by not a Network Administrator then deactivate plugin and show message.
2458 if (is_multisite() && !is_network_admin()) {
2459 deactivate_plugins(plugin_basename(__FILE__));
2460 wp_die(__('Only Network Administrator can activate WP-Optimize plugin.', 'wp-optimize').
2461 ' <a href="'.admin_url('plugins.php').'">'.__('go back', 'wp-optimize').'</a>');
2462 }
2463
2464 // On activation, check if last-optimized option exists. If not, add 'newly-activated' option.
2465 if (!WP_Optimize()->get_options()->get_option('last-optimized', false)) {
2466 WP_Optimize()->get_options()->update_option('newly-activated', true);
2467 }
2468
2469 WP_Optimize()->get_options()->set_default_options();
2470 WP_Optimize()->get_minify()->plugin_activate();
2471
2472 WP_Optimize::get_gzip_compression()->restore();
2473 WP_Optimize::get_browser_cache()->restore();
2474
2475 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');
2476 Updraft_Tasks_Activation::init_db();
2477 Updraft_Tasks_Activation::reinstall_if_needed();
2478
2479 // run premium activation actions.
2480 if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php')) {
2481 if (!class_exists('WP_Optimize_Premium')) {
2482 include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
2483 }
2484
2485 WP_Optimize_Premium()->plugin_activation_actions();
2486 }
2487 }
2488
2489 /**
2490 * Plugin deactivation actions.
2491 */
2492 function wpo_deactivation_actions() {
2493 WP_Optimize()->wpo_cron_deactivate();
2494 WP_Optimize()->get_page_cache()->disable();
2495 WP_Optimize()->get_minify()->plugin_deactivate();
2496 WP_Optimize::get_gzip_compression()->disable();
2497 WP_Optimize::get_browser_cache()->disable();
2498 }
2499
2500 function wpo_cron_deactivate() {
2501 WP_Optimize()->log('running wpo_cron_deactivate()');
2502 wp_clear_scheduled_hook('wpo_cron_event2');
2503 wp_clear_scheduled_hook('wpo_weekly_cron_tasks');
2504 }
2505
2506 /**
2507 * Plugin uninstall actions.
2508 */
2509 function wpo_uninstall_actions() {
2510 WP_Optimize::get_gzip_compression()->disable();
2511 WP_Optimize::get_browser_cache()->disable();
2512 WP_Optimize()->get_options()->delete_all_options();
2513 WP_Optimize()->get_minify()->plugin_uninstall();
2514 WP_Optimize()->get_options()->wipe_settings();
2515 WP_Optimize()->delete_transients_and_semaphores();
2516 }
2517
2518 function WP_Optimize() {
2519 return WP_Optimize::instance();
2520 }
2521
2522 endif;
2523
2524 $GLOBALS['wp_optimize'] = WP_Optimize();
2525