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

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