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

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