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

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