PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.1.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.1.0
4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 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.1.0, at wp-optimize.php

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