PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.0.12
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.0.12
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.12, at wp-optimize.php

2,010 lines 68.5 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.12
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.12');
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);
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 * Returns warning about overdue crons.
1183 *
1184 * @param int $howmany count of overdue crons
1185 * @return string
1186 */
1187 public function show_admin_warning_overdue_crons($howmany) {
1188 $ret = '<div class="updated below-h2"><p>';
1189 $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>';
1190 $ret .= '</p></div>';
1191 return $ret;
1192 }
1193
1194 public function admin_menu() {
1195
1196 $capability_required = $this->capability_required();
1197
1198 if (!current_user_can($capability_required) || (!$this->can_run_optimizations() && !$this->can_manage_options())) return;
1199
1200 $icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDE2IDE2IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc0MzE2IgogICBoZWlnaHQ9IjE2IgogICB3aWR0aD0iMTYiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0MzE4IiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQzMjEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSI+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2EwYTVhYTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTciCiAgICAgICBkPSJtIDEwLjc2ODgwOSw2Ljc2MTYwNTEgMCwwIGMgLTAuMDE2ODgsLTAuMDE2ODc4IC0wLjAyNTMxLC0wLjA0MjE4MSAtMC4wMzM3NCwtMC4wNjc0OTkgLTAuMDA4NCwtMC4wMDgzOSAtMC4wMDg0LC0wLjAxNjg3OCAtMC4wMTY4OCwtMC4wMzM3NDMgQyA5Ljk5MjYxMTIsNS4xOTIzMzY2IDguMjIwODU1Nyw0LjU4NDg3ODEgNi43NDQzOTEyLDUuMjkzNTc5NyA1LjY3MjkwMDUsNS44MDgyMzI4IDUuMDU3MDA0Myw2Ljg4ODE2MTMgNS4wNjU0NDIsOC4wMDE4MzY1IDQuNDU3OTgyMiw3LjMxMDAwNzYgMy42OTg2NTg0LDYuNzk1MzU0NSAyLjg1NDk2NDIsNi40OTE2MjUzIDMuMjY4Mzc0Myw1LjA2NTc4MzEgNC4yNTU0OTYsMy44MTcxMTY2IDUuNjg5Nzc0NiwzLjEyNTI4NzggOC4zNjQyODMyLDEuODM0NDM2OCAxMS41NzAzMTksMi45Mzk2NzQ0IDEyLjg4NjQ4MSw1LjU4ODg3MjYgMTMuNDUxNzU1LDYuNzI3ODU5NiAxNC42NDk4MDEsNy4zNTIxOTIxIDE1Ljg0Nzg0Niw3LjIzNDA3NSAxNS43NjM0ODIsNi4zMzk3NiAxNS41MTg4MDUsNS40MzcwMDg2IDE1LjEwNTM5Niw0LjU3NjQ0MDQgMTMuMjE1NTIxLDAuNjg3MDEzNCA4LjUzMzAyMjYsLTAuOTQxMzE2MjcgNC42NDM1OTQzLDAuOTQwMTIxNzkgMi4zMjM0MzcsMi4wNjIyMzM0IDAuODA0Nzg4MTQsNC4xNzk5MDQ0IDAuMzU3NjMxMzIsNi41MzM4MDk4IDIuNDE2MjQzOCw2LjQyNDEyOSA0LjQzMjY3MTcsNy41MDQwNTc0IDUuNDM2NjY2Miw5LjQzNjExNjcgbCAwLjAwODM5LDAgYyAwLjc1OTMxOTIsMS4zNzUyMjAzIDIuNDcyMDE3OCwxLjk0MDQ5NTMgMy45MDYyOTYsMS4yNDg2NjczIDEuMDQ2MTc5OCwtMC41MDYyMTggMS42NTM2NDA4LC0xLjUzNTUyMzggMS42Nzg5NTA4LC0yLjYxNTQ1MTIgMC41ODIxNDgsMC43MDg3MDE4IDEuMzMzMDM1LDEuMjQ4NjY2OCAyLjE1OTg1NiwxLjU3NzcwNjQgLTAuNDM4NzIxLDEuMzU4MzQ3OCAtMS40MDA1MzMsMi41NDc5NTQ4IC0yLjc5MjYyNywzLjIxNDQ3ODggLTIuNTkwMTM4NywxLjI0ODY1OCAtNS42NzgwNTc0LDAuMjUzMTA0IC03LjA2MTcxNTEsLTIuMjI3MzU3IGwgMCwwIEMgMi43NjIxMDQ4LDkuNDUyOTg5NCAxLjUxMzQzODMsOC44MjAyMTkxIDAuMjgxNjQ1OTIsOC45NzIwODQ0IDAuMzgyODg3NjUsOS43OTg5MDQ2IDAuNjE5MTIzMzEsMTAuNjE3Mjg3IDAuOTk4Nzg1MiwxMS40MDE5MjIgYyAxLjg4MTQzNjgsMy44OTc4NjQgNi41NjM5MzcsNS41MjYxOTggMTAuNDYxODAwOCwzLjY0NDc2IDIuMjQ0MjI2LC0xLjA4ODM2OSAzLjczNzU2MiwtMy4xMDQ3OTYgNC4yMzUzNDIsLTUuMzc0MzMyMyAtMS45OTk1NTQsMC4wNDIxODEgLTMuOTQ4NDg2LC0xLjAyOTMwNjMgLTQuOTI3MTcsLTIuOTEwNzQzMyB6IgogICAgICAgY2xhc3M9InN0MTciIC8+CiAgPC9nPgo8L3N2Zz4K';
1201
1202 // Removes the admin menu items on the left WP bar.
1203 if (!is_multisite() || (is_multisite() && is_network_admin())) {
1204 add_menu_page("WP-Optimize", "WP-Optimize", $capability_required, "WP-Optimize", array($this, "display_admin"), $icon_svg);
1205
1206 $sub_menu_items = $this->get_submenu_items();
1207
1208 foreach ($sub_menu_items as $menu_item) {
1209 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']);
1210 }
1211 }
1212
1213 $options = $this->get_options();
1214
1215 if ($options->get_option('enable-admin-menu', 'false') == 'true') {
1216 add_action('wp_before_admin_bar_render', array($this, 'wpo_admin_bar'));
1217 }
1218
1219 }
1220
1221 /**
1222 * Get the submenu items
1223 *
1224 * @return array
1225 */
1226 public function get_submenu_items() {
1227 $sub_menu_items = array(
1228 array(
1229 'page_title' => __('Database', 'wp-optimize'),
1230 'menu_title' => __('Database', 'wp-optimize'),
1231 'menu_slug' => 'WP-Optimize',
1232 'function' => array($this, 'display_admin'),
1233 'icon' => 'cloud',
1234 'create_submenu' => true,
1235 'order' => 20,
1236 ),
1237 array(
1238 'page_title' => __('Images', 'wp-optimize'),
1239 'menu_title' => __('Images', 'wp-optimize'),
1240 'menu_slug' => 'wpo_images',
1241 'function' => array($this, 'display_admin'),
1242 'icon' => 'images-alt2',
1243 'create_submenu' => true,
1244 'order' => 30,
1245 ),
1246 array(
1247 'page_title' => __('Cache', 'wp-optimize'),
1248 'menu_title' => __('Cache', 'wp-optimize'),
1249 'menu_slug' => 'wpo_cache',
1250 'function' => array($this, 'display_admin'),
1251 'icon' => 'archive',
1252 'create_submenu' => true,
1253 'order' => 40,
1254 ),
1255 array(
1256 'create_submenu' => false,
1257 'order' => 45,
1258 'icon' => 'separator',
1259 ),
1260 array(
1261 'page_title' => __('Settings', 'wp-optimize'),
1262 'menu_title' => __('Settings', 'wp-optimize'),
1263 'menu_slug' => 'wpo_settings',
1264 'function' => array($this, 'display_admin'),
1265 'icon' => 'admin-settings',
1266 'create_submenu' => true,
1267 'order' => 50,
1268 ),
1269 array(
1270 'page_title' => __('Support & FAQs', 'wp-optimize'),
1271 'menu_title' => __('Help', 'wp-optimize'),
1272 'menu_slug' => 'wpo_support',
1273 'function' => array($this, 'display_admin'),
1274 'icon' => 'sos',
1275 'create_submenu' => true,
1276 'order' => 60,
1277 ),
1278 array(
1279 'page_title' => __('Premium Upgrade', 'wp-optimize'),
1280 'menu_title' => __('Premium Upgrade', 'wp-optimize'),
1281 'menu_slug' => 'wpo_mayalso',
1282 'function' => array($this, 'display_admin'),
1283 'icon' => 'admin-plugins',
1284 'create_submenu' => true,
1285 'order' => 70,
1286 ),
1287 );
1288
1289 $sub_menu_items = apply_filters('wp_optimize_sub_menu_items', $sub_menu_items);
1290
1291 usort($sub_menu_items, array($this, 'order_sort'));
1292
1293 return $sub_menu_items;
1294 }
1295
1296 public function order_sort($a, $b) {
1297 if ($a['order'] == $b['order']) return 0;
1298 return ($a['order'] > $b['order']) ? 1 : -1;
1299 }
1300
1301 private function wp_normalize_path($path) {
1302 // Wp_normalize_path is not present before WP 3.9.
1303 if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
1304 // Taken from WP 4.6.
1305 $path = str_replace('\\', '/', $path);
1306 $path = preg_replace('|(?<=.)/+|', '/', $path);
1307 if (':' === substr($path, 1, 1)) {
1308 $path = ucfirst($path);
1309 }
1310 return $path;
1311 }
1312
1313 public function get_templates_dir() {
1314 return apply_filters('wp_optimize_templates_dir', $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'/templates'));
1315 }
1316
1317 public function get_templates_url() {
1318 return apply_filters('wp_optimize_templates_url', WPO_PLUGIN_URL.'/templates');
1319 }
1320
1321 /**
1322 * Return or output view content
1323 *
1324 * @param String $path - path to template, usually relative to templates/ within the WP-O directory
1325 * @param Boolean $return_instead_of_echo - what to do with the results
1326 * @param Array $extract_these - key/value pairs for substitution into the scope of the template
1327 *
1328 * @return String|Void
1329 */
1330 public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
1331 if ($return_instead_of_echo) ob_start();
1332
1333 if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
1334 $prefix = $matches[1];
1335 $suffix = $matches[2];
1336 if (isset($this->template_directories[$prefix])) {
1337 $template_file = $this->template_directories[$prefix].'/'.$suffix;
1338 }
1339 }
1340
1341 if (!isset($template_file)) {
1342 $template_file = WPO_PLUGIN_MAIN_PATH.'/templates/'.$path;
1343 }
1344
1345 $template_file = apply_filters('wp_optimize_template', $template_file, $path);
1346
1347 do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1348
1349 if (!file_exists($template_file)) {
1350 error_log("WP Optimize: template not found: ".$template_file);
1351 echo __('Error:', 'wp-optimize').' '.__('template not found', 'wp-optimize')." (".$path.")";
1352 } else {
1353 extract($extract_these);
1354 $wpdb = $GLOBALS['wpdb'];
1355 $wp_optimize = $this;
1356 $optimizer = $this->get_optimizer();
1357 $options = $this->get_options();
1358 $wp_optimize_notices = $this->get_notices();
1359 include $template_file;
1360 }
1361
1362 do_action('wp_optimize_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);
1363
1364 if ($return_instead_of_echo) return ob_get_clean();
1365 }
1366
1367 /**
1368 * Build a list of template directories (stored in self::$template_directories)
1369 */
1370 private function register_template_directories() {
1371
1372 $template_directories = array();
1373
1374 $templates_dir = $this->get_templates_dir();
1375
1376 if ($dh = opendir($templates_dir)) {
1377 while (($file = readdir($dh)) !== false) {
1378 if ('.' == $file || '..' == $file) continue;
1379 if (is_dir($templates_dir.'/'.$file)) {
1380 $template_directories[$file] = $templates_dir.'/'.$file;
1381 }
1382 }
1383 closedir($dh);
1384 }
1385
1386 // Optimal hook for most extensions to hook into.
1387 $this->template_directories = apply_filters('wp_optimize_template_directories', $template_directories);
1388
1389 }
1390
1391 /**
1392 * Not currently used; needs looking at.
1393 * N.B. The description does not match the actual function
1394 *
1395 * @param integer $date Date of when the optimization was executed.
1396 */
1397 public function send_email($date) {
1398 ob_start();
1399 // This need to work on - currently not using the parameter values.
1400 $my_time = current_time("timestamp", 0);
1401 $my_date = gmdate(get_option('date_format') . ' ' . get_option('time_format'), $my_time);
1402 $sendto = (!$options->get_option('email-address') ? get_bloginfo('admin_email') : $options->get_option('email-address'));
1403 $subject = get_bloginfo('name').": ".__("Automatic Operation Completed", "wp-optimize")." ".$my_date;
1404
1405 $msg = __("Scheduled optimization was executed at", "wp-optimize")." ".$my_date."\r\n"."\r\n";
1406 $msg .= __("You can safely delete this email.", "wp-optimize")."\r\n";
1407 $msg .= "\r\n";
1408 $msg .= __("Regards,", "wp-optimize")."\r\n";
1409 $msg .= __("WP-Optimize Plugin", "wp-optimize");
1410 ob_end_clean();
1411 }
1412
1413 /**
1414 * Message to debug
1415 *
1416 * @param string $message Message to insert into the log.
1417 * @param array $context array with variables used in $message like in template,
1418 * for ex.
1419 * $message = 'Hello {message}';
1420 * $context = ['message' => 'world']
1421 * 'Hello world' string will be saved in log.
1422 */
1423 public function log($message, $context = array()) {
1424 $this->get_logger()->debug($message, $context);
1425 }
1426
1427 /**
1428 * Format Bytes Into KB/MB
1429 *
1430 * @param mixed $bytes Number of bytes to be converted.
1431 * @return integer return the correct format size.
1432 */
1433 public function format_size($bytes) {
1434 if ($bytes > 1073741824) {
1435 return number_format_i18n(($bytes / 1073741824), 2) . ' '.__('GB', 'wp-optimize');
1436 } elseif ($bytes > 1048576) {
1437 return number_format_i18n(($bytes / 1048576), 1) . ' '.__('MB', 'wp-optimize');
1438 } elseif ($bytes > 1024) {
1439 return number_format_i18n(($bytes / 1024), 1) . ' '.__('KB', 'wp-optimize');
1440 } else {
1441 return number_format_i18n($bytes, 0) . ' '.__('bytes', 'wp-optimize');
1442 }
1443 }
1444
1445 /**
1446 * Executed this function on cron event.
1447 *
1448 * @return void
1449 */
1450 public function cron_action() {
1451
1452 $optimizer = $this->get_optimizer();
1453 $options = $this->get_options();
1454
1455 $this->log('WPO: Starting cron_action()');
1456
1457 if ('true' == $options->get_option('schedule')) {
1458 $this_options = $options->get_option('auto');
1459
1460 $optimizations = $optimizer->get_optimizations();
1461
1462 // Currently the output of the optimizations is not saved/used/logged.
1463 $results = $optimizer->do_optimizations($this_options, 'auto');
1464 }
1465
1466 }
1467
1468 /**
1469 * Schedule cron tasks used by plugin.
1470 *
1471 * @return void
1472 */
1473 public function schedule_plugin_cron_tasks() {
1474 if (!wp_next_scheduled('wpo_plugin_cron_tasks')) {
1475 wp_schedule_event(current_time("timestamp", 0), 'twicedaily', 'wpo_plugin_cron_tasks');
1476 }
1477
1478 add_action('wpo_plugin_cron_tasks', array($this, 'do_plugin_cron_tasks'));
1479 }
1480
1481 /**
1482 * Do plugin background tasks.
1483 *
1484 * @return void
1485 */
1486 public function do_plugin_cron_tasks() {
1487 // add tasks here.
1488 }
1489
1490 /**
1491 * This will customize a URL with a correct Affiliate link
1492 * This function can be update to suit any URL as longs as the URL is passed
1493 *
1494 * @param String $url - URL to be check to see if it an updraftplus match.
1495 * @param String $text - Text to be entered within the href a tags.
1496 * @param String $html - Any specific HTML to be added.
1497 * @param String $class - Specify a class for the href (including the attribute label)
1498 * @param Boolean $return_instead_of_echo - if set, then the result will be returned, not echo-ed.
1499 *
1500 * @return String|void
1501 */
1502 public function wp_optimize_url($url, $text, $html = '', $class = '', $return_instead_of_echo = false) {
1503 // Check if the URL is UpdraftPlus.
1504 $url = $this->maybe_add_affiliate_params($url); // Return URL - check if there is HTML such as images.
1505 if ('' != $html) {
1506 $result = '<a '.$class.' href="'.esc_attr($url).'">'.$html.'</a>';
1507 } else {
1508 $result = '<a '.$class.' href="'.esc_attr($url).'">'.htmlspecialchars($text).'</a>';
1509 }
1510 if ($return_instead_of_echo) return $result;
1511 echo $result;
1512 }
1513
1514 /**
1515 * Get an URL with an eventual affiliate ID
1516 *
1517 * @param string $url
1518 * @return string
1519 */
1520 public function maybe_add_affiliate_params($url) {
1521 // Check if the URL is UpdraftPlus.
1522 if (false !== strpos($url, '//updraftplus.com')) {
1523 // Set URL with Affiliate ID.
1524 $url = add_query_arg(array('afref' => $this->get_notices()->get_affiliate_id()), $url);
1525
1526 // Apply filters.
1527 $url = apply_filters('wpoptimize_updraftplus_com_link', $url);
1528 }
1529 return apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
1530 }
1531
1532 /**
1533 * Setup WPO logger(s)
1534 */
1535 public function setup_loggers() {
1536
1537 $logger = $this->get_logger();
1538 $loggers = $this->wpo_loggers();
1539
1540 if (!empty($loggers)) {
1541 foreach ($loggers as $_logger) {
1542 $logger->add_logger($_logger);
1543 }
1544 }
1545
1546 add_action('wp_optimize_after_optimizations', array($this, 'after_optimizations_logger_action'));
1547 }
1548
1549 /**
1550 * Run logger actions after all optimizations done
1551 */
1552 public function after_optimizations_logger_action() {
1553 $loggers = $this->get_logger()->get_loggers();
1554 if (!empty($loggers)) {
1555 foreach ($loggers as $logger) {
1556 if (is_a($logger, 'Updraft_Email_Logger')) {
1557 $logger->flush_log();
1558 }
1559 }
1560 }
1561 }
1562
1563 /**
1564 * Returns list of WPO loggers instances
1565 * Apply filter wp_optimize_loggers
1566 *
1567 * @return array
1568 */
1569 public function wpo_loggers() {
1570
1571 $loggers = array();
1572 $loggers_classes_by_id = array();
1573 $options_keys = array();
1574
1575 $loggers_classes = $this->get_loggers_classes();
1576
1577 foreach ($loggers_classes as $logger_class => $source) {
1578 $loggers_classes_by_id[strtolower($logger_class)] = $logger_class;
1579 }
1580
1581 $options = $this->get_options();
1582
1583 $saved_loggers = $options->get_option('logging');
1584 $logger_additional_options = $options->get_option('logging-additional');
1585
1586 // create loggers classes instances.
1587 if (!empty($saved_loggers)) {
1588 // check for previous version options format.
1589 $keys = array_keys($saved_loggers);
1590
1591 // if options stored in old format then reformat it.
1592 if (false == is_numeric($keys[0])) {
1593 $_saved_loggers = array();
1594 foreach ($saved_loggers as $logger_id => $enabled) {
1595 if ($enabled) {
1596 $_saved_loggers[] = $logger_id;
1597 }
1598 }
1599
1600 // fill email with admin.
1601 if (array_key_exists('updraft_email_logger', $saved_loggers) && $saved_loggers['updraft_email_logger']) {
1602 $logger_additional_options['updraft_email_logger'] = array(
1603 get_option('admin_email')
1604 );
1605 }
1606
1607 $saved_loggers = $_saved_loggers;
1608 }
1609
1610 foreach ($saved_loggers as $i => $logger_id) {
1611
1612 if (!array_key_exists($logger_id, $loggers_classes_by_id)) continue;
1613
1614 $logger_class = $loggers_classes_by_id[$logger_id];
1615
1616 $logger = new $logger_class();
1617
1618 $logger_options = $logger->get_options_list();
1619
1620 if (!empty($logger_options)) {
1621 foreach (array_keys($logger_options) as $option_name) {
1622 if (array_key_exists($option_name, $options_keys)) {
1623 $options_keys[$option_name]++;
1624 } else {
1625 $options_keys[$option_name] = 0;
1626 }
1627
1628 $option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';
1629
1630 // if options in old format then get correct value.
1631 if ('' === $option_value && array_key_exists($logger_id, $logger_additional_options)) {
1632 $option_value = array_shift($logger_additional_options[$logger_id]);
1633 }
1634
1635 $logger->set_option($option_name, $option_value);
1636 }
1637 }
1638
1639 // check if logger is active.
1640 $active = (!is_array($logger_additional_options) || (array_key_exists('active', $logger_additional_options) && empty($logger_additional_options['active'][$i]))) ? false : true;
1641
1642 if ($active) {
1643 $logger->enable();
1644 } else {
1645 $logger->disable();
1646 }
1647
1648 $loggers[] = $logger;
1649 }
1650 }
1651
1652 $loggers = apply_filters('wp_optimize_loggers', $loggers);
1653
1654 return $loggers;
1655 }
1656
1657 /**
1658 * Returns associative array with logger class name in a key and path to class file in a value.
1659 *
1660 * @return array
1661 */
1662 public function get_loggers_classes() {
1663 $loggers_classes = array(
1664 'Updraft_PHP_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-php-logger.php',
1665 'Updraft_Email_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-email-logger.php',
1666 'Updraft_Ring_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-ring-logger.php'
1667 );
1668
1669 $loggers_classes = apply_filters('wp_optimize_loggers_classes', $loggers_classes);
1670
1671 if (!empty($loggers_classes)) {
1672 foreach ($loggers_classes as $logger_class => $logger_file) {
1673 if (!class_exists($logger_class)) {
1674 if (is_file($logger_file)) {
1675 include_once($logger_file);
1676 }
1677 }
1678 }
1679 }
1680
1681 return $loggers_classes;
1682 }
1683
1684 /**
1685 * Returns information about all loggers classes.
1686 *
1687 * @return array
1688 */
1689 public function get_loggers_classes_info() {
1690 $loggers_classes = $this->get_loggers_classes();
1691
1692 $loggers_classes_info = array();
1693
1694 if (!empty($loggers_classes)) {
1695 foreach (array_keys($loggers_classes) as $logger_class_name) {
1696
1697 if (!class_exists($logger_class_name)) continue;
1698
1699 $logger_id = strtolower($logger_class_name);
1700 $logger_class = new $logger_class_name();
1701
1702 $loggers_classes_info[$logger_id] = array(
1703 'description' => $logger_class->get_description(),
1704 'available' => $logger_class->is_available(),
1705 'allow_multiple' => $logger_class->is_allow_multiple(),
1706 'options' => $logger_class->get_options_list()
1707 );
1708 }
1709 }
1710
1711 return $loggers_classes_info;
1712 }
1713
1714 /**
1715 * Returns true if optimization works in multisite mode
1716 *
1717 * @return boolean
1718 */
1719 public function is_multisite_mode() {
1720 return (is_multisite() && WP_Optimize()->is_premium());
1721 }
1722
1723 /**
1724 * Returns true if current user can run optimizations.
1725 *
1726 * @return bool
1727 */
1728 public function can_run_optimizations() {
1729 // we don't check permissions for cron jobs.
1730 if (defined('DOING_CRON') && DOING_CRON) return true;
1731
1732 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
1733 return true;
1734 }
1735
1736 /**
1737 * Returns true if current user can manage plugin options.
1738 *
1739 * @return bool
1740 */
1741 public function can_manage_options() {
1742 if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_manage_settings')) return false;
1743 return true;
1744 }
1745
1746 /**
1747 * Output information message for users who have no permissions to run optimizations.
1748 */
1749 public function prevent_run_optimizations_message() {
1750 $this->include_template('info-message.php', false, array('message' => __('You have no permissions to run optimizations.', 'wp-optimize')));
1751 }
1752
1753 /**
1754 * Output information message for users who have no permissions to manage settings.
1755 */
1756 public function prevent_manage_options_info() {
1757 $this->include_template('info-message.php', false, array('message' => __('You have no permissions to manage WP-Optimize settings.', 'wp-optimize')));
1758 }
1759
1760 /**
1761 * Returns list of all sites in multisite
1762 *
1763 * @return array
1764 */
1765 public function get_sites() {
1766 $sites = array();
1767 // check if function get_sites exists (since 4.6.0) else use wp_get_sites.
1768 if (function_exists('get_sites')) {
1769 $sites = get_sites(array('network_id' => null, 'number' => 999999));
1770 } elseif (function_exists('wp_get_sites')) {
1771 $sites = wp_get_sites(array('network_id' => null, 'limit' => 999999));
1772 }
1773 return $sites;
1774 }
1775
1776 /**
1777 * Output success/error messages from $output array.
1778 *
1779 * @param array $output ['messages' => success messages, 'errors' => error messages]
1780 */
1781 private function wpo_render_output_messages($output) {
1782 foreach ($output['messages'] as $item) {
1783 echo '<div class="updated fade below-h2"><strong>'.$item.'</strong></div>';
1784 }
1785
1786 foreach ($output['errors'] as $item) {
1787 echo '<div class="error fade below-h2"><strong>'.$item.'</strong></div>';
1788 }
1789 }
1790
1791 /**
1792 * Returns script memory limit in megabytes.
1793 *
1794 * @param bool $memory_limit
1795 * @return int
1796 */
1797 public function get_memory_limit($memory_limit = false) {
1798 // Returns in megabytes
1799 if (false == $memory_limit) $memory_limit = ini_get('memory_limit');
1800 $memory_limit = rtrim($memory_limit);
1801
1802 return $this->return_bytes($memory_limit);
1803 }
1804
1805 /**
1806 * Returns free memory in bytes.
1807 *
1808 * @return int
1809 */
1810 public function get_free_memory() {
1811 return $this->get_memory_limit() - memory_get_usage();
1812 }
1813
1814 /**
1815 * Checks PHP memory_limit and WP_MAX_MEMORY_LIMIT values and return minimal.
1816 *
1817 * @return int memory limit in bytes.
1818 */
1819 public function get_script_memory_limit() {
1820 $memory_limit = $this->get_memory_limit();
1821
1822 if (defined('WP_MAX_MEMORY_LIMIT')) {
1823 $wp_memory_limit = $this->get_memory_limit(WP_MAX_MEMORY_LIMIT);
1824
1825 if ($wp_memory_limit > 0 && $wp_memory_limit < $memory_limit) {
1826 $memory_limit = $wp_memory_limit;
1827 }
1828 }
1829
1830 return $memory_limit;
1831 }
1832
1833 /**
1834 * Returns max packet size for database.
1835 *
1836 * @return int|string
1837 */
1838 public function get_max_packet_size() {
1839 global $wpdb;
1840 static $mp = 0;
1841
1842 if ($mp > 0) return $mp;
1843
1844 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
1845 // Default to 1MB
1846 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
1847 // 32MB
1848 if ($mp < 33554432) {
1849 $save = $wpdb->show_errors(false);
1850 $req = @$wpdb->query("SET GLOBAL max_allowed_packet=33554432");
1851 $wpdb->show_errors($save);
1852
1853 $mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
1854 // Default to 1MB
1855 $mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
1856 }
1857
1858 return $mp;
1859 }
1860
1861 /**
1862 * Converts shorthand memory notation value to bytes.
1863 * From http://php.net/manual/en/function.ini-get.php
1864 *
1865 * @param string $val shorthand memory notation value.
1866 */
1867 public function return_bytes($val) {
1868 $val = trim($val);
1869 $last = strtolower($val[strlen($val)-1]);
1870 $val = (int) $val;
1871 switch ($last) {
1872 case 'g':
1873 $val *= 1024;
1874 // no break
1875 case 'm':
1876 $val *= 1024;
1877 // no break
1878 case 'k':
1879 $val *= 1024;
1880 }
1881
1882 return $val;
1883 }
1884
1885 /**
1886 * Log fatal errors to defined log destinations.
1887 */
1888 public function log_fatal_errors() {
1889 $last_error = error_get_last();
1890
1891 if (E_ERROR === $last_error['type']) {
1892 $this->get_logger()->critical($last_error['message']);
1893 }
1894 }
1895
1896 /**
1897 * Close browser connection and continue script work. - Taken from UpdraftPlus
1898 *
1899 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
1900 * @return void
1901 */
1902 public function close_browser_connection($txt = '') {
1903 // Close browser connection so that it can resume AJAX polling
1904 header('Content-Length: '.(empty($txt) ? '0' : 4+strlen($txt)));
1905 header('Connection: close');
1906 header('Content-Encoding: none');
1907 if (session_id()) session_write_close();
1908 echo "\r\n\r\n";
1909 echo $txt;
1910 // These two added - 19-Feb-15 - started being required on local dev machine, for unknown reason (probably some plugin that started an output buffer).
1911 $ob_level = ob_get_level();
1912 while ($ob_level > 0) {
1913 ob_end_flush();
1914 $ob_level--;
1915 }
1916 flush();
1917 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
1918 }
1919
1920 /**
1921 * Get the current theme's style.css headers
1922 *
1923 * @return array|WP_Error
1924 */
1925 public function get_stylesheet_headers() {
1926 static $headers;
1927 if (isset($headers)) return $headers;
1928
1929 $style = get_template_directory_uri() . '/style.css';
1930
1931 /**
1932 * Filters wp_remote_get parameters, when checking if browser cache is enabled.
1933 *
1934 * @param array $request_params Default parameters
1935 */
1936 $request_params = apply_filters('wpoptimize_get_stylesheet_headers_args', array('timeout' => 10));
1937
1938 // trying to load style.css.
1939 $response = wp_remote_get($style, $request_params);
1940
1941 if (is_a($response, 'WP_Error')) return $response;
1942
1943 $headers = wp_remote_retrieve_headers($response);
1944
1945 if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
1946 $headers = $headers->getAll();
1947 }
1948
1949 return $headers;
1950 }
1951
1952 /**
1953 * Try to change PHP script time limit.
1954 */
1955 public function change_time_limit() {
1956 $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
1957
1958 // Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
1959 @set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1960 }
1961 }
1962
1963 /**
1964 * Plugin activation actions.
1965 */
1966 function wpo_activation_actions() {
1967 // If plugin activated by not a Network Administrator then deactivate plugin and show message.
1968 if (is_multisite() && !is_network_admin()) {
1969 deactivate_plugins(plugin_basename(__FILE__));
1970 wp_die(__('Only Network Administrator can activate WP-Optimize plugin.', 'wp-optimize').
1971 ' <a href="'.admin_url('plugins.php').'">'.__('go back', 'wp-optimize').'</a>');
1972 }
1973
1974 // On activation, check if last-optimized option exists. If not, add 'newly-activated' option.
1975 if (!WP_Optimize()->get_options()->get_option('last-optimized', false)) {
1976 WP_Optimize()->get_options()->update_option('newly-activated', true);
1977 }
1978
1979 WP_Optimize()->get_options()->set_default_options();
1980 }
1981
1982 /**
1983 * Plugin deactivation actions.
1984 */
1985 function wpo_deactivation_actions() {
1986 WP_Optimize()->wpo_cron_deactivate();
1987 WP_Optimize()->get_page_cache()->disable();
1988 }
1989
1990 function wpo_cron_deactivate() {
1991 WP_Optimize()->log('running wpo_cron_deactivate()');
1992 wp_clear_scheduled_hook('wpo_cron_event2');
1993 }
1994
1995 /**
1996 * Plugin uninstall actions.
1997 */
1998 function wpo_uninstall_actions() {
1999 WP_Optimize()->get_options()->delete_all_options();
2000 wp_clear_scheduled_hook('wpo_cron_plugin');
2001 }
2002
2003 function WP_Optimize() {
2004 return WP_Optimize::instance();
2005 }
2006
2007 endif;
2008
2009 $GLOBALS['wp_optimize'] = WP_Optimize();
2010