PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.0.13
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.0.13
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 3.8.0 All 110 releases
wp-optimize / wp-optimize.php

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

2,019 lines 68.8 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.0.13
7 Author: David Anderson, Ruhani Rabin, Team Updraft
8 Author URI: https://updraftplus.com
9 Text Domain: wp-optimize
10 Domain Path: /languages
11 License: GPLv2 or later
12 */
13
14 if (!defined('ABSPATH')) die('No direct access allowed');
15
16 // Check to make sure if WP_Optimize is already call and returns.
17 if (!class_exists('WP_Optimize')) :
18 define('WPO_VERSION', '3.0.13');
19 define('WPO_PLUGIN_URL', plugin_dir_url(__FILE__));
20 define('WPO_PLUGIN_MAIN_PATH', plugin_dir_path(__FILE__));
21 define('WPO_PREMIUM_NOTIFICATION', false);
22
23 class WP_Optimize {
24
25 public $premium_version_link = 'https://getwpo.com/buy/';
26
27 private $template_directories;
28
29 protected static $_instance = null;
30
31 protected static $_optimizer_instance = null;
32
33 protected static $_options_instance = null;
34
35 protected static $_notices_instance = null;
36
37 protected static $_logger_instance = null;
38
39 protected static $_browser_cache = null;
40
41 protected static $_db_info = null;
42
43 protected static $_cache = null;
44
45 protected static $_gzip_compression = null;
46
47 /**
48 * Class constructor
49 */
50 public function __construct() {
51
52 // Checks if premium is installed along with plugins needed.
53 add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
54
55 register_activation_hook(__FILE__, 'wpo_activation_actions');
56 register_deactivation_hook(__FILE__, 'wpo_deactivation_actions');
57 register_uninstall_hook(__FILE__, 'wpo_uninstall_actions');
58
59 add_action('admin_init', array($this, 'admin_init'));
60 add_action('admin_menu', array($this, 'admin_menu'));
61
62 add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
63 add_action('wpo_cron_event2', array($this, 'cron_action'));
64 add_filter('cron_schedules', array($this, 'cron_schedules'));
65
66 if (!$this->is_premium()) {
67 add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
68 }
69
70 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
71
72 add_action('wp_ajax_wp_optimize_ajax', array($this, 'wp_optimize_ajax_handler'));
73
74 // Show update to Premium notice for non-premium multisite.
75 add_action('wpo_additional_options', array($this, 'show_multisite_update_to_premium_notice'));
76
77 // Action column (show repair button if need).
78 add_filter('wpo_tables_list_additional_column_data', array($this, 'tables_list_additional_column_data'), 15, 2);
79
80 /**
81 * Add action for display Images > Compress images tab.
82 */
83 add_action('wp_optimize_admin_page_wpo_images_smush', array($this, 'admin_page_wpo_images_smush'));
84
85 include_once(WPO_PLUGIN_MAIN_PATH.'/includes/updraftcentral.php');
86
87 include_once(WPO_PLUGIN_MAIN_PATH.'/includes/backward-compatibility-functions.php');
88
89 register_shutdown_function(array($this, 'log_fatal_errors'));
90
91 $this->schedule_plugin_cron_tasks();
92 }
93
94 public function admin_page_wpo_images_smush() {
95 $options = Updraft_Smush_Manager()->get_smush_options();
96 $custom = 100 == $options['image_quality'] || 90 == $options['image_quality'] ? false : true;
97 $this->include_template('images/smush.php', false, array('smush_options' => $options, 'custom' => $custom));
98 }
99
100 public static function instance() {
101 if (empty(self::$_instance)) {
102 self::$_instance = new self();
103 }
104 return self::$_instance;
105 }
106
107 public static function get_optimizer() {
108 if (empty(self::$_optimizer_instance)) {
109 if (!class_exists('WP_Optimizer')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-wp-optimizer.php');
110 self::$_optimizer_instance = new WP_Optimizer();
111 }
112 return self::$_optimizer_instance;
113 }
114
115 public static function get_options() {
116 if (empty(self::$_options_instance)) {
117 if (!class_exists('WP_Optimize_Options')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-wp-optimize-options.php');
118 self::$_options_instance = new WP_Optimize_Options();
119 }
120 return self::$_options_instance;
121 }
122
123 public static function get_notices() {
124 if (empty(self::$_notices_instance)) {
125 if (!class_exists('WP_Optimize_Notices')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/wp-optimize-notices.php');
126 self::$_notices_instance = new WP_Optimize_Notices();
127 }
128 return self::$_notices_instance;
129 }
130
131 /**
132 * Returns instance if WPO_Page_Cache class.
133 *
134 * @return WPO_Page_Cache
135 */
136 public function get_page_cache() {
137 if (!class_exists('WPO_Page_Cache')) include_once(WPO_PLUGIN_MAIN_PATH.'/cache/class-wpo-page-cache.php');
138
139 return WPO_Page_Cache::instance();
140 }
141
142 /**
143 * Create instance of WP_Optimize_Browser_Cache.
144 *
145 * @return WP_Optimize_Browser_Cache
146 */
147 public static function get_browser_cache() {
148 if (empty(self::$_browser_cache)) {
149 if (!class_exists('WP_Optimize_Browser_Cache')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-wp-optimize-browser-cache.php');
150 self::$_browser_cache = new WP_Optimize_Browser_Cache();
151 }
152 return self::$_browser_cache;
153 }
154
155 /**
156 * Returns WP_Optimize_Database_Information instance.
157 *
158 * @return WP_Optimize_Database_Information
159 */
160 public function get_db_info() {
161 if (empty(self::$_db_info)) {
162 if (!class_exists('WP_Optimize_Database_Information')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/wp-optimize-database-information.php');
163 self::$_db_info = new WP_Optimize_Database_Information();
164 }
165 return self::$_db_info;
166 }
167
168 /**
169 * Returns instance of WP_Optimize_Gzip_Compression.
170 *
171 * @return WP_Optimize_Gzip_Compression
172 */
173 static public function get_gzip_compression() {
174 if (empty(self::$_gzip_compression)) {
175 if (!class_exists('WP_Optimize_Gzip_Compression')) include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-wp-optimize-gzip-compression.php');
176 self::$_gzip_compression = new WP_Optimize_Gzip_Compression();
177 }
178 return self::$_gzip_compression;
179 }
180
181 /**
182 * Create instance of WP_Optimize_Htaccess.
183 *
184 * @param string $htaccess_file absolute path to htaccess file, by default it use .htaccess in WordPress root directory.
185 * @return WP_Optimize_Htaccess
186 */
187 public static function get_htaccess($htaccess_file = '') {
188 if (!class_exists('WP_Optimize_Cache')) {
189 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-wp-optimize-htaccess.php');
190 }
191
192 return new WP_Optimize_Htaccess($htaccess_file);
193 }
194
195 /**
196 * Return instance of Updraft_Logger
197 *
198 * @return Updraft_Logger
199 */
200 public static function get_logger() {
201 if (empty(self::$_logger_instance)) {
202 include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-updraft-logger.php');
203 self::$_logger_instance = new Updraft_Logger();
204 }
205 return self::$_logger_instance;
206 }
207
208 /**
209 * Enqueue scripts and styles on WP-Optimize pages.
210 */
211 public function admin_enqueue_scripts() {
212 $current_screen = get_current_screen();
213 // load scripts and styles only on WP-Optimize pages.
214 if (!preg_match('/wp\-optimize/i', $current_screen->id)) return;
215
216 $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
217 $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
218 $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
219
220 wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);
221
222 wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);
223 wp_enqueue_script('wp-optimize-cache-js', WPO_PLUGIN_URL.'js/cache'.$min_or_not_internal.'.js', array('smush-js'), $enqueue_version);
224 wp_enqueue_script('wp-optimize-admin-js', WPO_PLUGIN_URL.'js/wpoadmin'.$min_or_not_internal.'.js', array('jquery', 'updraft-queue-js', 'smush-js'), $enqueue_version);
225 wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
226 // Using tablesorter to help with organising the DB size on Table Information
227 // https://github.com/Mottie/tablesorter
228 wp_enqueue_script('tablesorter-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter'.$min_or_not.'.js', array('jquery'), $enqueue_version);
229
230 wp_enqueue_script('tablesorter-widgets-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter.widgets'.$min_or_not.'.js', array('jquery'), $enqueue_version);
231
232 // wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);
233
234 $js_variables = $this->wpo_js_translations();
235 $js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
236
237 wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
238
239 do_action('wpo_premium_scripts_styles', $min_or_not, $enqueue_version);
240 }
241
242 /**
243 * Load Task Manager
244 */
245 public function get_task_manager() {
246 include_once(WPO_PLUGIN_MAIN_PATH.'/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');
247
248 Updraft_Tasks_Activation::check_updates();
249
250 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-meta.php');
251 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-options.php');
252 include_once(WPO_PLUGIN_MAIN_PATH . '/vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
253
254 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-task.php');
255 include_once(WPO_PLUGIN_MAIN_PATH . '/includes/class-updraft-smush-manager.php');
256
257 return Updraft_Smush_Manager();
258 }
259
260 /**
261 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
262 *
263 * @returns Boolean
264 */
265 public static function is_premium() {
266 if (file_exists(WPO_PLUGIN_MAIN_PATH.'/premium.php') && function_exists('WP_Optimize_Premium')) {
267 $wp_optimize_premium = WP_Optimize_Premium();
268 if (is_a($wp_optimize_premium, 'WP_Optimize_Premium')) return true;
269 }
270 return false;
271 }
272
273 /**
274 * 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.
275 *
276 * @return bool
277 */
278 public function is_apache_server() {
279 global $is_apache;
280 return $is_apache;
281 }
282
283 /**
284 * Check if Apache module or modules active.
285 *
286 * @param string|array $module - single Apache module name or list of Apache module names.
287 *
288 * @return bool|null - if null, the result was indeterminate
289 */
290 public function is_apache_module_loaded($module) {
291 if (!$this->is_apache_server()) return false;
292
293 if (!function_exists('apache_get_modules')) return null;
294
295 $module_loaded = true;
296
297 if (is_array($module)) {
298 foreach ($module as $single_module) {
299 if (!in_array($single_module, apache_get_modules())) {
300 $module_loaded = false;
301 break;
302 }
303 }
304 } else {
305 $module_loaded = in_array($module, apache_get_modules());
306 }
307
308 return $module_loaded;
309 }
310
311 /**
312 * 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.
313 */
314 public function plugins_loaded() {
315
316 if (is_multisite()) {
317 add_action('network_admin_menu', array($this, 'admin_menu'));
318 }
319
320 // Run Premium loader if it exists
321 if (file_exists(WPO_PLUGIN_MAIN_PATH.'/premium.php') && !class_exists('WP_Optimize_Premium')) {
322 include_once(WPO_PLUGIN_MAIN_PATH.'/premium.php');
323 }
324
325 // load defaults
326 WP_Optimize()->get_options()->set_default_options();
327
328 // Initialize loggers.
329 $this->setup_loggers();
330
331 if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
332 if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
333 deactivate_plugins($free_plugin);
334
335 // If WPO_ADVANCED_CACHE is defined, we empty advanced-cache.php to regenerate later. Otherwise it contains the path to free.
336 if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
337 file_put_contents(trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php', '');
338 }
339
340 // Registers the notice letting the user know it cannot be active if premium is active.
341 add_action('admin_notices', array($this, 'show_admin_notice_premium'));
342 return;
343 }
344
345 // Loads the task manager
346 $this->get_task_manager();
347
348 // Loads the language file.
349 load_plugin_textdomain('wp-optimize', false, dirname(plugin_basename(__FILE__)) . '/languages');
350
351 // Load page cache.
352 $this->get_page_cache();
353 $this->init_page_cache();
354 }
355
356 /**
357 * Check whether one of free/Premium is active (whether it is this instance or not)
358 *
359 * @param String $which - 'free' or 'premium'
360 *
361 * @return String|Boolean - plugin path (if installed) or false if not
362 */
363 private function is_active($which = 'free') {
364 $active_plugins = $this->get_active_plugins();
365 foreach ($active_plugins as $file) {
366 if ('wp-optimize.php' == basename($file)) {
367 $plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
368 if (('free' == $which && !file_exists($plugin_dir.'/premium.php')) || ('free' != $which && file_exists($plugin_dir.'/premium.php'))) return $file;
369 }
370 }
371 return false;
372 }
373
374 /**
375 * Gets an array of plugins active on either the current site, or site-wide
376 *
377 * @return Array - a list of plugin paths (relative to the plugin directory)
378 */
379 private function get_active_plugins() {
380
381 // Gets all active plugins on the current site
382 $active_plugins = get_option('active_plugins');
383
384 if (is_multisite()) {
385 $network_active_plugins = get_site_option('active_sitewide_plugins');
386 if (!empty($network_active_plugins)) {
387 $network_active_plugins = array_keys($network_active_plugins);
388 $active_plugins = array_merge($active_plugins, $network_active_plugins);
389 }
390 }
391
392 return $active_plugins;
393 }
394
395 /**
396 * This function checks whether a specific plugin is installed, and returns information about it
397 *
398 * @param string $name Specify "Plugin Name" to return details about it.
399 * @return array Returns an array of details such as if installed, the name of the plugin and if it is active.
400 */
401 public function is_installed($name) {
402
403 // Needed to have the 'get_plugins()' function
404 include_once(ABSPATH.'wp-admin/includes/plugin.php');
405
406 // Gets all plugins available
407 $get_plugins = get_plugins();
408
409 $active_plugins = $this->get_active_plugins();
410
411 $plugin_info['installed'] = false;
412 $plugin_info['active'] = false;
413
414 // Loops around each plugin available.
415 foreach ($get_plugins as $key => $value) {
416 // If the plugin name matches that of the specified name, it will gather details.
417 if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
418 $plugin_info['installed'] = true;
419 $plugin_info['name'] = $key;
420 $plugin_info['version'] = $value['Version'];
421 if (in_array($key, $active_plugins)) {
422 $plugin_info['active'] = true;
423 }
424 break;
425 }
426 return $plugin_info;
427 }
428
429 /**
430 * This is a notice to show users that premium is installed
431 */
432 public function show_admin_notice_premium() {
433 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>';
434 if (isset($_GET['activate'])) unset($_GET['activate']);
435 }
436
437 /**
438 * Show update to Premium notice for non-premium multisite.
439 */
440 public function show_multisite_update_to_premium_notice() {
441 if (!is_multisite() || self::is_premium()) return;
442
443 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>';
444 }
445
446 public function admin_init() {
447 $pagenow = $GLOBALS['pagenow'];
448
449 $this->register_template_directories();
450
451 if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
452 $options = $this->get_options();
453
454 $dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);
455
456 if (file_exists(WPO_PLUGIN_MAIN_PATH . '/index.html')) {
457 $installed = filemtime(WPO_PLUGIN_MAIN_PATH . '/index.html');
458 $installed_for = (time() - $installed);
459 }
460
461 if (($installed && time() > $dismissed_until && $installed_for > (14 * 86400) && !defined('WP_OPTIMIZE_NOADS_B')) || (defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
462 add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead'));
463 }
464 }
465
466 $this->install_or_update_notice = include_once WPO_PLUGIN_MAIN_PATH . 'includes/class-wp-optimize-install-or-update-notice.php';
467 }
468
469 public function show_admin_notice_upgradead() {
470 $this->include_template('notices/thanks-for-using-main-dash.php');
471 }
472
473 public function capability_required() {
474 return apply_filters('wp_optimize_capability_required', 'manage_options');
475 }
476
477 public function wp_optimize_ajax_handler() {
478 $nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
479
480 if (!wp_verify_nonce($nonce, 'wp-optimize-ajax-nonce') || empty($_POST['subaction'])) die('Security check');
481
482 $subaction = $_POST['subaction'];
483 $data = isset($_POST['data']) ? $_POST['data'] : null;
484
485 if (!current_user_can($this->capability_required())) die('Security check');
486
487 // Currently the settings are only available to network admins.
488 if (is_multisite() && !current_user_can('manage_network_options')) {
489 /**
490 * Filters the commands allowed to the subsite admins. Other commands are only available to network admin. Only used in a multisite context.
491 */
492 $allowed_commands = apply_filters('wpo_multisite_allowed_commands', array('check_server_status', 'compress_single_image', 'restore_single_image'));
493 if (!in_array($subaction, $allowed_commands)) return array(
494 'result' => false,
495 'error_code' => 'update_failed',
496 'error_message' => __('Options can only be saved by network admin', 'wp-optimize')
497 );
498 }
499
500 $wp_optimize = $this;
501 $optimizer = $this->get_optimizer();
502 $options = $this->get_options();
503
504 $results = array();
505
506 // Some commands that are available via AJAX only.
507 if (in_array($subaction, array('dismiss_dash_notice_until', 'dismiss_season'))) {
508 $options->update_option($subaction, (time() + 366 * 86400));
509 } elseif (in_array($subaction, array('dismiss_page_notice_until', 'dismiss_notice'))) {
510 $options->update_option($subaction, (time() + 84 * 86400));
511 } else {
512 // Other commands, available for any remote method.
513 if (!class_exists('WP_Optimize_Commands')) include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-commands.php');
514 if (!class_exists('WP_Optimize_Cache_Commands')) include_once(WPO_PLUGIN_MAIN_PATH . 'cache/class-cache-commands.php');
515
516 $commands = new WP_Optimize_Commands();
517 $cache_commands = new WP_Optimize_Cache_Commands();
518
519 // check if called command not in main commands class and exist in cache commands class then change class.
520 if (!is_callable(array($commands, $subaction)) && is_callable(array($cache_commands, $subaction))) {
521 $commands = $cache_commands;
522 }
523
524 if (!is_callable(array($commands, $subaction))) {
525 error_log("WP-Optimize: ajax_handler: no such command (".$subaction.")");
526 die('No such command');
527 } else {
528 $results = call_user_func(array($commands, $subaction), $data);
529
530 // clean status box content, it broke json sometimes.
531 if (isset($results['status_box_contents'])) {
532 $results['status_box_contents'] = str_replace(array("\n", "\t"), '', $results['status_box_contents']);
533 }
534
535 if (is_wp_error($results)) {
536 $results = array(
537 'result' => false,
538 'error_code' => $results->get_error_code(),
539 'error_message' => $results->get_error_message(),
540 'error_data' => $results->get_error_data(),
541 );
542 }
543
544 // if nothing was returned for some reason, set as result null.
545 if (empty($results)) {
546 $results = array(
547 'result' => null
548 );
549 }
550 }
551 }
552
553 $result = json_encode($results);
554
555 // Requires PHP 5.3+
556 $json_last_error = function_exists('json_last_error') ? json_last_error() : false;
557
558 // if json_encode returned error then return error.
559 if ($json_last_error) {
560 $result = array(
561 'result' => false,
562 'error_code' => $json_last_error,
563 'error_message' => 'json_encode error : '.$json_last_error,
564 'error_data' => '',
565 );
566
567 $result = json_encode($result);
568 }
569
570 echo $result;
571
572 die;
573 }
574
575 /**
576 * Builds the Tabs that should be displayed
577 *
578 * @return array Returns all tabs specified
579 */
580 public function get_tabs($page) {
581 // define tabs for pages.
582 $pages_tabs = array(
583 'WP-Optimize' => array('optimize' => __('Optimizations', 'wp-optimize'), 'tables' => __('Tables', 'wp-optimize')),
584 'wpo_images' => array(
585 'smush' => __('Compress images', 'wp-optimize'),
586 'unused' => __('Unused images and sizes', 'wp-optimize').'<span class="premium-only">Premium</span>',
587 'lazyload' => __('Lazy-load', 'wp-optimize').'<span class="premium-only">Premium</span>',
588 ),
589 'wpo_cache' => array(
590 'cache' => __('Page cache', 'wp-optimize'),
591 'preload' => __('Preload', 'wp-optimize'),
592 'advanced' => __('Advanced settings', 'wp-optimize'),
593 'gzip' => __('Gzip compression', 'wp-optimize'),
594 'settings' => __('Static file headers', 'wp-optimize') // Adds a settings tab
595 ),
596 'wpo_settings' => array(
597 'settings' => array(
598 'title' => __('Settings', 'wp-optimize'),
599 ),
600 ),
601 'wpo_support' => array('support' => __('Support / FAQs', 'wp-optimize')),
602 'wpo_mayalso' => array('may_also' => __('Premium / Plugin family', 'wp-optimize')),
603 );
604
605 $tabs = (array_key_exists($page, $pages_tabs)) ? $pages_tabs[$page] : array();
606
607 return apply_filters('wp_optimize_admin_page_'.$page.'_tabs', $tabs);
608 }
609
610 /**
611 * Main page structure.
612 */
613 public function display_admin() {
614 $capability_required = $this->capability_required();
615
616 if (!current_user_can($capability_required) || (!$this->can_run_optimizations() && !$this->can_manage_options())) {
617 echo "Permission denied.";
618 return;
619 }
620
621 $this->register_admin_content();
622
623 echo '<div id="wp-optimize-wrap">';
624
625 $this->include_template('admin-page-header.php', false, array('show_notices' => !$this->install_or_update_notice->show_current_notice()));
626
627 do_action('wpo_admin_after_header');
628
629 echo '<div id="actions-results-area"></div>';
630
631 $pages = $this->get_submenu_items();
632
633 foreach ($pages as $page) {
634 if (isset($page['menu_slug'])) {
635 $this->display_admin_page($page['menu_slug']);
636 }
637 }
638
639 // closes main plugin wrapper div. #wp-optimize-wrap
640 echo '</div><!-- END #wp-optimize-wrap -->';
641
642 }
643
644 /**
645 * Prepare and display admin page with $page id.
646 *
647 * @param string $page wp-optimize page id i.e. dashboard, database, images, cache, ...
648 */
649 public function display_admin_page($page) {
650
651 $active_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
652
653 echo '<div class="wpo-page' . ($active_page == $page ? ' active' : '') . '" data-whichpage="'.$page.'">';
654
655 echo '<div class="wpo-main">';
656
657 // get defined tabs for $page.
658 $tabs = $this->get_tabs($page);
659
660 // if no tabs defined for $page then use $page as $active_tab for load template, doing related actions e t.c.
661 if (empty($tabs)) {
662 $active_tab = $page;
663 } else {
664 $tab_keys = array_keys($tabs);
665 $default_tab = apply_filters('wp_optimize_admin_'.$page.'_default_tab', $tab_keys[0]);
666 $active_tab = isset($_GET['tab']) ? substr($_GET['tab'], 12) : $default_tab;
667 if (!in_array($active_tab, array_keys($tabs))) $active_tab = $default_tab;
668 }
669
670 do_action('wp_optimize_admin_page_'.$page, $active_tab);
671
672 // if tabs defined then display
673 if (!empty($tabs)) {
674 $this->include_template('admin-page-header-tabs.php', false, array('page' => $page, 'active_tab' => $active_tab, 'tabs' => $tabs, 'wpo_is_premium' => self::is_premium()));
675 }
676
677 foreach ($tabs as $tab_id => $tab_description) {
678 // output wrap div for tab with id #wp-optimize-nav-tab-contents-'.$page.'-'.$tab_id
679 echo '<div class="wp-optimize-nav-tab-contents" id="wp-optimize-nav-tab-'.$page.'-'.$tab_id.'-contents" '.(($tab_id == $active_tab) ? '' : 'style="display:none;"').'>';
680
681 echo '<div class="postbox wpo-tab-postbox">';
682 // call action for generate tab content.
683
684 do_action('wp_optimize_admin_page_'.$page.'_'.$tab_id);
685
686 // closes postbox.
687 echo '</div><!-- END .postbox -->';
688 // closes tab wrapper.
689 echo '</div><!-- END .wp-optimize-nav-tab-contents -->';
690 }
691
692 echo '</div><!-- END .wpo-main -->';
693
694 do_action('wp_optimize_admin_after_page_'.$page, $active_tab);
695
696 echo '</div><!-- END .wpo-page -->';
697
698 }
699
700 /**
701 * Define required actions for admin pages.
702 */
703 public function register_admin_content() {
704 /**
705 * SETTINGS
706 */
707 add_action('wp_optimize_admin_page_wpo_settings_settings', array($this, 'output_dashboard_settings_tab'), 20);
708
709 /**
710 * Premium / other plugins
711 */
712 add_action('wp_optimize_admin_page_wpo_mayalso_may_also', array($this, 'output_dashboard_other_plugins_tab'), 20);
713
714 /**
715 * DATABASE
716 */
717 add_action('wp_optimize_admin_page_WP-Optimize_optimize', array($this, 'output_database_optimize_tab'), 20);
718
719 add_action('wp_optimize_admin_page_WP-Optimize_tables', array($this, 'output_database_tables_tab'), 20);
720
721 /**
722 * CACHE
723 */
724
725 add_action('wp_optimize_admin_page_wpo_cache_cache', array($this, 'output_page_cache_tab'), 20);
726 add_action('wp_optimize_admin_page_wpo_cache_preload', array($this, 'output_page_cache_preload_tab'), 20);
727 add_action('wp_optimize_admin_page_wpo_cache_advanced', array($this, 'output_page_cache_advanced_tab'), 20);
728 add_action('wp_optimize_admin_page_wpo_cache_gzip', array($this, 'output_cache_gzip_tab'), 20);
729 add_action('wp_optimize_admin_page_wpo_cache_settings', array($this, 'output_cache_settings_tab'), 20);
730
731 /**
732 * SUPPORT
733 */
734 add_action('wp_optimize_admin_page_wpo_support_support', array($this, 'output_dashboard_support_tab'), 20);
735 // Display Support page.
736
737 if (!self::is_premium()) {
738 /**
739 * Add action for display Images > Unused images and sizes tab.
740 */
741 add_action('wp_optimize_admin_page_wpo_images_unused', array($this, 'admin_page_wpo_images_unused'));
742
743 /**
744 * Add action for display Dashboard > Lazyload tab.
745 */
746 add_action('wp_optimize_admin_page_wpo_images_lazyload', array($this, 'admin_page_wpo_images_lazyload'));
747 }
748 }
749
750 /**
751 * Dashboard settings
752 */
753 public function output_dashboard_settings_tab() {
754 $options = $this->get_options();
755
756 if ('POST' == $_SERVER['REQUEST_METHOD']) {
757 // Nonce check.
758 check_admin_referer('wpo_settings');
759
760 $output = $options->save_settings($_POST);
761
762 if (isset($_POST['wp-optimize-settings'])) {
763 // save settings request sent.
764 $output = $options->save_settings($_POST);
765 }
766
767 $this->wpo_render_output_messages($output);
768 }
769
770 if ($this->can_manage_options()) {
771 $this->include_template('settings/settings.php');
772 } else {
773 $this->prevent_manage_options_info();
774 }
775 }
776
777 /**
778 * Dashboard support tab
779 */
780 public function output_dashboard_support_tab() {
781 WP_Optimize()->include_template('settings/support-and-faqs.php');
782 }
783
784 /**
785 * Dashboard Other plugins / premium tab
786 */
787 public function output_dashboard_other_plugins_tab() {
788 $this->include_template('settings/may-also-like.php');
789 }
790
791 /**
792 * Gzip tab
793 */
794 public function output_page_cache_tab() {
795 $wpo_cache = $this->get_page_cache();
796 $wpo_cache_options = $wpo_cache->config->get();
797 $display = $wpo_cache_options['enable_page_caching'] ? "style='display:block'" : "style='display:none'";
798
799 WP_Optimize()->include_template('cache/page-cache.php', false, array(
800 'wpo_cache' => $wpo_cache,
801 'active_cache_plugins' => WP_Optimize_Detect_Cache_Plugins::instance()->get_active_cache_plugins(),
802 'wpo_cache_options' => $wpo_cache_options,
803 'cache_size' => $this->get_page_cache()->get_cache_size(),
804 'display' => $display
805 ));
806 }
807
808 /**
809 * Preload tab
810 */
811 public function output_page_cache_preload_tab() {
812 $wpo_cache = $this->get_page_cache();
813 $wpo_cache_options = $wpo_cache->config->get();
814 $wpo_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance();
815 $is_running = $wpo_cache_preloader->is_running();
816 $status = $wpo_cache_preloader->get_status_info();
817
818 WP_Optimize()->include_template('cache/page-cache-preload.php', false, array(
819 'wpo_cache_options' => $wpo_cache_options,
820 'is_running' => $is_running,
821 'status_message' => isset($status['message']) ? $status['message'] : '',
822 'schedule_options' => array(
823 'wpo_use_cache_lifespan' => __('Same as cache lifespan', 'wp-optimize'),
824 'wpo_daily' => __('Daily', 'wp-optimize'),
825 'wpo_weekly' => __('Weekly', 'wp-optimize'),
826 'wpo_fortnightly' => __('Fortnightly', 'wp-optimize'),
827 'wpo_monthly' => __('Monthly (approx. - every 30 days)', 'wp-optimize')
828 )
829 ));
830 }
831
832 /**
833 * Advanced tab
834 */
835 public function output_page_cache_advanced_tab() {
836 $wpo_cache = $this->get_page_cache();
837 $wpo_cache_options = $wpo_cache->config->get();
838
839 $cache_exception_urls = is_array($wpo_cache_options['cache_exception_urls']) ? join("\n", $wpo_cache_options['cache_exception_urls']) : '';
840 $cache_exception_cookies = is_array($wpo_cache_options['cache_exception_cookies']) ? join("\n", $wpo_cache_options['cache_exception_cookies']) : '';
841 $cache_exception_browser_agents = is_array($wpo_cache_options['cache_exception_browser_agents']) ? join("\n", $wpo_cache_options['cache_exception_browser_agents']) : '';
842
843 WP_Optimize()->include_template('cache/page-cache-advanced.php', false, array(
844 'wpo_cache' => $this->get_page_cache(),
845 'wpo_cache_options' => $wpo_cache_options,
846 'cache_exception_urls' => $cache_exception_urls,
847 'cache_exception_cookies' => $cache_exception_cookies,
848 'cache_exception_browser_agents' => $cache_exception_browser_agents,
849 ));
850 }
851
852 /**
853 * Gzip tab
854 */
855 public function output_cache_gzip_tab() {
856 $wpo_gzip_compression = $this->get_gzip_compression();
857 $wpo_gzip_compression_enabled = $wpo_gzip_compression->is_gzip_compression_enabled(true);
858
859 WP_Optimize()->include_template('cache/gzip-compression.php', false, array(
860 'wpo_gzip_compression_enabled' => $wpo_gzip_compression_enabled,
861 'wpo_gzip_compression_settings_added' => $wpo_gzip_compression->is_gzip_compression_section_exists(),
862 'info_link' => 'https://getwpo.com/gzip-compression-explained/',
863 'faq_link' => 'https://getwpo.com/gzip-faq-link/',
864 'class_name' => (!is_wp_error($wpo_gzip_compression_enabled) && $wpo_gzip_compression_enabled ? 'wpo-enabled' : 'wpo-disabled')
865 ));
866 }
867
868 /**
869 * Cache tab
870 */
871 public function output_cache_settings_tab() {
872
873 $wpo_browser_cache = $this->get_browser_cache();
874 $wpo_browser_cache_enabled = $wpo_browser_cache->is_enabled();
875
876 WP_Optimize()->include_template('cache/browser-cache.php', false, array(
877 'wpo_browser_cache_enabled' => $wpo_browser_cache_enabled,
878 'wpo_browser_cache_settings_added' => $wpo_browser_cache->is_browser_cache_section_exists(),
879 'class_name' => (true === $wpo_browser_cache_enabled ? 'wpo-enabled' : 'wpo-disabled'),
880 'wpo_browser_cache_expire_days' => $this->get_options()->get_option('browser_cache_expire_days', '28'),
881 'wpo_browser_cache_expire_hours' => $this->get_options()->get_option('browser_cache_expire_hours', '0'),
882 'info_link' => 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching',
883 'faq_link' => 'https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04',
884 ));
885 }
886
887 /**
888 * Outputs the DB optimize Tab
889 */
890 public function output_database_optimize_tab() {
891 $optimizer = $this->get_optimizer();
892 $options = $this->get_options();
893
894 // check if nonce passed.
895 $nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
896
897 // save options.
898 if ($nonce_passed && isset($_POST['wp-optimize'])) $options->save_sent_manual_run_optimization_options($_POST, true);
899
900 $optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
901
902 $optimization_results = (($nonce_passed) ? $optimizer->do_optimizations($_POST) : false);
903
904 // display optimizations table or restricted access message.
905 if ($this->can_run_optimizations()) {
906 $this->include_template('database/optimize-table.php', false, array('optimize_db' => $optimize_db, 'optimization_results' => $optimization_results ));
907 } else {
908 $this->prevent_run_optimizations_message();
909 }
910 }
911
912 /**
913 * Outputs the DB Tables Tab
914 */
915 public function output_database_tables_tab() {
916 // check if nonce passed.
917 $nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
918
919 $optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
920
921 if ($this->can_run_optimizations()) {
922 $this->include_template('database/tables.php', false, array('optimize_db' => $optimize_db));
923 } else {
924 $this->prevent_run_optimizations_message();
925 }
926 }
927
928 /**
929 * Runs upon the WP action admin_page_wpo_images_unused
930 */
931 public function admin_page_wpo_images_unused() {
932 WP_Optimize()->include_template('images/unused.php');
933 }
934
935 /**
936 * Runs upon the WP action wp_optimize_admin_page_wpo_images_lazyload
937 */
938 public function admin_page_wpo_images_lazyload() {
939 WP_Optimize()->include_template('images/lazyload.php');
940 }
941
942 /**
943 * Returns array of translations used in javascript code.
944 *
945 * @return array
946 */
947 public function wpo_js_translations() {
948 return apply_filters('wpo_js_translations', array(
949 'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
950 'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
951 'optimization_complete' => __('Optimization complete', 'wp-optimize'),
952 'run_optimizations' => __('Run optimizations', 'wp-optimize'),
953 'cancel' => __('Cancel', 'wp-optimize'),
954 'enable' => __('Enable', 'wp-optimize'),
955 'disable' => __('Disable', 'wp-optimize'),
956 'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
957 'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
958 'fill_all_settings_fields' => __('Before saving, you need to complete the currently incomplete settings (or remove them).', 'wp-optimize'),
959 'table_was_not_repaired' => __('%s was not repaired. For more details, please check the logs (configured in your logging destinations settings).', 'wp-optimize'),
960 'are_you_sure_you_want_to_remove_this_table' => __('WARNING - some plugins might not be detected as installed or activated if they are in unknown folders (for example premium plugins).', 'wp-optimize').' '.__('Only delete a table if you are sure of what you are doing, and after taking a backup.', 'wp-optimize')." \r".__('Are you sure you want to remove this table?', 'wp-optimize'),
961 'table_was_not_deleted' => __('%s was not deleted. For more details, please check your logs configured in logging destinations settings.', 'wp-optimize'),
962 'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
963 'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
964 'update' => __('Update', 'wp-optimize'),
965 'run_now' => __('Run now', 'wp-optimize'),
966 'starting_preload' => __('Started preload...', 'wp-optimize'),
967 'loading_urls' => __('Loading URLs...', 'wp-optimize'),
968 'current_cache_size' => __('Current cache size:', 'wp-optimize'),
969 'number_of_files' => __('Number of files:', 'wp-optimize'),
970 'spinner_src' => esc_attr(admin_url('images/spinner-2x.gif')),
971 'sites' => $this->get_sites(),
972 ));
973 }
974
975 public function wpo_admin_bar() {
976 $wp_admin_bar = $GLOBALS['wp_admin_bar'];
977
978 if (defined('WPOPTIMIZE_ADMINBAR_DISABLE') && WPOPTIMIZE_ADMINBAR_DISABLE) return;
979
980 // Show menu item in top bar only for super admins.
981 if (is_multisite() & !is_super_admin(get_current_user_id())) return;
982
983 // Add a link called at the top admin bar.
984 $args = array(
985 'id' => 'wp-optimize-node',
986 'title' => apply_filters('wpoptimize_admin_node_title', 'WP-Optimize')
987 );
988 $wp_admin_bar->add_node($args);
989
990 $pages = $this->get_submenu_items();
991
992 foreach ($pages as $page_id => $page) {
993
994 if (!isset($page['create_submenu']) || !$page['create_submenu']) {
995 if (isset($page['icon']) && 'separator' == $page['icon']) {
996 $args = array(
997 'id' => 'wpo-separator-'.$page_id,
998 'parent' => 'wp-optimize-node',
999 'meta' => array(
1000 'class' => 'separator',
1001 ),
1002 );
1003 $wp_admin_bar->add_node($args);
1004 }
1005 continue;
1006 }
1007
1008 // 'menu_slug' => 'WP-Optimize',
1009
1010 $menu_page_url = menu_page_url($page['menu_slug'], false);
1011
1012 if (is_multisite()) {
1013 $menu_page_url = network_admin_url('admin.php?page='.$page['menu_slug']);
1014 }
1015
1016 $args = array(
1017 'id' => 'wpoptimize_admin_node_'.$page_id,
1018 'title' => $page['menu_title'],
1019 'parent' => 'wp-optimize-node',
1020 'href' => $menu_page_url,
1021 );
1022 $wp_admin_bar->add_node($args);
1023 }
1024
1025 }
1026
1027 /**
1028 * Add settings link on plugin page
1029 *
1030 * @param string $links Passing through the URL to be used within the HREF.
1031 * @return string Returns the Links.
1032 */
1033 public function plugin_settings_link($links) {
1034
1035 $admin_page_url = $this->get_options()->admin_page_url();
1036 $settings_page_url = $this->get_options()->admin_page_url('wpo_settings');
1037
1038 if (false == self::is_premium()) {
1039 $premium_link = '<a href="' . esc_url($this->premium_version_link) . '" target="_blank">' . __('Premium', 'wp-optimize') . '</a>';
1040 array_unshift($links, $premium_link);
1041 }
1042
1043 $settings_link = '<a href="' . esc_url($settings_page_url) . '">' . __('Settings', 'wp-optimize') . '</a>';
1044 array_unshift($links, $settings_link);
1045
1046 $optimize_link = '<a href="' . esc_url($admin_page_url) . '">' . __('Optimize', 'wp-optimize') . '</a>';
1047 array_unshift($links, $optimize_link);
1048 return $links;
1049 }
1050
1051 /**
1052 * Action wpo_tables_list_additional_column_data. Output button Optimize in the action column.
1053 *
1054 * @param string $content String for output to column
1055 * @param object $table_info Object with table info.
1056 *
1057 * @return string
1058 */
1059 public function tables_list_additional_column_data($content, $table_info) {
1060 if ($table_info->is_needing_repair) {
1061 $content .= '<div class="wpo_button_wrap">'
1062 . '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
1063 . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1064 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
1065 . '</div>';
1066 }
1067
1068 // table belongs to plugin.
1069 if ($table_info->can_be_removed) {
1070 $content .= '<div>'
1071 . '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
1072 . '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
1073 . '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
1074 . '</div>';
1075 }
1076
1077 return $content;
1078 }
1079
1080 /**
1081 * Initialize WP-Optimize page cache.
1082 */
1083 public function init_page_cache() {
1084 if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
1085 $this->get_page_cache()->enable();
1086 }
1087 }
1088
1089 /**
1090 * Schedules cron event based on selected schedule type
1091 *
1092 * @return void
1093 */
1094 public function cron_activate() {
1095 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
1096
1097 $options = $this->get_options();
1098
1099 if ($options->get_option('schedule') === false) {
1100 $options->set_default_options();
1101 } else {
1102 if ('true' == $options->get_option('schedule')) {
1103 if (!wp_next_scheduled('wpo_cron_event2')) {
1104 $schedule_type = $options->get_option('schedule-type', 'wpo_weekly');
1105
1106 // Backward compatibility
1107 if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';
1108
1109 $this_time = (86400 * 7);
1110
1111 switch ($schedule_type) {
1112 case "wpo_daily":
1113 $this_time = 86400;
1114 break;
1115
1116 case "wpo_weekly":
1117 $this_time = (86400 * 7);
1118 break;
1119
1120 case "wpo_fortnightly":
1121 $this_time = (86400 * 14);
1122 break;
1123
1124 case "wpo_monthly":
1125 $this_time = (86400 * 30);
1126 break;
1127 }
1128
1129 add_action('wpo_cron_event2', array($this, 'cron_action'));
1130 wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
1131 WP_Optimize()->log('running wp_schedule_event()');
1132 }
1133 }
1134 }
1135 }
1136
1137 /**
1138 * Clears all cron events
1139 *
1140 * @return void
1141 */
1142 public function wpo_cron_deactivate() {
1143 wp_clear_scheduled_hook('wpo_cron_event2');
1144 }
1145
1146 /**
1147 * Scheduler public functions to update schedulers
1148 *
1149 * @param array $schedules An array of schedules being passed.
1150 * @return array An array of schedules being returned.
1151 */
1152 public function cron_schedules($schedules) {
1153 $schedules['wpo_daily'] = array('interval' => 86400, 'display' => 'Once Daily');
1154 $schedules['wpo_weekly'] = array('interval' => 86400 * 7, 'display' => 'Once Weekly');
1155 $schedules['wpo_fortnightly'] = array('interval' => 86400 * 14, 'display' => 'Once Every Fortnight');
1156 $schedules['wpo_monthly'] = array('interval' => 86400 * 30, 'display' => 'Once Every Month');
1157 return $schedules;
1158 }
1159
1160 /**
1161 * Returns count of overdue cron jobs.
1162 *
1163 * @return integer
1164 */
1165 public function howmany_overdue_crons() {
1166 $how_many_overdue = 0;
1167 if (function_exists('_get_cron_array') || (is_file(ABSPATH.WPINC.'/cron.php') && include_once(ABSPATH.WPINC.'/cron.php') && function_exists('_get_cron_array'))) {
1168 $crons = _get_cron_array();
1169 if (is_array($crons)) {
1170 $timenow = time();
1171 foreach ($crons as $jt => $job) {
1172 if ($jt < $timenow) {
1173 $how_many_overdue++;
1174 }
1175 }
1176 }
1177 }
1178 return $how_many_overdue;
1179 }
1180
1181 /**
1182 * Run updates on plugin activation.
1183 */
1184 public function run_updates() {
1185 include_once(WPO_PLUGIN_MAIN_PATH.'/includes/class-wp-optimize-updates.php');
1186 WP_Optimize_Updates::check_updates();
1187 }
1188
1189 /**
1190 * Returns warning about overdue crons.
1191 *
1192 * @param int $howmany count of overdue crons
1193 * @return string
1194 */
1195 public function show_admin_warning_overdue_crons($howmany) {
1196 $ret = '<div class="updated below-h2"><p>';
1197 $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>';
1198 $ret .= '</p></div>';
1199 return $ret;
1200 }
1201
1202 public function admin_menu() {
1203
1204 $capability_required = $this->capability_required();
1205
1206 if (!current_user_can($capability_required) || (!$this->can_run_optimizations() && !$this->can_manage_options())) return;
1207
1208 $icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDE2IDE2IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc0MzE2IgogICBoZWlnaHQ9IjE2IgogICB3aWR0aD0iMTYiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0MzE4IiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQzMjEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSI+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2EwYTVhYTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTciCiAgICAgICBkPSJtIDEwLjc2ODgwOSw2Ljc2MTYwNTEgMCwwIGMgLTAuMDE2ODgsLTAuMDE2ODc4IC0wLjAyNTMxLC0wLjA0MjE4MSAtMC4wMzM3NCwtMC4wNjc0OTkgLTAuMDA4NCwtMC4wMDgzOSAtMC4wMDg0LC0wLjAxNjg3OCAtMC4wMTY4OCwtMC4wMzM3NDMgQyA5Ljk5MjYxMTIsNS4xOTIzMzY2IDguMjIwODU1Nyw0LjU4NDg3ODEgNi43NDQzOTEyLDUuMjkzNTc5NyA1LjY3MjkwMDUsNS44MDgyMzI4IDUuMDU3MDA0Myw2Ljg4ODE2MTMgNS4wNjU0NDIsOC4wMDE4MzY1IDQuNDU3OTgyMiw3LjMxMDAwNzYgMy42OTg2NTg0LDYuNzk1MzU0NSAyLjg1NDk2NDIsNi40OTE2MjUzIDMuMjY4Mzc0Myw1LjA2NTc4MzEgNC4yNTU0OTYsMy44MTcxMTY2IDUuNjg5Nzc0NiwzLjEyNTI4NzggOC4zNjQyODMyLDEuODM0NDM2OCAxMS41NzAzMTksMi45Mzk2NzQ0IDEyLjg4NjQ4MSw1LjU4ODg3MjYgMTMuNDUxNzU1LDYuNzI3ODU5NiAxNC42NDk4MDEsNy4zNTIxOTIxIDE1Ljg0Nzg0Niw3LjIzNDA3NSAxNS43NjM0ODIsNi4zMzk3NiAxNS41MTg4MDUsNS40MzcwMDg2IDE1LjEwNTM5Niw0LjU3NjQ0MDQgMTMuMjE1NTIxLDAuNjg3MDEzNCA4LjUzMzAyMjYsLTAuOTQxMzE2MjcgNC42NDM1OTQzLDAuOTQwMTIxNzkgMi4zMjM0MzcsMi4wNjIyMzM0IDAuODA0Nzg4MTQsNC4xNzk5MDQ0IDAuMzU3NjMxMzIsNi41MzM4MDk4IDIuNDE2MjQzOCw2LjQyNDEyOSA0LjQzMjY3MTcsNy41MDQwNTc0IDUuNDM2NjY2Miw5LjQzNjExNjcgbCAwLjAwODM5LDAgYyAwLjc1OTMxOTIsMS4zNzUyMjAzIDIuNDcyMDE3OCwxLjk0MDQ5NTMgMy45MDYyOTYsMS4yNDg2NjczIDEuMDQ2MTc5OCwtMC41MDYyMTggMS42NTM2NDA4LC0xLjUzNTUyMzggMS42Nzg5NTA4LC0yLjYxNTQ1MTIgMC41ODIxNDgsMC43MDg3MDE4IDEuMzMzMDM1LDEuMjQ4NjY2OCAyLjE1OTg1NiwxLjU3NzcwNjQgLTAuNDM4NzIxLDEuMzU4MzQ3OCAtMS40MDA1MzMsMi41NDc5NTQ4IC0yLjc5MjYyNywzLjIxNDQ3ODggLTIuNTkwMTM4NywxLjI0ODY1OCAtNS42NzgwNTc0LDAuMjUzMTA0IC03LjA2MTcxNTEsLTIuMjI3MzU3IGwgMCwwIEMgMi43NjIxMDQ4LDkuNDUyOTg5NCAxLjUxMzQzODMsOC44MjAyMTkxIDAuMjgxNjQ1OTIsOC45NzIwODQ0IDAuMzgyODg3NjUsOS43OTg5MDQ2IDAuNjE5MTIzMzEsMTAuNjE3Mjg3IDAuOTk4Nzg1MiwxMS40MDE5MjIgYyAxLjg4MTQzNjgsMy44OTc4NjQgNi41NjM5MzcsNS41MjYxOTggMTAuNDYxODAwOCwzLjY0NDc2IDIuMjQ0MjI2LC0xLjA4ODM2OSAzLjczNzU2MiwtMy4xMDQ3OTYgNC4yMzUzNDIsLTUuMzc0MzMyMyAtMS45OTk1NTQsMC4wNDIxODEgLTMuOTQ4NDg2LC0xLjAyOTMwNjMgLTQuOTI3MTcsLTIuOTEwNzQzMyB6IgogICAgICAgY2xhc3M9InN0MTciIC8+CiAgPC9nPgo8L3N2Zz4K';
1209
1210 // Removes the admin menu items on the left WP bar.
1211 if (!is_multisite() || (is_multisite() && is_network_admin())) {
1212 add_menu_page("WP-Optimize", "WP-Optimize", $capability_required, "WP-Optimize", array($this, "display_admin"), $icon_svg);
1213
1214 $sub_menu_items = $this->get_submenu_items();
1215
1216 foreach ($sub_menu_items as $menu_item) {
1217 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']);
1218 }
1219 }
1220
1221 $options = $this->get_options();
1222
1223 if ($options->get_option('enable-admin-menu', 'false') == 'true') {
1224 add_action('wp_before_admin_bar_render', array($this, 'wpo_admin_bar'));
1225 }
1226
1227 }
1228
1229 /**
1230 * Get the submenu items
1231 *
1232 * @return array
1233 */
1234 public function get_submenu_items() {
1235 $sub_menu_items = array(
1236 array(
1237 'page_title' => __('Database', 'wp-optimize'),
1238 'menu_title' => __('Database', 'wp-optimize'),
1239 'menu_slug' => 'WP-Optimize',
1240 'function' => array($this, 'display_admin'),
1241 'icon' => 'cloud',
1242 'create_submenu' => true,
1243 'order' => 20,
1244 ),
1245 array(
1246 'page_title' => __('Images', 'wp-optimize'),
1247 'menu_title' => __('Images', 'wp-optimize'),
1248 'menu_slug' => 'wpo_images',
1249 'function' => array($this, 'display_admin'),
1250 'icon' => 'images-alt2',
1251 'create_submenu' => true,
1252 'order' => 30,
1253 ),
1254 array(
1255 'page_title' => __('Cache', 'wp-optimize'),
1256 'menu_title' => __('Cache', 'wp-optimize'),
1257 'menu_slug' => 'wpo_cache',
1258 'function' => array($this, 'display_admin'),
1259 'icon' => 'archive',
1260 'create_submenu' => true,
1261 'order' => 40,
1262 ),
1263 array(
1264 'create_submenu' => false,
1265 'order' => 45,
1266 'icon' => 'separator',
1267 ),
1268 array(
1269 'page_title' => __('Settings', 'wp-optimize'),
1270 'menu_title' => __('Settings', 'wp-optimize'),
1271 'menu_slug' => 'wpo_settings',
1272 'function' => array($this, 'display_admin'),
1273 'icon' => 'admin-settings',
1274 'create_submenu' => true,
1275 'order' => 50,
1276 ),
1277 array(
1278 'page_title' => __('Support & FAQs', 'wp-optimize'),
1279 'menu_title' => __('Help', 'wp-optimize'),
1280 'menu_slug' => 'wpo_support',
1281 'function' => array($this, 'display_admin'),
1282 'icon' => 'sos',
1283 'create_submenu' => true,
1284 'order' => 60,
1285 ),
1286 array(
1287 'page_title' => __('Premium Upgrade', 'wp-optimize'),
1288 'menu_title' => __('Premium Upgrade', 'wp-optimize'),
1289 'menu_slug' => 'wpo_mayalso',
1290 'function' => array($this, 'display_admin'),
1291 'icon' => 'admin-plugins',
1292 'create_submenu' => true,
1293 'order' => 70,
1294 ),
1295 );
1296
1297 $sub_menu_items = apply_filters('wp_optimize_sub_menu_items', $sub_menu_items);
1298
1299 usort($sub_menu_items, array($this, 'order_sort'));
1300
1301 return $sub_menu_items;
1302 }
1303
1304 public function order_sort($a, $b) {
1305 if ($a['order'] == $b['order']) return 0;
1306 return ($a['order'] > $b['order']) ? 1 : -1;
1307 }
1308
1309 private function wp_normalize_path($path) {
1310 // Wp_normalize_path is not present before WP 3.9.
1311 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1312 // Taken from WP 4.6.
1313 $path = str_replace('\\', '/', $path);
1314 $path = preg_replace('|(?<=.)/+|', '/', $path);
1315 if (':' === substr($path, 1, 1)) {
1316 $path = ucfirst($path);
1317 }
1318 return $path;
1319 }
1320
1321 public function get_templates_dir() {
1322 return apply_filters('wp_optimize_templates_dir', $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'/templates'));
1323 }
1324
1325 public function get_templates_url() {
1326 return apply_filters('wp_optimize_templates_url', WPO_PLUGIN_URL.'/templates');
1327 }
1328
1329 /**
1330 * Return or output view content
1331 *
1332 * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1333 * @param Boolean $return_instead_of_echo - what to do with the results
1334 * @param Array $extract_these - key/value pairs for substitution into the scope of the template
1335 *
1336 * @return String|Void
1337 */
1338 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1339 if ($return_instead_of_echo) ob_start();
1340
1341 if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
1342 $prefix = $matches[1];
1343 $suffix = $matches[2];
1344 if (isset($this->template_directories[$prefix])) {
1345 $template_file = $this->template_directories[$prefix].'/'.$suffix;
1346 }
1347 }
1348
1349 if (!isset($template_file)) {
1350 $template_file = WPO_PLUGIN_MAIN_PATH.'/templates/'.$path;
1351 }
1352
1353 $template_file = apply_filters('wp_optimize_template', $template_file, $path);
1354
1355 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1356
1357 if (!file_exists($template_file)) {
1358 error_log("WP Optimize: template not found: ".$template_file);
1359 echo __('Error:', 'wp-optimize').' '.__('template not found', 'wp-optimize')." (".$path.")";
1360 } else {
1361 extract($extract_these);
1362 $wpdb = $GLOBALS['wpdb'];
1363 $wp_optimize = $this;
1364 $optimizer = $this->get_optimizer();
1365 $options = $this->get_options();
1366 $wp_optimize_notices = $this->get_notices();
1367 include $template_file;
1368 }
1369
1370 do_action('wp_optimize_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1371
1372 if ($return_instead_of_echo) return ob_get_clean();
1373 }
1374
1375 /**
1376 * Build a list of template directories (stored in self::$template_directories)
1377 */
1378 private function register_template_directories() {
1379
1380 $template_directories = array();
1381
1382 $templates_dir = $this->get_templates_dir();
1383
1384 if ($dh = opendir($templates_dir)) {
1385 while (($file = readdir($dh)) !== false) {
1386 if ('.' == $file || '..' == $file) continue;
1387 if (is_dir($templates_dir.'/'.$file)) {
1388 $template_directories[$file] = $templates_dir.'/'.$file;
1389 }
1390 }
1391 closedir($dh);
1392 }
1393
1394 // Optimal hook for most extensions to hook into.
1395 $this->template_directories = apply_filters('wp_optimize_template_directories', $template_directories);
1396
1397 }
1398
1399 /**
1400 * Not currently used; needs looking at.
1401 * N.B. The description does not match the actual function
1402 *
1403 * @param integer $date Date of when the optimization was executed.
1404 */
1405 public function send_email($date) {
1406 ob_start();
1407 // This need to work on - currently not using the parameter values.
1408 $my_time = current_time("timestamp", 0);
1409 $my_date = gmdate(get_option('date_format') . ' ' . get_option('time_format'), $my_time);
1410 $sendto = (!$options->get_option('email-address') ? get_bloginfo('admin_email') : $options->get_option('email-address'));
1411 $subject = get_bloginfo('name').": ".__("Automatic Operation Completed", "wp-optimize")." ".$my_date;
1412
1413 $msg = __("Scheduled optimization was executed at", "wp-optimize")." ".$my_date."\r\n"."\r\n";
1414 $msg .= __("You can safely delete this email.", "wp-optimize")."\r\n";
1415 $msg .= "\r\n";
1416 $msg .= __("Regards,", "wp-optimize")."\r\n";
1417 $msg .= __("WP-Optimize Plugin", "wp-optimize");
1418 ob_end_clean();
1419 }
1420
1421 /**
1422 * Message to debug
1423 *
1424 * @param string $message Message to insert into the log.
1425 * @param array $context array with variables used in $message like in template,
1426 * for ex.
1427 * $message = 'Hello {message}';
1428 * $context = ['message' => 'world']
1429 * 'Hello world' string will be saved in log.
1430 */
1431 public function log($message, $context = array()) {
1432 $this->get_logger()->debug($message, $context);
1433 }
1434
1435 /**
1436 * Format Bytes Into KB/MB
1437 *
1438 * @param mixed $bytes Number of bytes to be converted.
1439 * @return integer return the correct format size.
1440 */
1441 public function format_size($bytes) {
1442 if ($bytes > 1073741824) {
1443 return number_format_i18n(($bytes / 1073741824), 2) . ' '.__('GB', 'wp-optimize');
1444 } elseif ($bytes > 1048576) {
1445 return number_format_i18n(($bytes / 1048576), 1) . ' '.__('MB', 'wp-optimize');
1446 } elseif ($bytes > 1024) {
1447 return number_format_i18n(($bytes / 1024), 1) . ' '.__('KB', 'wp-optimize');
1448 } else {
1449 return number_format_i18n($bytes, 0) . ' '.__('bytes', 'wp-optimize');
1450 }
1451 }
1452
1453 /**
1454 * Executed this function on cron event.
1455 *
1456 * @return void
1457 */
1458 public function cron_action() {
1459
1460 $optimizer = $this->get_optimizer();
1461 $options = $this->get_options();
1462
1463 $this->log('WPO: Starting cron_action()');
1464
1465 if ('true' == $options->get_option('schedule')) {
1466 $this_options = $options->get_option('auto');
1467
1468 $optimizations = $optimizer->get_optimizations();
1469
1470 // Currently the output of the optimizations is not saved/used/logged.
1471 $results = $optimizer->do_optimizations($this_options, 'auto');
1472 }
1473
1474 }
1475
1476 /**
1477 * Schedule cron tasks used by plugin.
1478 *
1479 * @return void
1480 */
1481 public function schedule_plugin_cron_tasks() {
1482 if (!wp_next_scheduled('wpo_plugin_cron_tasks')) {
1483 wp_schedule_event(current_time("timestamp", 0), 'twicedaily', 'wpo_plugin_cron_tasks');
1484 }
1485
1486 add_action('wpo_plugin_cron_tasks', array($this, 'do_plugin_cron_tasks'));
1487 }
1488
1489 /**
1490 * Do plugin background tasks.
1491 *
1492 * @return void
1493 */
1494 public function do_plugin_cron_tasks() {
1495 // add tasks here.
1496 }
1497
1498 /**
1499 * This will customize a URL with a correct Affiliate link
1500 * This function can be update to suit any URL as longs as the URL is passed
1501 *
1502 * @param String $url - URL to be check to see if it an updraftplus match.
1503 * @param String $text - Text to be entered within the href a tags.
1504 * @param String $html - Any specific HTML to be added.
1505 * @param String $class - Specify a class for the href (including the attribute label)
1506 * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1507 *
1508 * @return String|void
1509 */
1510 public function wp_optimize_url($url, $text, $html = '', $class = '', $return_instead_of_echo = false) {
1511 // Check if the URL is UpdraftPlus.
1512 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
1513 if ('' != $html) {
1514 $result = '<a '.$class.' href="'.esc_attr($url).'">'.$html.'</a>';
1515 } else {
1516 $result = '<a '.$class.' href="'.esc_attr($url).'">'.htmlspecialchars($text).'</a>';
1517 }
1518 if ($return_instead_of_echo) return $result;
1519 echo $result;
1520 }
1521
1522 /**
1523 * Get an URL with an eventual affiliate ID
1524 *
1525 * @param string $url
1526 * @return string
1527 */
1528 public function maybe_add_affiliate_params($url) {
1529 // Check if the URL is UpdraftPlus.
1530 if (false !== strpos($url, '//updraftplus.com')) {
1531 // Set URL with Affiliate ID.
1532 $url = add_query_arg(array('afref' => $this->get_notices()->get_affiliate_id()), $url);
1533
1534 // Apply filters.
1535 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1536 }
1537 return apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
1538 }
1539
1540 /**
1541 * Setup WPO logger(s)
1542 */
1543 public function setup_loggers() {
1544
1545 $logger = $this->get_logger();
1546 $loggers = $this->wpo_loggers();
1547
1548 if (!empty($loggers)) {
1549 foreach ($loggers as $_logger) {
1550 $logger->add_logger($_logger);
1551 }
1552 }
1553
1554 add_action('wp_optimize_after_optimizations', array($this, 'after_optimizations_logger_action'));
1555 }
1556
1557 /**
1558 * Run logger actions after all optimizations done
1559 */
1560 public function after_optimizations_logger_action() {
1561 $loggers = $this->get_logger()->get_loggers();
1562 if (!empty($loggers)) {
1563 foreach ($loggers as $logger) {
1564 if (is_a($logger, 'Updraft_Email_Logger')) {
1565 $logger->flush_log();
1566 }
1567 }
1568 }
1569 }
1570
1571 /**
1572 * Returns list of WPO loggers instances
1573 * Apply filter wp_optimize_loggers
1574 *
1575 * @return array
1576 */
1577 public function wpo_loggers() {
1578
1579 $loggers = array();
1580 $loggers_classes_by_id = array();
1581 $options_keys = array();
1582
1583 $loggers_classes = $this->get_loggers_classes();
1584
1585 foreach ($loggers_classes as $logger_class => $source) {
1586 $loggers_classes_by_id[strtolower($logger_class)] = $logger_class;
1587 }
1588
1589 $options = $this->get_options();
1590
1591 $saved_loggers = $options->get_option('logging');
1592 $logger_additional_options = $options->get_option('logging-additional');
1593
1594 // create loggers classes instances.
1595 if (!empty($saved_loggers)) {
1596 // check for previous version options format.
1597 $keys = array_keys($saved_loggers);
1598
1599 // if options stored in old format then reformat it.
1600 if (false == is_numeric($keys[0])) {
1601 $_saved_loggers = array();
1602 foreach ($saved_loggers as $logger_id => $enabled) {
1603 if ($enabled) {
1604 $_saved_loggers[] = $logger_id;
1605 }
1606 }
1607
1608 // fill email with admin.
1609 if (array_key_exists('updraft_email_logger', $saved_loggers) && $saved_loggers['updraft_email_logger']) {
1610 $logger_additional_options['updraft_email_logger'] = array(
1611 get_option('admin_email')
1612 );
1613 }
1614
1615 $saved_loggers = $_saved_loggers;
1616 }
1617
1618 foreach ($saved_loggers as $i => $logger_id) {
1619
1620 if (!array_key_exists($logger_id, $loggers_classes_by_id)) continue;
1621
1622 $logger_class = $loggers_classes_by_id[$logger_id];
1623
1624 $logger = new $logger_class();
1625
1626 $logger_options = $logger->get_options_list();
1627
1628 if (!empty($logger_options)) {
1629 foreach (array_keys($logger_options) as $option_name) {
1630 if (array_key_exists($option_name, $options_keys)) {
1631 $options_keys[$option_name]++;
1632 } else {
1633 $options_keys[$option_name] = 0;
1634 }
1635
1636 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
1637
1638 // if options in old format then get correct value.
1639 if ('' === $option_value && array_key_exists($logger_id, $logger_additional_options)) {
1640 $option_value = array_shift($logger_additional_options[$logger_id]);
1641 }
1642
1643 $logger->set_option($option_name, $option_value);
1644 }
1645 }
1646
1647 // check if logger is active.
1648 $active = (!is_array($logger_additional_options) || (array_key_exists('active', $logger_additional_options) && empty($logger_additional_options['active'][$i]))) ? false : true;
1649
1650 if ($active) {
1651 $logger->enable();
1652 } else {
1653 $logger->disable();
1654 }
1655
1656 $loggers[] = $logger;
1657 }
1658 }
1659
1660 $loggers = apply_filters('wp_optimize_loggers', $loggers);
1661
1662 return $loggers;
1663 }
1664
1665 /**
1666 * Returns associative array with logger class name in a key and path to class file in a value.
1667 *
1668 * @return array
1669 */
1670 public function get_loggers_classes() {
1671 $loggers_classes = array(
1672 'Updraft_PHP_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-php-logger.php',
1673 'Updraft_Email_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-email-logger.php',
1674 'Updraft_Ring_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-ring-logger.php'
1675 );
1676
1677 $loggers_classes = apply_filters('wp_optimize_loggers_classes', $loggers_classes);
1678
1679 if (!empty($loggers_classes)) {
1680 foreach ($loggers_classes as $logger_class => $logger_file) {
1681 if (!class_exists($logger_class)) {
1682 if (is_file($logger_file)) {
1683 include_once($logger_file);
1684 }
1685 }
1686 }
1687 }
1688
1689 return $loggers_classes;
1690 }
1691
1692 /**
1693 * Returns information about all loggers classes.
1694 *
1695 * @return array
1696 */
1697 public function get_loggers_classes_info() {
1698 $loggers_classes = $this->get_loggers_classes();
1699
1700 $loggers_classes_info = array();
1701
1702 if (!empty($loggers_classes)) {
1703 foreach (array_keys($loggers_classes) as $logger_class_name) {
1704
1705 if (!class_exists($logger_class_name)) continue;
1706
1707 $logger_id = strtolower($logger_class_name);
1708 $logger_class = new $logger_class_name();
1709
1710 $loggers_classes_info[$logger_id] = array(
1711 'description' => $logger_class->get_description(),
1712 'available' => $logger_class->is_available(),
1713 'allow_multiple' => $logger_class->is_allow_multiple(),
1714 'options' => $logger_class->get_options_list()
1715 );
1716 }
1717 }
1718
1719 return $loggers_classes_info;
1720 }
1721
1722 /**
1723 * Returns true if optimization works in multisite mode
1724 *
1725 * @return boolean
1726 */
1727 public function is_multisite_mode() {
1728 return (is_multisite() && WP_Optimize()->is_premium());
1729 }
1730
1731 /**
1732 * Returns true if current user can run optimizations.
1733 *
1734 * @return bool
1735 */
1736 public function can_run_optimizations() {
1737 // we don't check permissions for cron jobs.
1738 if (defined('DOING_CRON') && DOING_CRON) return true;
1739
1740 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
1741 return true;
1742 }
1743
1744 /**
1745 * Returns true if current user can manage plugin options.
1746 *
1747 * @return bool
1748 */
1749 public function can_manage_options() {
1750 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_manage_settings')) return false;
1751 return true;
1752 }
1753
1754 /**
1755 * Output information message for users who have no permissions to run optimizations.
1756 */
1757 public function prevent_run_optimizations_message() {
1758 $this->include_template('info-message.php', false, array('message' => __('You have no permissions to run optimizations.', 'wp-optimize')));
1759 }
1760
1761 /**
1762 * Output information message for users who have no permissions to manage settings.
1763 */
1764 public function prevent_manage_options_info() {
1765 $this->include_template('info-message.php', false, array('message' => __('You have no permissions to manage WP-Optimize settings.', 'wp-optimize')));
1766 }
1767
1768 /**
1769 * Returns list of all sites in multisite
1770 *
1771 * @return array
1772 */
1773 public function get_sites() {
1774 $sites = array();
1775 // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
1776 if (function_exists('get_sites')) {
1777 $sites = get_sites(array('network_id' => null, 'number' => 999999));
1778 } elseif (function_exists('wp_get_sites')) {
1779 $sites = wp_get_sites(array('network_id' => null, 'limit' => 999999));
1780 }
1781 return $sites;
1782 }
1783
1784 /**
1785 * Output success/error messages from $output array.
1786 *
1787 * @param array $output ['messages' => success messages, 'errors' => error messages]
1788 */
1789 private function wpo_render_output_messages($output) {
1790 foreach ($output['messages'] as $item) {
1791 echo '<div class="updated fade below-h2"><strong>'.$item.'</strong></div>';
1792 }
1793
1794 foreach ($output['errors'] as $item) {
1795 echo '<div class="error fade below-h2"><strong>'.$item.'</strong></div>';
1796 }
1797 }
1798
1799 /**
1800 * Returns script memory limit in megabytes.
1801 *
1802 * @param bool $memory_limit
1803 * @return int
1804 */
1805 public function get_memory_limit($memory_limit = false) {
1806 // Returns in megabytes
1807 if (false == $memory_limit) $memory_limit = ini_get('memory_limit');
1808 $memory_limit = rtrim($memory_limit);
1809
1810 return $this->return_bytes($memory_limit);
1811 }
1812
1813 /**
1814 * Returns free memory in bytes.
1815 *
1816 * @return int
1817 */
1818 public function get_free_memory() {
1819 return $this->get_memory_limit() - memory_get_usage();
1820 }
1821
1822 /**
1823 * Checks PHP memory_limit and WP_MAX_MEMORY_LIMIT values and return minimal.
1824 *
1825 * @return int memory limit in bytes.
1826 */
1827 public function get_script_memory_limit() {
1828 $memory_limit = $this->get_memory_limit();
1829
1830 if (defined('WP_MAX_MEMORY_LIMIT')) {
1831 $wp_memory_limit = $this->get_memory_limit(WP_MAX_MEMORY_LIMIT);
1832
1833 if ($wp_memory_limit > 0 && $wp_memory_limit < $memory_limit) {
1834 $memory_limit = $wp_memory_limit;
1835 }
1836 }
1837
1838 return $memory_limit;
1839 }
1840
1841 /**
1842 * Returns max packet size for database.
1843 *
1844 * @return int|string
1845 */
1846 public function get_max_packet_size() {
1847 global $wpdb;
1848 static $mp = 0;
1849
1850 if ($mp > 0) return $mp;
1851
1852 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
1853 // Default to 1MB
1854 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
1855 // 32MB
1856 if ($mp < 33554432) {
1857 $save = $wpdb->show_errors(false);
1858 $req = @$wpdb->query("SET GLOBAL max_allowed_packet=33554432");
1859 $wpdb->show_errors($save);
1860
1861 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
1862 // Default to 1MB
1863 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
1864 }
1865
1866 return $mp;
1867 }
1868
1869 /**
1870 * Converts shorthand memory notation value to bytes.
1871 * From http://php.net/manual/en/function.ini-get.php
1872 *
1873 * @param string $val shorthand memory notation value.
1874 */
1875 public function return_bytes($val) {
1876 $val = trim($val);
1877 $last = strtolower($val[strlen($val)-1]);
1878 $val = (int) $val;
1879 switch ($last) {
1880 case 'g':
1881 $val *= 1024;
1882 // no break
1883 case 'm':
1884 $val *= 1024;
1885 // no break
1886 case 'k':
1887 $val *= 1024;
1888 }
1889
1890 return $val;
1891 }
1892
1893 /**
1894 * Log fatal errors to defined log destinations.
1895 */
1896 public function log_fatal_errors() {
1897 $last_error = error_get_last();
1898
1899 if (E_ERROR === $last_error['type']) {
1900 $this->get_logger()->critical($last_error['message']);
1901 }
1902 }
1903
1904 /**
1905 * Close browser connection and continue script work. - Taken from UpdraftPlus
1906 *
1907 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
1908 * @return void
1909 */
1910 public function close_browser_connection($txt = '') {
1911 // Close browser connection so that it can resume AJAX polling
1912 header('Content-Length: '.(empty($txt) ? '0' : 4+strlen($txt)));
1913 header('Connection: close');
1914 header('Content-Encoding: none');
1915 if (session_id()) session_write_close();
1916 echo "\r\n\r\n";
1917 echo $txt;
1918 // These two added - 19-Feb-15 - started being required on local dev machine, for unknown reason (probably some plugin that started an output buffer).
1919 $ob_level = ob_get_level();
1920 while ($ob_level > 0) {
1921 ob_end_flush();
1922 $ob_level--;
1923 }
1924 flush();
1925 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
1926 }
1927
1928 /**
1929 * Get the current theme's style.css headers
1930 *
1931 * @return array|WP_Error
1932 */
1933 public function get_stylesheet_headers() {
1934 static $headers;
1935 if (isset($headers)) return $headers;
1936
1937 $style = get_template_directory_uri() . '/style.css';
1938
1939 /**
1940 * Filters wp_remote_get parameters, when checking if browser cache is enabled.
1941 *
1942 * @param array $request_params Default parameters
1943 */
1944 $request_params = apply_filters('wpoptimize_get_stylesheet_headers_args', array('timeout' => 10));
1945
1946 // trying to load style.css.
1947 $response = wp_remote_get($style, $request_params);
1948
1949 if (is_a($response, 'WP_Error')) return $response;
1950
1951 $headers = wp_remote_retrieve_headers($response);
1952
1953 if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
1954 $headers = $headers->getAll();
1955 }
1956
1957 return $headers;
1958 }
1959
1960 /**
1961 * Try to change PHP script time limit.
1962 */
1963 public function change_time_limit() {
1964 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
1965
1966 // Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
1967 @set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1968 }
1969 }
1970
1971 /**
1972 * Plugin activation actions.
1973 */
1974 function wpo_activation_actions() {
1975 // If plugin activated by not a Network Administrator then deactivate plugin and show message.
1976 if (is_multisite() && !is_network_admin()) {
1977 deactivate_plugins(plugin_basename(__FILE__));
1978 wp_die(__('Only Network Administrator can activate WP-Optimize plugin.', 'wp-optimize').
1979 ' <a href="'.admin_url('plugins.php').'">'.__('go back', 'wp-optimize').'</a>');
1980 }
1981
1982 // On activation, check if last-optimized option exists. If not, add 'newly-activated' option.
1983 if (!WP_Optimize()->get_options()->get_option('last-optimized', false)) {
1984 WP_Optimize()->get_options()->update_option('newly-activated', true);
1985 }
1986
1987 WP_Optimize()->get_options()->set_default_options();
1988 WP_Optimize()->run_updates();
1989 }
1990
1991 /**
1992 * Plugin deactivation actions.
1993 */
1994 function wpo_deactivation_actions() {
1995 WP_Optimize()->wpo_cron_deactivate();
1996 WP_Optimize()->get_page_cache()->disable();
1997 }
1998
1999 function wpo_cron_deactivate() {
2000 WP_Optimize()->log('running wpo_cron_deactivate()');
2001 wp_clear_scheduled_hook('wpo_cron_event2');
2002 }
2003
2004 /**
2005 * Plugin uninstall actions.
2006 */
2007 function wpo_uninstall_actions() {
2008 WP_Optimize()->get_options()->delete_all_options();
2009 wp_clear_scheduled_hook('wpo_cron_plugin');
2010 }
2011
2012 function WP_Optimize() {
2013 return WP_Optimize::instance();
2014 }
2015
2016 endif;
2017
2018 $GLOBALS['wp_optimize'] = WP_Optimize();
2019