[ Avaa Bypassed ]




Upload:

Command:

hmhc3928@3.142.130.127: ~ $
<?php
/**
Plugin Name: WP-Optimize - Clean, Compress, Cache
Plugin URI: https://getwpo.com
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.
Version: 3.8.0
Update URI: https://wordpress.org/plugins/wp-optimize/
Author: TeamUpdraft, DavidAnderson
Author URI: https://updraftplus.com
Text Domain: wp-optimize
Domain Path: /languages
License: GPLv2 or later
 */

if (!defined('ABSPATH')) die('No direct access allowed');

// Check to make sure if WP_Optimize is already call and returns.
if (!class_exists('WP_Optimize')) :
define('WPO_VERSION', '3.8.0');
define('WPO_PLUGIN_URL', plugin_dir_url(__FILE__));
define('WPO_PLUGIN_MAIN_PATH', plugin_dir_path(__FILE__));
define('WPO_PLUGIN_SLUG', plugin_basename(__FILE__));
define('WPO_PREMIUM_NOTIFICATION', false);
define('WPO_REQUIRED_PHP_VERSION', '5.6');
if (!defined('WPO_USE_WEBP_CONVERSION')) define('WPO_USE_WEBP_CONVERSION', true);

class WP_Optimize {

	public $premium_version_link = 'https://getwpo.com/buy/';

	private $template_directories;

	protected static $_instance = null;

	protected $_cache_init_status = null;

	/**
	 * Class constructor
	 */
	public function __construct() {

		spl_autoload_register(array($this, 'loader'));

		// Checks if premium is installed along with plugins needed.
		add_action('plugins_loaded', array($this, 'plugins_loaded'), 1);
		
		register_activation_hook(__FILE__, array('WPO_Activation', 'actions'));
		register_deactivation_hook(__FILE__, array('WPO_Deactivation', 'actions'));
		register_uninstall_hook(__FILE__, array('WPO_Uninstall', 'actions'));
		
		$this->load_admin();
		add_action('admin_init', array($this, 'admin_init'));
		add_action('admin_bar_menu', array($this, 'cache_admin_bar'), 100, 1);

		add_action('init', array($this, 'schedule_plugin_cron_tasks'));

		add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'plugin_settings_link'));
		add_action('wpo_cron_event2', array($this, 'cron_action'));
		add_filter('cron_schedules', array($this, 'cron_schedules'));

		if (!$this->get_options()->get_option('installed-for', false)) $this->get_options()->update_option('installed-for', time());

		if (!self::is_premium()) {
			add_action('auto_option_settings', array($this->get_options(), 'auto_option_settings'));
		}

		add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));

		add_action('wp_enqueue_scripts', array($this, 'frontend_enqueue_scripts'));
		if ($this->get_options()->get_option('404_detector', 0)) {
			WP_Optimize_Performance::get_instance($this->get_404_detector())->hook_404_handler();
		}

		$this->load_ajax_handler();
		WP_Optimize_Heartbeat::get_instance();

		// Show update to Premium notice for non-premium multisite.
		add_action('wpo_additional_options', array($this, 'show_multisite_update_to_premium_notice'));

		// Action column (show repair button if need).
		add_filter('wpo_tables_list_additional_column_data', array($this, 'tables_list_additional_column_data'), 15, 2);

		/**
		 * Add action for display Images > Compress images tab.
		 */
		add_action('wp_optimize_admin_page_wpo_images_smush', array($this, 'admin_page_wpo_images_smush'));

		include_once(WPO_PLUGIN_MAIN_PATH.'includes/updraftcentral.php');

		include_once(WPO_PLUGIN_MAIN_PATH.'includes/backward-compatibility-functions.php');
				
		register_shutdown_function(array($this, 'log_fatal_errors'));

		add_action('wpo_admin_before_closing_wrap', array($this, 'load_modal_template'), 20);

		add_action('upgrader_process_complete', array($this, 'detect_active_plugins_and_themes_updates'), 10, 2);

		$import_done_hooks = array(
			'import_end', // wordpress importer
			'pmxi_after_xml_import', // wp all import
		);

		$db_update_hooks = apply_filters('wp_optimize_db_update_hooks', $import_done_hooks);

		foreach ($db_update_hooks as $hook) {
			add_action($hook, array($this, 'maybe_schedule_update_record_count_event'));
		}
		add_action('wpo_update_record_count_event', array($this->get_db_info(), 'wpo_update_record_count'));

	}

	/**
	 * Check if minimum requirements for WP-Optimize is met or not.
	 *
	 * @return bool
	 */
	public function is_minimum_requirement_met() {
		return (version_compare(WPO_REQUIRED_PHP_VERSION, PHP_VERSION, '<='));
	}

	/**
	 * Add admin notice about minimum server requirements.
	 */
	public function add_notice_minimum_requirements_not_met() {
		add_action('admin_notices', array($this, 'output_php_version_notice'));
	}

	/**
	 * Deactivate the plugin programmatically
	 */
	public function deactivate_plugin() {
		if (!function_exists('deactivate_plugins')) {
			require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
		}
		deactivate_plugins(plugin_basename(__FILE__));
	}

	/**
	 * Die after stating minimum requirements
	 */
	public function die_minimum_requirement_not_met() {
		$message = $this->get_php_version_notice_message();
		$message .= ' <a href="'.esc_attr(admin_url('plugins.php')).'">'.esc_html__('Back to Plugins.', 'wp-optimize').'</a>';
		wp_die($message);
	}

	/**
	 * Auto-loads classes.
	 *
	 * @param string $class_name The name of the class.
	 */
	private function loader($class_name) {
		$dirs = $this->get_class_directories();

		foreach ($dirs as $dir) {
			$class_file = WPO_PLUGIN_MAIN_PATH . trailingslashit($dir) . 'class-' . str_replace('_', '-', strtolower($class_name)) . '.php';
			if (file_exists($class_file)) {
				require_once($class_file);
				return;
			}

			$interface_file = WPO_PLUGIN_MAIN_PATH . trailingslashit($dir) . 'interface-' . str_replace('_', '-', strtolower($class_name)) . '.php';
			if (file_exists($interface_file)) {
				require_once($interface_file);
				return;
			}
		}

		// Include PHP Minify - https://github.com/matthiasmullie/minify
		if (strpos($class_name, 'MatthiasMullie') !== false) {
			$class_name_parts = explode('\\', $class_name);
			$class_file = WPO_PLUGIN_MAIN_PATH.'vendor/'.strtolower($class_name_parts[0]).'/'.strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $class_name_parts[1])).'/src/'.implode('/', array_slice($class_name_parts, 2)).'.php';
			if (file_exists($class_file)) {
				require_once($class_file);
				return;
			}
		}
		
		if ('Minify_HTML' == $class_name) {
			require_once WPO_PLUGIN_MAIN_PATH.'vendor/mrclay/minify/lib/Minify/HTML.php';
			return;
		}
	}

	/**
	 * Returns an array of class directories
	 *
	 * @return array
	 */
	private function get_class_directories() {
		return array(
			'cache',
			'compatibility',
			'includes',
			'includes/tables',
			'includes/list-tables',
			'minify',
			'optimizations',
			'webp',
		);
	}

	/**
	 * Initialize Admin class to load admin UI
	 */
	private function load_admin() {
		$this->get_admin_instance();
	}

	/**
	 * Returns Admin class instance
	 *
	 * @return WP_Optimize_Admin
	 */
	public function get_admin_instance() {
		return WP_Optimize_Admin::instance();
	}
	
	/**
	 * Detect when an active plugin or theme is updated, and trigger an action
	 *
	 * @param object $upgrader_object
	 * @param array  $options
	 * @return void
	 */
	public function detect_active_plugins_and_themes_updates($upgrader_object, $options) {
		if (empty($options) || !isset($options['type'])) return;
		
		$should_purge_cache = false;
		$skin = $upgrader_object->skin;
		if ('plugin' === $options['type']) {
			// A plugin is updated using the default update system (upgrader_overwrote_package is used for the upload method)
			if (property_exists($skin, 'plugin_active') && $skin->plugin_active) {
				$should_purge_cache = true;
			}
		} elseif ('theme' === $options['type']) {
			$active_theme = get_stylesheet();
			$parent_theme = get_template();
			// A theme is updated using the upload system
			if (isset($options['action']) && 'install' === $options['action'] && isset($skin->options['overwrite']) && 'update-theme' === $skin->options['overwrite']) {
				$updated_theme = $upgrader_object->result['destination_name'];
				// Check if the theme is in use
				if ($active_theme == $updated_theme || $parent_theme == $updated_theme) {
					$should_purge_cache = true;
				}
			// A theme is updated using the classic update system
			} elseif (isset($options['action']) && 'update' === $options['action'] && isset($options['themes']) && is_array($options['themes'])) {
				// Check if the theme is in use
				if (in_array($active_theme, $options['themes']) || in_array($parent_theme, $options['themes'])) {
					$should_purge_cache = true;
				}
			}
		}

		/**
		 * Action executed when an active theme or plugin was updated
		 */
		if ($should_purge_cache) do_action('wpo_active_plugin_or_theme_updated');

	}

	/**
	 * Sets a flag to indicate an import action is done, if needed
	 */
	public function maybe_schedule_update_record_count_event() {
		if (!wp_next_scheduled('wpo_update_record_count_event')) {
			wp_schedule_single_event(time() + 60, 'wpo_update_record_count_event');
		}
	}
			
	public function admin_page_wpo_images_smush() {
		$options = Updraft_Smush_Manager()->get_smush_options();
		$custom = 90 >= $options['image_quality'] && 65 <= $options['image_quality'];
		$sites = WP_Optimize()->get_sites();
		$this->include_template('images/smush.php', false, array('smush_options' => $options, 'custom' => $custom, 'sites' => $sites, 'does_server_allows_local_webp_conversion' => $this->does_server_allows_local_webp_conversion()));
		$this->include_template('images/smush-popup.php');
	}

	public static function instance() {
		if (empty(self::$_instance)) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	public function get_optimizer() {
		return WP_Optimizer::instance();
	}

	/**
	 * Adds 3rd party plugin compatibilities.
	 */
	public function load_compatibilities() {
		WPO_Polylang_Compatibility::instance();
		WPO_Page_Builder_Compatibility::instance();
		WPO_Custom_Permalink_Compatibility::instance();
		WPO_TranslatePress_Compatibility::instance();

		do_action('wpo_load_compatibilities');
	}

	/**
	 * Get and instantiate WP_Optimize_Minify
	 *
	 * @return WP_Optimize_Minify
	 */
	public function get_minify() {
		return WP_Optimize_Minify::instance();
	}

	public function get_options() {
		return WP_Optimize_Options::instance();
	}

	public function get_notices() {
		return WP_Optimize_Notices::instance();
	}

	/**
	 * Returns instance if WPO_Page_Cache class.
	 *
	 * @return WPO_Page_Cache
	 */
	public function get_page_cache() {
		return WPO_Page_Cache::instance();
	}

	/**
	 * Returns instance if WP_Optimize_WebP class.
	 *
	 * @return WP_Optimize_WebP
	 */
	public function get_webp_instance() {
		return WP_Optimize_WebP::get_instance();
	}

	/**
	 * Detects if the platform is Kinsta or not
	 *
	 * @return bool Returns true if it is Kinsta platform, otherwise returns false
	 */
	private function is_kinsta() {
		return isset($_SERVER['KINSTA_CACHE_ZONE']);
	}

	/**
	 * Detects whether the server handles cache. eg. Nginx cache
	 */
	public function does_server_handles_cache() {
		return $this->is_kinsta();
	}

	/**
	 * Detects whether the server supports table optimization.
	 *
	 * Some servers prevent table optimization
	 * because InnoDB engine does not optimize table
	 * instead it drops tables and recreate them
	 * which results in elevated disk write operations
	 */
	public function does_server_allows_table_optimization() {
		return !$this->is_kinsta();
	}

	/**
	 * Detects whether the server supports local webp conversion tools
	 */
	private function does_server_allows_local_webp_conversion() {
		return !$this->is_kinsta();
	}

	/**
	 * Create instance of WP_Optimize_Browser_Cache.
	 *
	 * @return WP_Optimize_Browser_Cache
	 */
	public function get_browser_cache() {
		return WP_Optimize_Browser_Cache::instance();
	}

	/**
	 * Returns WP_Optimize_Database_Information instance.
	 *
	 * @return WP_Optimize_Database_Information
	 */
	public function get_db_info() {
		return WP_Optimize_Database_Information::instance();
	}

	/**
	 * Returns instance of WP_Optimize_Gzip_Compression.
	 *
	 * @return WP_Optimize_Gzip_Compression
	 */
	public function get_gzip_compression() {
		return WP_Optimize_Gzip_Compression::instance();
	}

	/**
	 * Create instance of WP_Optimize_Htaccess.
	 *
	 * @param string $htaccess_file absolute path to htaccess file, by default it use .htaccess in WordPress root directory.
	 * @return WP_Optimize_Htaccess
	 */
	public static function get_htaccess($htaccess_file = '') {
		return new WP_Optimize_Htaccess($htaccess_file);
	}

	/**
	 * Return instance of Updraft_Logger
	 *
	 * @return Updraft_Logger
	 */
	public function get_logger() {
		return Updraft_Logger::instance();
	}

	/**
	 * Check if the current page belongs to WP-Optimize.
	 *
	 * @return bool
	 */
	public function is_wpo_page() {
		$current_screen = get_current_screen();

		return (bool) preg_match('/wp\-optimize/i', $current_screen->id);
	}

	/**
	 * Enqueue scripts and styles on WP-Optimize pages.
	 */
	public function admin_enqueue_scripts() {
		$enqueue_version = $this->get_enqueue_version();
		$min_or_not = $this->get_min_or_not_string();
		$min_or_not_internal = $this->get_min_or_not_internal_string();

		// Register or enqueue common scripts
		wp_register_script('wp-optimize-send-command', WPO_PLUGIN_URL.'js/send-command'.$min_or_not_internal.'.js', array(), $enqueue_version);
		wp_localize_script('wp-optimize-send-command', 'wp_optimize_send_command_data', array('nonce' => wp_create_nonce('wp-optimize-ajax-nonce')));
		wp_register_script('wp-optimize-block-ui', WPO_PLUGIN_URL.'js/blockUI'.$min_or_not_internal.'.js', array('jquery'), $enqueue_version);
		wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);

		// load scripts and styles only on WP-Optimize pages.
		if (!$this->is_wpo_page()) return;
				
		wp_enqueue_script('jquery-serialize-json', WPO_PLUGIN_URL.'js/serialize-json/jquery.serializejson'.$min_or_not.'.js', array('jquery'), $enqueue_version);

		wp_register_script('updraft-queue-js', WPO_PLUGIN_URL.'js/queue'.$min_or_not_internal.'.js', array(), $enqueue_version);

		wp_enqueue_script('wp-optimize-modal', WPO_PLUGIN_URL.'js/modal'.$min_or_not_internal.'.js', array('jquery', 'backbone', 'wp-util'), $enqueue_version);
		wp_enqueue_script('wp-optimize-cache-js', WPO_PLUGIN_URL.'js/cache'.$min_or_not_internal.'.js', array('wp-optimize-send-command', 'smush-js', 'wp-optimize-heartbeat-js', 'wp-optimize-block-ui'), $enqueue_version);
		wp_enqueue_script('wp-optimize-admin-js', WPO_PLUGIN_URL.'js/wpoadmin'.$min_or_not_internal.'.js', array('jquery', 'updraft-queue-js', 'wp-optimize-send-command', 'smush-js', 'wp-optimize-modal', 'wp-optimize-cache-js', 'wp-optimize-heartbeat-js'), $enqueue_version);
		wp_enqueue_style('wp-optimize-admin-css', WPO_PLUGIN_URL.'css/wp-optimize-admin'.$min_or_not_internal.'.css', array(), $enqueue_version);
		// Using tablesorter to help with organising the DB size on Table Information
		// https://github.com/Mottie/tablesorter
		wp_enqueue_script('tablesorter-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter'.$min_or_not.'.js', array('jquery', 'wp-optimize-send-command'), $enqueue_version);

		wp_enqueue_script('tablesorter-widgets-js', WPO_PLUGIN_URL.'js/tablesorter/jquery.tablesorter.widgets'.$min_or_not.'.js', array('jquery'), $enqueue_version);

		// wp_enqueue_style('tablesorter-css', WPO_PLUGIN_URL.'css/tablesorter/theme.default.min.css', array(), $enqueue_version);

		$js_variables = $this->wpo_js_translations();
		$js_variables['loggers_classes_info'] = $this->get_loggers_classes_info();
		wp_localize_script('wp-optimize-admin-js', 'wpoptimize', $js_variables);
		
		do_action('wpo_premium_scripts_styles', $min_or_not_internal, $min_or_not, $enqueue_version);

		wp_enqueue_script('wp-optimize-status-report', WPO_PLUGIN_URL.'js/status'.$min_or_not_internal.'.js', array('wp-api-fetch', 'wp-optimize-admin-js'), $enqueue_version);

		wp_enqueue_script('js-zip', WPO_PLUGIN_URL.'/js/jszip/jszip' . $min_or_not . '.js', array(), $enqueue_version);
	}

	/**
	 * Enqueue any required front-end scripts
	 *
	 * @return void
	 */
	public function frontend_enqueue_scripts() {
		if (!current_user_can('manage_options') || !is_admin_bar_showing()) return;
		$enqueue_version = $this->get_enqueue_version();
		$min_or_not_internal = WP_Optimize()->get_min_or_not_internal_string();

		// Register or enqueue common scripts
		wp_enqueue_style('wp-optimize-global', WPO_PLUGIN_URL.'css/wp-optimize-global'.$min_or_not_internal.'.css', array(), $enqueue_version);
	}

	/**
	 * Load Task Manager
	 */
	public function get_task_manager() {
		include_once(WPO_PLUGIN_MAIN_PATH.'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-tasks-activation.php');

		Updraft_Tasks_Activation::check_updates();

		include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-meta.php');
		include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-options.php');
		include_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
				
		include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-smush-task.php');
		include_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-smush-manager.php');

		return Updraft_Smush_Manager();
	}

	/**
	 * Indicate whether we have an associated instance of WP-Optimize Premium or not.
	 *
	 * @returns Boolean
	 */
	public static function is_premium() {
		if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && function_exists('WP_Optimize_Premium')) {
			$wp_optimize_premium = WP_Optimize_Premium();
			if (is_a($wp_optimize_premium, 'WP_Optimize_Premium')) return true;
		}
		return false;
	}

	/**
	 * 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.
	 *
	 * @return bool
	 */
	public function is_apache_server() {
		global $is_apache;
		return $is_apache;
	}

	/**
	 * Check if script running on IIS web server.
	 *
	 * @return bool
	 */
	public function is_IIS_server() {
		global $is_IIS, $is_iis7;
		return $is_IIS || $is_iis7;
	}

	/**
	 * Check if Apache module or modules active.
	 *
	 * @param string|array $module - single Apache module name or list of Apache module names.
	 *
	 * @return bool|null - if null, the result was indeterminate
	 */
	public function is_apache_module_loaded($module) {
		if (!$this->is_apache_server()) return false;
				
		if (!function_exists('apache_get_modules')) return null;

		$module_loaded = true;

		if (is_array($module)) {
			foreach ($module as $single_module) {
				if (!in_array($single_module, apache_get_modules())) {
					$module_loaded = false;
					break;
				}
			}
		} else {
			$module_loaded = in_array($module, apache_get_modules());
		}

		return $module_loaded;
	}

	/**
	 * 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.
	 */
	public function plugins_loaded() {

		if (!$this->is_minimum_requirement_met()) {
			$this->add_notice_minimum_requirements_not_met();
			$this->deactivate_plugin();
			WPO_Deactivation::actions();
			return;
		}

		if ($this->does_server_handles_cache()) {
			add_filter('wp_optimize_admin_page_wpo_cache_tabs', array($this, 'filter_cache_tabs'), 99, 1);

			// If newly migrated to server that handles cache, disable wpo cache
			$cache = $this->get_page_cache();
			if ($cache->is_enabled()) {
				$cache->disable();
			}
		}

		add_filter('robots_txt', array($this, 'robots_txt'), 99, 1);

		// Run Premium loader if it exists
		if (file_exists(WPO_PLUGIN_MAIN_PATH.'premium.php') && !class_exists('WP_Optimize_Premium')) {
			include_once(WPO_PLUGIN_MAIN_PATH.'premium.php');
		}

		// load defaults
		WP_Optimize()->get_options()->set_default_options();

		// Initialize loggers.
		$this->setup_loggers();

		if ($this->is_active('premium') && false !== ($free_plugin = $this->is_active('free'))) {
			if (!function_exists('deactivate_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
			deactivate_plugins($free_plugin);

			// If WPO_ADVANCED_CACHE is defined, we empty advanced-cache.php to regenerate later. Otherwise it contains the path to free.
			if (defined('WPO_ADVANCED_CACHE') && WPO_ADVANCED_CACHE) {
				$advanced_cache_filename = trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';

				if (!is_file($advanced_cache_filename) && is_writable(dirname($advanced_cache_filename)) || (is_file($advanced_cache_filename) && is_writable($advanced_cache_filename))) {
					file_put_contents($advanced_cache_filename, '');
				}
			}

					// Registers the notice letting the user know it cannot be active if premium is active.
			add_action('admin_notices', array($this, 'show_admin_notice_premium'));
			return;
		}

		// Loads the task manager
		$this->get_task_manager();

		add_action('init', array($this, 'load_language_file'), 0);

		// Load 3rd party plugin compatibilities.
		$this->load_compatibilities();

		// Load page cache.
		$this->get_page_cache();
		// We use the init hook to avoid the _load_textdomain_just_in_time warning,
		// which is triggered because we use translations during cache initialization
		add_action('init', array($this, 'init_page_cache'), 1);

		// Include minify
		$this->get_minify();
		$this->run_updates();

		// We need this here because webp can be unavailable because of server moves
		// This deletes already converted webp images and original image file when a media is deleted
		WP_Optimize_WebP_Images::get_instance();

		// Include WebP
		if (WPO_USE_WEBP_CONVERSION) {
			$this->get_webp_instance();
		}

		// add_filter('updraftcentral_host_plugins', array($this, 'attach_updraftcentral_host'));
		// if (file_exists(WPO_PLUGIN_MAIN_PATH.'central/factory.php')) include_once(WPO_PLUGIN_MAIN_PATH.'central/factory.php');
	}

	/**
	 * Loads the language file.
	 *
	 * @return void
	 */
	public function load_language_file() {
		load_plugin_textdomain('wp-optimize', false, dirname(plugin_basename(__FILE__)) . '/languages');
	}

	/**
	 * Attach this wp-optimize plugin as host of the UpdraftCentral libraries
	 * (e.g. "central" folder)
	 *
	 * @param array $hosts List of plugins having the "central" library integrated into them
	 *
	 * @return array
	 */
	public function attach_updraftcentral_host($hosts) {
		$hosts[] = 'wp-optimize';
		return $hosts;
	}

	/**
	 * Filter cache tabs (when it is Kinsta)
	 *
	 * @param  array $tabs An array of tabs
	 *
	 * @return array $tabs An array of tabs
	 */
	public function filter_cache_tabs($tabs) {
		unset($tabs['preload']);
		unset($tabs['advanced']);
		unset($tabs['gzip']);
		unset($tabs['settings']);
		return $tabs;
	}

	/**
	 * Check whether one of free/Premium is active (whether it is this instance or not)
	 *
	 * @param String $which - 'free' or 'premium'
	 *
	 * @return String|Boolean - plugin path (if installed) or false if not
	 */
	private function is_active($which = 'free') {
		$active_plugins = $this->get_active_plugins();
		foreach ($active_plugins as $file) {
			if ('wp-optimize.php' == basename($file)) {
				$plugin_dir = WP_PLUGIN_DIR.'/'.dirname($file);
				if (('free' == $which && !file_exists($plugin_dir.'/premium.php')) || ('free' != $which && file_exists($plugin_dir.'/premium.php'))) return $file;
			}
		}
		return false;
	}

	/**
	 * Gets an array of plugins active on either the current site, or site-wide
	 *
	 * @return Array - a list of plugin paths (relative to the plugin directory)
	 */
	private function get_active_plugins() {

		// Gets all active plugins on the current site
		$active_plugins = get_option('active_plugins');

		if (is_multisite()) {
			$network_active_plugins = get_site_option('active_sitewide_plugins');
			if (!empty($network_active_plugins)) {
				$network_active_plugins = array_keys($network_active_plugins);
				$active_plugins = array_merge($active_plugins, $network_active_plugins);
			}
		}

		return $active_plugins;
	}

	/**
	 * This function checks whether a specific plugin is installed, and returns information about it
	 *
	 * @param  string $name Specify "Plugin Name" to return details about it.
	 * @return array        Returns an array of details such as if installed, the name of the plugin and if it is active.
	 */
	public function is_installed($name) {

		// Needed to have the 'get_plugins()' function
		include_once(ABSPATH.'wp-admin/includes/plugin.php');

		// Gets all plugins available
		$get_plugins = get_plugins();

		$active_plugins = $this->get_active_plugins();

		$plugin_info = array();
		$plugin_info['installed'] = false;
		$plugin_info['active'] = false;

		// Loops around each plugin available.
		foreach ($get_plugins as $key => $value) {
			// If the plugin name matches that of the specified name, it will gather details.
			if ($value['Name'] != $name && $value['TextDomain'] != $name) continue;
			$plugin_info['installed'] = true;
			$plugin_info['name'] = $key;
			$plugin_info['version'] = $value['Version'];
			if (in_array($key, $active_plugins)) {
				$plugin_info['active'] = true;
			}
			break;
		}
		return $plugin_info;
	}

	/**
	 * This is a notice to show users that premium is installed
	 */
	public function show_admin_notice_premium() {
		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>';
		if (isset($_GET['activate'])) unset($_GET['activate']);
	}

	/**
	 * Show update to Premium notice for non-premium multisite.
	 */
	public function show_multisite_update_to_premium_notice() {
		if (!is_multisite() || self::is_premium()) return;

		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>';
	}

	public function admin_init() {
		$pagenow = $GLOBALS['pagenow'];

		$this->register_template_directories();

		if (('index.php' == $pagenow && current_user_can('update_plugins')) || ('index.php' == $pagenow && defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
			$options = $this->get_options();

			$dismissed_until = $options->get_option('dismiss_dash_notice_until', 0);

			if (file_exists(WPO_PLUGIN_MAIN_PATH . 'index.html')) {
				$installed = filemtime(WPO_PLUGIN_MAIN_PATH . 'index.html');
				$installed_for = (time() - $installed);
			}

			if (($installed && time() > $dismissed_until && $installed_for > (14 * 86400) && !defined('WP_OPTIMIZE_NOADS_B')) || (defined('WP_OPTIMIZE_FORCE_DASHNOTICE') && WP_OPTIMIZE_FORCE_DASHNOTICE)) {
				add_action('all_admin_notices', array($this, 'show_admin_notice_upgraded'));
			}
		}

		if ($this->is_wp_smush_installed()) {
			add_filter('transient_wp-smush-conflict_check', array($this, 'modify_wp_smush_conflict_check'), 9, 1);
		}
		if ($this->get_options()->get_option('404_detector', 0)) {
			WP_Optimize_Performance::get_instance($this->get_404_detector())->init();
		}
	}

	/**
	 * Checks whether the WP Smush plugin is active or not
	 *
	 * @return bool
	 */
	private function is_wp_smush_installed() {
		return is_plugin_active('wp-smushit/wp-smush.php');
	}

	/**
	 * Remove WPO plugin name from WP Smushit transient value
	 *
	 * @return array $active_plugins
	 */
	public function modify_wp_smush_conflict_check($active_plugins) {
		// This can be boolean value since it is return value of get_transient
		if (!is_array($active_plugins)) return $active_plugins;

		if (false !== ($key = array_search('WP-Optimize - Clean, Compress, Cache', $active_plugins))) {
			unset($active_plugins[$key]);
		}
		return $active_plugins;
	}

	/**
	 * Get the install or update notice instance
	 *
	 * @return WP_Optimize_Install_Or_Update_Notice
	 */
	public function get_install_or_update_notice() {
		static $instance = null;
		if (is_a($instance, 'WP_Optimize_Install_Or_Update_Notice')) return $instance;
		$instance = new WP_Optimize_Install_Or_Update_Notice();
		return $instance;
	}

	/**
	 * Display an admin notice for an upgraded version.
	 */
	public function show_admin_notice_upgraded() {
		$this->include_template('notices/thanks-for-using-main-dash.php', false, array(
			'is_premium' => WP_Optimize::is_premium()
		));
	}
			
	public function capability_required() {
		return apply_filters('wp_optimize_capability_required', 'manage_options');
	}

	/**
	 * Returns array of translations used in javascript code.
	 *
	 * @return array
	 */
	public function wpo_js_translations() {
		$log_message = __('For more details, please check your logs configured in logging destinations settings.', 'wp-optimize');
		return apply_filters('wpo_js_translations', array(
			'automatic_backup_before_optimizations' => __('Automatic backup before optimizations', 'wp-optimize'),
			'error_unexpected_response' => __('An unexpected response was received.', 'wp-optimize'),
			'optimization_complete' => __('Optimization complete', 'wp-optimize'),
			'with_warnings' => __('(with warnings - open the browser console for more details)', 'wp-optimize'),
			'optimizing_table' => __('Optimizing table:', 'wp-optimize'),
			'run_optimizations' => __('Run optimizations', 'wp-optimize'),
			'table_optimization_timeout' => 120000,
			'add' => __('Add', 'wp-optimize'),
			'cancel' => __('Cancel', 'wp-optimize'),
			'cancelling' => __('Cancelling...', 'wp-optimize'),
			'enable' => __('Enable', 'wp-optimize'),
			'disable' => __('Disable', 'wp-optimize'),
			'please_select_settings_file' => __('Please, select settings file.', 'wp-optimize'),
			'are_you_sure_you_want_to_remove_logging_destination' => __('Are you sure you want to remove this logging destination?', 'wp-optimize'),
			'fill_all_settings_fields' => __('Before saving, you need to complete the currently incomplete settings (or remove them).', 'wp-optimize'),
			'table_was_not_repaired' => __('%s was not repaired.', 'wp-optimize') . ' ' . $log_message,
			'table_was_not_deleted' => __('%s was not deleted.', 'wp-optimize') . ' ' . $log_message,
			'table_was_not_converted' => __('%s was not converted to InnoDB.', 'wp-optimize') . ' ' . $log_message,
			'please_use_positive_integers' => __('Please use positive integers.', 'wp-optimize'),
			'please_use_valid_values' => __('Please use valid values.', 'wp-optimize'),
			'update' => __('Update', 'wp-optimize'),
			'run_now' => __('Run now', 'wp-optimize'),
			'starting_preload' => __('Started preload...', 'wp-optimize'),
			'loading_urls' => __('Loading URLs...', 'wp-optimize'),
			'current_cache_size' => __('Current cache size:', 'wp-optimize'),
			'number_of_files' => __('Number of files:', 'wp-optimize'),
			'toggle_info' => __('Show information', 'wp-optimize'),
			'delete_file' => __('Delete', 'wp-optimize'),
			'deleting' => __('Deleting...', 'wp-optimize'),
			'added_to_list' => __('Added to the list', 'wp-optimize'),
			'added_notice' => __('The file was added to the list', 'wp-optimize'),
			'save_notice' => __('Save the changes', 'wp-optimize'),
			'saving' => __('Saving...', 'wp-optimize'),
			'clearing_cache' => __('Clearing cache...', 'wp-optimize'),
			'creating_cache' => __('Creating cache...', 'wp-optimize'),
			'page_refresh' => __('Refreshing the page to reflect changes...', 'wp-optimize'),
			'cache_file_not_found' => __('Cache file was not found.', 'wp-optimize'),
			'settings_have_been_deleted_successfully' => __('WP-Optimize settings have been deleted successfully.', 'wp-optimize'),
			'loading_data' => __('Loading data...', 'wp-optimize'),
			'spinner_src' => esc_url(admin_url('images/spinner-2x.gif')),
			'logo_src' => esc_url(WPO_PLUGIN_URL.'images/notices/wp_optimize_logo.png'),
			'settings_page_url' => is_multisite() ? network_admin_url('admin.php?page=wpo_settings') : admin_url('admin.php?page=wpo_settings'),
			'sites' => $this->get_sites(),
			'user_always_ignores_table_deletion_warning' => (get_user_meta(get_current_user_id(), 'wpo-ignores-table-deletion-warning', true)) ? true : false,
			'user_always_ignores_post_meta_deletion_warning' => (get_user_meta(get_current_user_id(), 'wpo-ignores-post-meta-deletion-warning', true)) ? true : false,
			'user_always_ignores_orphaned_relationship_data_deletion_warning' => (get_user_meta(get_current_user_id(), 'wpo-ignores-orphaned-relationship-data-deletion-warning', true)) ? true : false,
			'post_meta_tweak_completed' => __('The tweak has been performed.', 'wp-optimize'),
			'no_minified_assets' => __('No minified files are present', 'wp-optimize'),
			'network_site_url' => network_site_url(),
			'export_settings_file_name' => 'wpoptimize-settings-'.sanitize_title(get_bloginfo('name')).'.json',
			'import_select_file' => __('You have not yet selected a file to import.', 'wp-optimize'),
			'import_invalid_json_file' => __('Error: The chosen file is corrupt.', 'wp-optimize') . ' ' . __('Please choose a valid WP-Optimize export file.', 'wp-optimize'),
			'importing' => __('Importing...', 'wp-optimize'),
			'importing_data_from' => __('This will import data from:', 'wp-optimize'),
			'exported_on' => __('Which was exported on:', 'wp-optimize'),
			'continue_import' => __('Do you want to carry out the import?', 'wp-optimize'),
			'select_destination' => __('Select destination', 'wp-optimize'),
			'show' => __('Show', 'wp-optimize'),
			'hide' => __('Hide', 'wp-optimize'),
			'please_wait' => __('Please wait a moment...', 'wp-optimize'),
			'clipboard_failed' => __('Copy to clipboard failed, please do it manually', 'wp-optimize'),
			'clipboard_success' => __('System status has been copied to the clipboard', 'wp-optimize'),
			'show_information' => __('Show information', 'wp-optimize'),
			'hide_information' => __('Hide information', 'wp-optimize'),
			'data_not_available' => __('Not available', 'wp-optimize')
		));
	}

	/**
	 * Manages the admin bar menu for caching (currently page and minify)
	 */
	public function cache_admin_bar($wp_admin_bar) {

		$options = $this->get_options();
		if (!$options->get_option('enable_cache_in_admin_bar', true)) return;

		/**
		 * The "purge cache" menu items
		 *
		 * @param array  $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
		 * @param object $wp_admin_bar
		 */
		$menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);

		if (empty($menu_items) || !is_array($menu_items)) return;

		$wp_admin_bar->add_menu(array(
			'id'    => 'wpo_purge_cache',
			'title' => __('Purge cache', 'wp-optimize'),
			'href'  => '#',
			'meta'  => array(
				'title' => __('Purge cache', 'wp-optimize'),
			),
			'parent' => false,
		));

		foreach ($menu_items as $item) {
			$wp_admin_bar->add_menu($item);
		}
	}

	/**
	 * Add settings link on plugin page
	 *
	 * @param  string $links Passing through the URL to be used within the HREF.
	 * @return string        Returns the Links.
	 */
	public function plugin_settings_link($links) {

		$admin_page_url = $this->get_options()->admin_page_url();
		$settings_page_url = $this->get_options()->admin_page_url('wpo_settings');

		if (false == self::is_premium()) {
			$premium_link = '<a href="' . esc_url($this->premium_version_link) . '" target="_blank">' . __('Premium', 'wp-optimize') . '</a>';
			array_unshift($links, $premium_link);
		}

		$settings_link = '<a href="' . esc_url($settings_page_url) . '">' . __('Settings', 'wp-optimize') . '</a>';
		array_unshift($links, $settings_link);

		$optimize_link = '<a href="' . esc_url($admin_page_url) . '">' . __('Optimize', 'wp-optimize') . '</a>';
		array_unshift($links, $optimize_link);
		return $links;
	}

	/**
	 * Action wpo_tables_list_additional_column_data. Output button Optimize in the action column.
	 *
	 * @param string $content    String for output to column
	 * @param object $table_info Object with table info.
	 *
	 * @return string
	 */
	public function tables_list_additional_column_data($content, $table_info) {
		if ($table_info->is_needing_repair) {
			$content .= '<div class="wpo_button_wrap">'
				. '<button class="button button-secondary run-single-table-repair" data-table="' . esc_attr($table_info->Name) . '">' . __('Repair', 'wp-optimize') . '</button>'
				. '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
				. '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
				. '</div>';
		}

		// table belongs to plugin.
		if ($table_info->can_be_removed) {
			$content .= '<div>'
				. '<button class="button button-secondary run-single-table-delete" data-table="' . esc_attr($table_info->Name) . '">' . __('Remove', 'wp-optimize') . '</button>'
				. '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
				. '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
				. '</div>';
		}

		// Add option for MyISAM to InnoDB conversion.
		if ('MyISAM' == $table_info->Engine) {
			$content .= '<div class="wpo_button_convert wpo_button_wrap">'
				. '<button class="button button-secondary toinnodb" data-table="' . esc_attr($table_info->Name) . '">' . __('Convert to InnoDB', 'wp-optimize') . '</button>'
				. '<img class="optimization_spinner visibility-hidden" src="' . esc_attr(admin_url('images/spinner-2x.gif')) . '" width="20" height="20" alt="...">'
				. '<span class="optimization_done_icon dashicons dashicons-yes visibility-hidden"></span>'
				. '</div>';
						
		}
				
		return $content;
	}

	/**
	 * Initialize WP-Optimize page cache.
	 */
	public function init_page_cache() {
		if ($this->get_page_cache()->config->get_option('enable_page_caching', false)) {
			if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
				$this->_cache_init_status = $this->get_page_cache()->enable();
			}
		}
	}

	/**
	 * Get init_page_cache() status.
	 *
	 * @return bool
	 */
	public function get_init_page_cache_status() {
		return $this->_cache_init_status;
	}

	/**
	 * Schedules cron event based on selected schedule type
	 *
	 * @return void
	 */
	public function cron_activate() {
		$gmt_offset = (int) (3600 * get_option('gmt_offset'));

		$options = $this->get_options();

		if ($options->get_option('schedule') === false) {
			$options->set_default_options();
		} else {
			if ('true' == $options->get_option('schedule')) {
				if (!wp_next_scheduled('wpo_cron_event2')) {
					$schedule_type = $options->get_option('schedule-type', 'wpo_weekly');

					// Backward compatibility
					if ('wpo_otherweekly' == $schedule_type) $schedule_type = 'wpo_fortnightly';

					$this_time = (86400 * 7);

					switch ($schedule_type) {
						case "wpo_daily":
							$this_time = 86400;
							break;

						case "wpo_weekly":
							$this_time = (86400 * 7);
							break;

						case "wpo_fortnightly":
							$this_time = (86400 * 14);
							break;

						case "wpo_monthly":
							$this_time = (86400 * 30);
							break;
					}

					add_action('wpo_cron_event2', array($this, 'cron_action'));
					$result = wp_schedule_event((current_time("timestamp", 0) + $this_time - $gmt_offset), $schedule_type, 'wpo_cron_event2');
					WP_Optimize()->log('running wp_schedule_event()');
					if (is_wp_error($result)) {
						$error_msg = $result->get_error_message();
						WP_Optimize()->log($error_msg);
						WP_Optimize()->log(print_r($result, true));
					} else {
						WP_Optimize()->log($result);
					}
				}
			}
		}
	}

	/**
	 * Clears all cron events
	 *
	 * @return void
	 */
	public function wpo_cron_deactivate() {
		$cron_jobs = _get_cron_array();
		foreach ($cron_jobs as $job) {
			foreach (array_keys($job) as $hook) {
				if (preg_match('/^wpo_/', $hook)) wp_unschedule_hook($hook);
			}
		}
	}

	/**
	 * Scheduler public functions to update schedulers
	 *
	 * @param  array $schedules An array of schedules being passed.
	 * @return array            An array of schedules being returned.
	 */
	public function cron_schedules($schedules) {
		$schedules['wpo_daily'] = array('interval' => 86400, 'display' => 'Once Daily');
		$schedules['wpo_weekly'] = array('interval' => 86400 * 7, 'display' => 'Once Weekly');
		$schedules['wpo_fortnightly'] = array('interval' => 86400 * 14, 'display' => 'Once Every Fortnight');
		$schedules['wpo_monthly'] = array('interval' => 86400 * 30, 'display' => 'Once Every Month');
		return $schedules;
	}

	/**
	 * Returns count of overdue cron jobs.
	 *
	 * @return integer
	 */
	public function howmany_overdue_crons() {
		$how_many_overdue = 0;
		if (function_exists('_get_cron_array') || (is_file(ABSPATH.WPINC.'/cron.php') && include_once(ABSPATH.WPINC.'/cron.php') && function_exists('_get_cron_array'))) {
			$crons = _get_cron_array();
			if (is_array($crons)) {
				$timenow = time();
				foreach ($crons as $jt => $job) {
					if ($jt < $timenow) {
						$how_many_overdue++;
					}
				}
			}
		}
		return $how_many_overdue;
	}

	/**
	 * Run updates on plugin activation.
	 */
	public function run_updates() {
		include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimize-updates.php');
		WP_Optimize_Updates::check_updates();
	}

	/**
	 * Returns warning about overdue crons.
	 *
	 * @param int $howmany count of overdue crons
	 * @return string
	 */
	public function show_admin_warning_overdue_crons($howmany) {
		$ret = '<div class="updated below-h2"><p>';
		$ret .= '<strong>'.__('Warning', 'wp-optimize').':</strong> '.sprintf(__('WordPress has a number (%d) of scheduled tasks which are overdue.', 'wp-optimize'), $howmany).' '. __('Unless this is a development site, this probably means that the scheduler in your WordPress install is not working.', 'wp-optimize').' <a target="_blank" 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>';
		$ret .= '</p></div>';
		return $ret;
	}

	private function wp_normalize_path($path) {
		// Wp_normalize_path is not present before WP 3.9.
		if (function_exists('wp_normalize_path')) return wp_normalize_path($path);
		// Taken from WP 4.6.
		$path = str_replace('\\', '/', $path);
		$path = preg_replace('|(?<=.)/+|', '/', $path);
		if (':' === substr($path, 1, 1)) {
			$path = ucfirst($path);
		}
		return $path;
	}

	public function get_templates_dir() {
		return apply_filters('wp_optimize_templates_dir', $this->wp_normalize_path(WPO_PLUGIN_MAIN_PATH.'templates'));
	}

	public function get_templates_url() {
		return apply_filters('wp_optimize_templates_url', WPO_PLUGIN_URL.'templates');
	}

	/**
	 * Return or output view content
	 *
	 * @param String  $path                   - path to template, usually relative to templates/ within the WP-O directory
	 * @param Boolean $return_instead_of_echo - what to do with the results
	 * @param Array	  $extract_these		  - key/value pairs for substitution into the scope of the template
	 *
	 * @return String|Void
	 */
	public function include_template($path, $return_instead_of_echo = false, $extract_these = array()) {
		if ($return_instead_of_echo) ob_start();

		if (preg_match('#^([^/]+)/(.*)$#', $path, $matches)) {
			$prefix = $matches[1];
			$suffix = $matches[2];
			if (isset($this->template_directories[$prefix])) {
				$template_file = $this->template_directories[$prefix].'/'.$suffix;
			}
		}

		if (!isset($template_file)) {
			$template_file = WPO_PLUGIN_MAIN_PATH.'templates/'.$path;
		}

		$template_file = apply_filters('wp_optimize_template', $template_file, $path);

		do_action('wp_optimize_before_template', $path, $template_file, $return_instead_of_echo, $extract_these);

		if (!file_exists($template_file)) {
			error_log("WP Optimize: template not found: ".$template_file);
			echo __('Error:', 'wp-optimize').' '.__('template not found', 'wp-optimize')." (".$path.")";
		} else {
				extract($extract_these);
				// The following are useful variables which can be used in the template.
				// They appear as unused, but may be used in the $template_file.
				$wpdb = $GLOBALS['wpdb'];// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wpdb might be used in the included template
				$wp_optimize = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wp_optimize might be used in the included template
				$optimizer = $this->get_optimizer();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $optimizer might be used in the included template
				$options = $this->get_options();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $options might be used in the included template
				$wp_optimize_notices = $this->get_notices();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $wp_optimize_notices might be used in the included template
				include $template_file;
		}

		do_action('wp_optimize_after_template', $path, $template_file, $return_instead_of_echo, $extract_these);

		if ($return_instead_of_echo) return ob_get_clean();
	}

	/**
	 * Build a list of template directories (stored in self::$template_directories)
	 */
	private function register_template_directories() {

		$template_directories = array();

		$templates_dir = $this->get_templates_dir();

		if ($dh = opendir($templates_dir)) {
			while (($file = readdir($dh)) !== false) {
				if ('.' == $file || '..' == $file) continue;
				if (is_dir($templates_dir.'/'.$file)) {
					$template_directories[$file] = $templates_dir.'/'.$file;
				}
			}
				closedir($dh);
		}

		// Optimal hook for most extensions to hook into.
		$this->template_directories = apply_filters('wp_optimize_template_directories', $template_directories);

	}

	/**
	 * Message to debug
	 *
	 * @param string $message Message to insert into the log.
	 * @param array  $context array with variables used in $message like in template,
	 * 						  for ex.
	 *						  $message = 'Hello {message}';
	 * 						  $context = ['message' => 'world']
	 * 						  'Hello world' string will be saved in log.
	 */
	public function log($message, $context = array()) {
		$this->get_logger()->debug($message, $context);
	}

	/**
	 * Format Bytes Into KB/MB
	 *
	 * @param  mixed   $bytes    Number of bytes to be converted.
	 * @param  integer $decimals the number of decimal digits
	 * @return integer        return the correct format size.
	 */
	public function format_size($bytes, $decimals = 2) {
		if (!is_numeric($bytes)) return __('N/A', 'wp-optimize');

		if (1073741824 <= $bytes) {
			$bytes = number_format($bytes / 1073741824, $decimals) . ' GB';
		} elseif (1048576 <= $bytes) {
			$bytes = number_format($bytes / 1048576, $decimals) . ' MB';
		} elseif (1024 <= $bytes) {
			$bytes = number_format($bytes / 1024, $decimals) . ' KB';
		} elseif (1 < $bytes) {
			$bytes = $bytes . ' bytes';
		} elseif (1 == $bytes) {
			$bytes = $bytes . ' byte';
		} else {
			$bytes = '0 bytes';
		}

		return $bytes;
	}

	/**
	 * Format a timestamp into a juman readable date time
	 *
	 * @param int	 $timestamp Epoch timestamp to convert
	 * @param string $separator String separator
	 * @return string
	 */
	public function format_date_time($timestamp, $separator = ' @ ') {
		return date_i18n(get_option('date_format'). $separator .get_option('time_format'), ($timestamp + get_option('gmt_offset') * 3600));
	}

	/**
	 * Executed this function on cron event.
	 *
	 * @return void
	 */
	public function cron_action() {

		$optimizer = $this->get_optimizer();
		$options = $this->get_options();

		$this->log('WPO: Starting cron_action()');
		$options->update_option('last-optimized', time());
		if ('true' == $options->get_option('schedule')) {
			$this_options = $options->get_option('auto');

			// Currently the output of the optimizations is not saved/used/logged.
			$optimizer->do_optimizations($this_options, 'auto');
		}

	}

	/**
	 * Schedule cron tasks used by plugin.
	 *
	 * @return void
	 */
	public function schedule_plugin_cron_tasks() {
		if (!wp_next_scheduled('wpo_weekly_cron_tasks')) {
			wp_schedule_event(current_time("timestamp", 0), 'weekly', 'wpo_weekly_cron_tasks');
		}

		add_action('wpo_weekly_cron_tasks', array($this, 'do_weekly_cron_tasks'));
		WP_Optimize_404_Detector_Cron::get_instance();
	}

	/**
	 * Do plugin background tasks.
	 *
	 * @return void
	 */
	public function do_weekly_cron_tasks() {
		// add tasks here.
		$this->get_db_info()->update_plugin_json();
	}

	/**
	 * This will customize a URL with a correct Affiliate link
	 * This function can be update to suit any URL as longs as the URL is passed
	 *
	 * @param String  $url					  - URL to be check to see if it an updraftplus match.
	 * @param String  $text					  - Text to be entered within the href a tags.
	 * @param String  $html					  - Any specific HTML to be added. Supplied parameter will not be escaped in this function. Provide escaped, safe HTML
	 * @param String|Array	$attrs                  - Specify the HTML attributes as an array or string. Use the array format for multiple attributes (e.g., array( "class" => "lorem-ipsum", "title" => "Highlighting text" )), and use the string format for a single attribute (e.g., 'class="lorem-ipsum"').
	 * @param Boolean	$return_instead_of_echo - if set, then the result will be returned, not echo-ed.
	 * @return String|void
	 */
	public function wp_optimize_url($url, $text = '', $html = '', $attrs = '', $return_instead_of_echo = false) {
		// Check if the URL is UpdraftPlus.
		$url = $this->maybe_add_affiliate_params($url);		// Return URL - check if there is HTML such as images.
		
		// Check if the variable $text is empty (null value included), otherwise assign $html.
		$content = empty($text) ? $html : esc_html($text);
		
		// Check if $attrs is an array to convert the attributes into a string line.
		$str_attrs = '';
		if (is_array($attrs)) {
			foreach ($attrs as $attr => $value) {
				$str_attrs .= $attr . '="' . esc_attr($value) . '" ';
			}
		} else {
			// If $attrs is empty, the explode function will only return an empty array.
			$attrs = explode('=', $attrs);
			// Check if $attrs in positions 1 and 2 are not empty and exist; otherwise, return an empty string.
			$str_attrs = !empty($attrs[0]) && !empty($attrs[1]) ? $attrs[0] . '="' . esc_attr(str_replace('"', '', $attrs[1])) . '"' : '';
		}
		
		// Check if it is necessary to add a target value if the url is external
		$is_external_url = $this->is_external_url($url);
		if ($is_external_url) {
			$str_attrs = preg_replace('/\s+target="_blank"/i', '', $str_attrs);
			$str_attrs .= ' target="_blank"';
		}
		
		$result = sprintf(
			'<a href="%s" %s>%s</a>',
			esc_url($url),
			$str_attrs,
			$content
		);

		if ($return_instead_of_echo) return $result;
		echo $result;
	}
	
	/**
	 * Check if a URL is external
	 *
	 * @param string $url
	 * @return string
	 */
	public function is_external_url($url) {
		if (empty($url)) {
			return false;
		}
		
		$current_domain = wp_parse_url(home_url(), PHP_URL_HOST);
		$url = wp_parse_url($url, PHP_URL_HOST);

		// Compare the domains and return true if they are different
		return $current_domain !== $url;
	}

	/**
	 * Get an URL with an eventual affiliate ID
	 *
	 * @param string $url
	 * @return string
	 */
	public function maybe_add_affiliate_params($url) {
		// Check if the URL is UpdraftPlus.
		if (false !== strpos($url, '//updraftplus.com')) {
			// Set URL with Affiliate ID.
			$url = add_query_arg(array('afref' => $this->get_notices()->get_affiliate_id()), $url);

			// Apply filters.
			$url = apply_filters('wpoptimize_updraftplus_com_link', $url);
		}
		return apply_filters('wpoptimize_maybe_add_affiliate_params', $url);
	}

	/**
	 * Setup WPO logger(s)
	 */
	public function setup_loggers() {

		$logger = $this->get_logger();
		$loggers = $this->wpo_loggers();

		if (!empty($loggers)) {
			foreach ($loggers as $_logger) {
				$logger->add_logger($_logger);
			}
		}

		add_action('wp_optimize_after_optimizations', array($this, 'after_optimizations_logger_action'));
	}

	/**
	 * Run logger actions after all optimizations done
	 */
	public function after_optimizations_logger_action() {
		$loggers = $this->get_logger()->get_loggers();
		if (!empty($loggers)) {
			foreach ($loggers as $logger) {
				if (is_a($logger, 'Updraft_Email_Logger')) {
					$logger->flush_log();
				}
			}
		}
	}

	/**
	 * Returns list of WPO loggers instances
	 * Apply filter wp_optimize_loggers
	 *
	 * @return array
	 */
	public function wpo_loggers() {

		$loggers = array();
		$loggers_classes_by_id = array();
		$options_keys = array();

		$loggers_classes = $this->get_loggers_classes();

		foreach ($loggers_classes as $logger_class => $source) {
			$loggers_classes_by_id[strtolower($logger_class)] = $logger_class;
		}

		$options = $this->get_options();
				
		$saved_loggers = $options->get_option('logging');
		$logger_additional_options = $options->get_option('logging-additional');

		// create loggers classes instances.
		if (!empty($saved_loggers)) {
			// check for previous version options format.
			$keys = array_keys($saved_loggers);

			// if options stored in old format then reformat it.
			if (false == is_numeric($keys[0])) {
				$_saved_loggers = array();
					foreach ($saved_loggers as $logger_id => $enabled) {
						if ($enabled) {
							$_saved_loggers[] = $logger_id;
						}
					}

					// fill email with admin.
					if (array_key_exists('updraft_email_logger', $saved_loggers) && $saved_loggers['updraft_email_logger']) {
						$logger_additional_options['updraft_email_logger'] = array(
							get_option('admin_email')
						);
					}

					$saved_loggers = $_saved_loggers;
			}

			foreach ($saved_loggers as $i => $logger_id) {

				if (!array_key_exists($logger_id, $loggers_classes_by_id)) continue;

				$logger_class = $loggers_classes_by_id[$logger_id];

				$logger = new $logger_class();

				$logger_options = $logger->get_options_list();

				if (!empty($logger_options)) {
					foreach (array_keys($logger_options) as $option_name) {
						if (array_key_exists($option_name, $options_keys)) {
							$options_keys[$option_name]++;
						} else {
									$options_keys[$option_name] = 0;
						}

						$option_value = isset($logger_additional_options[$option_name][$options_keys[$option_name]]) ? $logger_additional_options[$option_name][$options_keys[$option_name]] : '';

						// if options in old format then get correct value.
						if ('' === $option_value && array_key_exists($logger_id, $logger_additional_options)) {
							$option_value = array_shift($logger_additional_options[$logger_id]);
						}

						$logger->set_option($option_name, $option_value);
					}
				}

				// check if logger is active.
				$active = (!is_array($logger_additional_options) || (array_key_exists('active', $logger_additional_options) && empty($logger_additional_options['active'][$i]))) ? false : true;

				if ($active) {
					$logger->enable();
				} else {
					$logger->disable();
				}

				$loggers[] = $logger;
			}
		}

		$loggers = apply_filters('wp_optimize_loggers', $loggers);

		return $loggers;
	}

	/**
	 * Returns associative array with logger class name in a key and path to class file in a value.
	 *
	 * @return array
	 */
	public function get_loggers_classes() {
		$loggers_classes = array(
			'Updraft_PHP_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-php-logger.php',
			'Updraft_Email_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-email-logger.php',
			'Updraft_Ring_Logger' => WPO_PLUGIN_MAIN_PATH . 'includes/class-updraft-ring-logger.php'
		);

		$loggers_classes = apply_filters('wp_optimize_loggers_classes', $loggers_classes);

		if (!empty($loggers_classes)) {
			foreach ($loggers_classes as $logger_class => $logger_file) {
				if (!class_exists($logger_class)) {
					if (is_file($logger_file)) {
						include_once($logger_file);
					}
				}
			}
		}

		return $loggers_classes;
	}

	/**
	 * Returns information about all loggers classes.
	 *
	 * @return array
	 */
	public function get_loggers_classes_info() {
		$loggers_classes = $this->get_loggers_classes();

		$loggers_classes_info = array();

		if (!empty($loggers_classes)) {
			foreach (array_keys($loggers_classes) as $logger_class_name) {

				if (!class_exists($logger_class_name)) continue;

				$logger_id = strtolower($logger_class_name);
				$logger_class = new $logger_class_name();

				$loggers_classes_info[$logger_id] = array(
					'description' => $logger_class->get_description(),
					'available' => $logger_class->is_available(),
					'allow_multiple' => $logger_class->is_allow_multiple(),
					'options' => $logger_class->get_options_list()
				);
			}
		}

		return $loggers_classes_info;
	}

	/**
	 * Returns true if optimization works in multisite mode
	 *
	 * @return boolean
	 */
	public function is_multisite_mode() {
		return (is_multisite() && self::is_premium());
	}

	/**
	 * Returns true if current user can run optimizations.
	 *
	 * @return bool
	 */
	public function can_run_optimizations() {
		// we don't check permissions for cron jobs.
		if (defined('DOING_CRON') && DOING_CRON) return true;

		if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_run_optimizations')) return false;
		return true;
	}

	/**
	 * Returns true if current user can manage plugin options.
	 *
	 * @return bool
	 */
	public function can_manage_options() {
		if (self::is_premium() && false == user_can(get_current_user_id(), 'wpo_manage_settings')) return false;
		return true;
	}

	/**
	 * Returns list of all sites in multisite
	 *
	 * @return array
	 */
	public function get_sites() {
		$sites = array();
		// check if function get_sites exists (since 4.6.0) else use wp_get_sites.
		if (function_exists('get_sites')) {
			$sites = get_sites(array('network_id' => null, 'deleted' => 0, 'number' => 999999));
		} elseif (function_exists('wp_get_sites')) {
			$sites = wp_get_sites(array('network_id' => null, 'deleted' => 0, 'limit' => 999999));
		}
		return $sites;
	}

	/**
	 * Returns script memory limit in megabytes.
	 *
	 * @param bool $memory_limit
	 * @return int
	 */
	public function get_memory_limit($memory_limit = false) {
		// Returns in megabytes
		if (false == $memory_limit) $memory_limit = ini_get('memory_limit');
		$memory_limit = rtrim($memory_limit);

		return $this->return_bytes($memory_limit);
	}

	/**
	 * Returns free memory in bytes.
	 *
	 * @return int
	 */
	public function get_free_memory() {
		return $this->get_memory_limit() - memory_get_usage();
	}

	/**
	 * Checks PHP memory_limit and WP_MAX_MEMORY_LIMIT values and return minimal.
	 *
	 * @return int memory limit in bytes.
	 */
	public function get_script_memory_limit() {
		$memory_limit = $this->get_memory_limit();

		if (defined('WP_MAX_MEMORY_LIMIT')) {
			$wp_memory_limit = $this->get_memory_limit(WP_MAX_MEMORY_LIMIT);

			if ($wp_memory_limit > 0 && $wp_memory_limit < $memory_limit) {
				$memory_limit = $wp_memory_limit;
			}
		}

		return $memory_limit;
	}

	/**
	 * Returns max packet size for database.
	 *
	 * @return int|string
	 */
	public function get_max_packet_size() {
		global $wpdb;
		static $mp = 0;

		if ($mp > 0) return $mp;

		$mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
		// Default to 1MB
		$mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
		// 32MB
		if ($mp < 33554432) {
			$save = $wpdb->show_errors(false);
			@$wpdb->query("SET GLOBAL max_allowed_packet=33554432");// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress errors from displaying
			$wpdb->show_errors($save);

			$mp = (int) $wpdb->get_var("SELECT @@session.max_allowed_packet");
			// Default to 1MB
			$mp = (is_numeric($mp) && $mp > 0) ? $mp : 1048576;
		}

		return $mp;
	}

	/**
	 * Converts shorthand memory notation value to bytes.
	 * From http://php.net/manual/en/function.ini-get.php
	 *
	 * @param string $val shorthand memory notation value.
	 */
	public function return_bytes($val) {
		$val = trim($val);
		$last = strtolower($val[strlen($val)-1]);
		$val = (int) $val;
		switch ($last) {
			case 'g':
			$val *= 1024;
			// no break
			case 'm':
			$val *= 1024;
			// no break
			case 'k':
			$val *= 1024;
		}

		return $val;
	}

	/**
	 * Log fatal errors to defined log destinations.
	 */
	public function log_fatal_errors() {
		$last_error = error_get_last();

		if (isset($last_error['type']) && E_ERROR === $last_error['type']) {
			$this->get_logger()->critical($last_error['message']);
		}
	}

	/**
	 * Close browser connection and continue script work. - Taken from UpdraftPlus
	 *
	 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
	 * @return void
	 */
	public function close_browser_connection($txt = '') {
		if (!headers_sent()) {
			// Close browser connection so that it can resume AJAX polling
			header('Content-Length: '.(empty($txt) ? '0' : 4+strlen($txt)));
			header('Content-Type: application/json');
			header('Connection: close');
			header('Content-Encoding: none');
		}

		if (session_id()) session_write_close();
		echo "\r\n\r\n";
		echo $txt;
		// These two added - 19-Feb-15 - started being required on local dev machine, for unknown reason (probably some plugin that started an output buffer).
		$ob_level = ob_get_level();
		while ($ob_level > 0) {
			ob_end_flush();
			$ob_level--;
		}
		flush();
		if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
		if (function_exists('litespeed_finish_request')) litespeed_finish_request();
	}

	/**
	 * Try to change PHP script time limit.
	 */
	public function change_time_limit() {
		$time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;

		@set_time_limit($time_limit); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Try to reduce the chances of PHP self-terminating via reaching max_execution_time.
	}

	/**
	 * Does the request come from UDC
	 *
	 * @return boolean
	 */
	public function is_updraft_central_request() {
		return defined('UPDRAFTCENTRAL_COMMAND') && UPDRAFTCENTRAL_COMMAND;
	}

	/**
	 * Does the data need to be included in this request. Currently only true if the request is made from UpdraftCentral.
	 *
	 * @return boolean
	 */
	public function template_should_include_data() {
		/**
		 * Filters whether data should be included in certain templates or not.
		 */
		return apply_filters('wpo_template_should_include_data', $this->is_updraft_central_request());
	}

	/**
	 * Load the templates for the modal window
	 */
	public function load_modal_template() {
		$this->include_template('modal.php');
	}

	/**
	 * Delete transients and semaphores data from options table.
	 */
	public function delete_transients_and_semaphores() {
		global $wpdb;

		$masks = array(
			'updraft_locked_wpo_%',
			'updraft_unlocked_wpo_%',
			'updraft_last_lock_time_wpo_%',
			'updraft_semaphore_wpo_%',
			'wpo_locked_%',
			'wpo_unlocked_%',
			'wpo_last_lock_time_%',
			'wpo_semaphore_%',
			'_transient_timeout_wpo_%',
			'_transient_wpo_%',
			'updraft_lock_wpo_%',
			'wpo_last_scheduled_%',
		);

		$where_parts = array();
		foreach ($masks as $mask) {
			$where_parts[] = "(`option_name` LIKE '{$mask}')";
		}

		$wpdb->query("DELETE FROM {$wpdb->options} WHERE " . join(' OR ', $where_parts));
	}

	/**
	 * Prevents bots from indexing plugins list
	 */
	public function robots_txt($output) {
		$upload_dir = wp_upload_dir();
		$path = parse_url($upload_dir['baseurl']);
		$output .= "\nUser-agent: *";
		$output .= "\nDisallow: " . str_replace($path['scheme'].'://'.$path['host'], '', $upload_dir['baseurl']) . "/wpo/wpo-plugins-tables-list.json\n";
		return $output;
	}

	/**
	 * Returns desired enqueue version string
	 *
	 * @return string Enqueue version as string
	 */
	public function get_enqueue_version() {
		return (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
	}

	/**
	 * Returns script suffix string
	 *
	 * @return string empty or `.min` suffix string
	 */
	public function get_min_or_not_string() {
		return (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
	}

	/**
	 * Returns script suffix string with WPO_VERSION
	 *
	 * @return string empty or min suffix with wpo_version string
	 */
	public function get_min_or_not_internal_string() {
		return (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-' . str_replace('.', '-', WPO_VERSION) . '.min';
	}

	/**
	 * Instantiate Ajax handling class
	 */
	private function load_ajax_handler() {
		WPO_Ajax::get_instance();
	}

	/**
	 * Get instance of WP_Optimize_Table_Management
	 *
	 * @return WP_Optimize_Table_Management
	 */
	public function get_table_management() {
		return WP_Optimize_Table_Management::get_instance();
	}

	/**
	 * Get instance of WP_Optimize_404_Detector
	 *
	 * @return WP_Optimize_404_Detector
	 */
	public function get_404_detector() {
		return WP_Optimize_404_Detector::get_instance();
	}

	/**
	 * Returns the message used to notify the user that the PHP version doesn't meet the requirements.
	 *
	 * @return string
	 */
	public function get_php_version_notice_message() {
		return sprintf(esc_html__('WP-Optimize requires a minimum PHP version of %s or higher', 'wp-optimize'), WPO_REQUIRED_PHP_VERSION);
	}

	/**
	 * Output notice when PHP version is not meet for WP-Optimize.
	 *
	 * @return void
	 */
	public function output_php_version_notice() {
		?>
		<div class="notice notice-error is-dismissible">
			<p><?php echo $this->get_php_version_notice_message(); ?></p>
		</div>
		<?php
	}
}

/**
 * Unschedule specific tasks:
 * `wpo_cron_event2` => DB optimizations
 * `wpo_weekly_cron_tasks` => ex: plugin.json auto update
 *
 * @return void
 */
function wpo_cron_deactivate() {
	WP_Optimize()->log('running wpo_cron_deactivate()');
	wp_clear_scheduled_hook('wpo_cron_event2');
	wp_clear_scheduled_hook('wpo_weekly_cron_tasks');
}

function WP_Optimize() {
	return WP_Optimize::instance();
}

endif;

$GLOBALS['wp_optimize'] = WP_Optimize();

Filemanager

Name Type Size Permission Actions
cache Folder 0755
compatibility Folder 0755
css Folder 0755
images Folder 0755
includes Folder 0755
js Folder 0755
languages Folder 0755
minify Folder 0755
optimizations Folder 0755
templates Folder 0755
vendor Folder 0755
webp Folder 0755
LICENSE.txt File 17.67 KB 0644
google-fonts.json File 24.93 KB 0644
index.html File 198 B 0644
plugin.json File 935.33 KB 0644
readme.txt File 56.79 KB 0644
security.md File 1.31 KB 0644
wp-optimize.php File 64.81 KB 0644