From ad5348214ecf88b05ba037ecc73cb9316a58eea1 Mon Sep 17 00:00:00 2001 From: JasWSInc Date: Fri, 13 Jun 2014 01:33:48 -0800 Subject: [PATCH] Finalizing websharks/quick-cache#151 Additional work toward achieving websharks/quick-cache#130 Also resolves websharks/quick-cache#206 Also resolves websharks/quick-cache#95 Also resolves websharks/quick-cache#193 --- quick-cache-pro/includes/actions.php | 137 +-- .../includes/advanced-cache.tpl.php | 931 +-------------- quick-cache-pro/includes/auto-cache.php | 9 +- quick-cache-pro/includes/menu-pages.php | 525 ++++----- quick-cache-pro/includes/share.php | 1012 ++++++++++++++++- .../includes/version-specific-upgrade.php | 136 +++ quick-cache-pro/quick-cache-pro.inc.php | 768 +++---------- 7 files changed, 1651 insertions(+), 1867 deletions(-) create mode 100644 quick-cache-pro/includes/version-specific-upgrade.php diff --git a/quick-cache-pro/includes/actions.php b/quick-cache-pro/includes/actions.php index a063afec..be8757fa 100644 --- a/quick-cache-pro/includes/actions.php +++ b/quick-cache-pro/includes/actions.php @@ -6,8 +6,12 @@ class actions // Action handlers. { + protected $plugin; // Set by constructor. + public function __construct() { + $this->plugin = plugin(); + if(empty($_REQUEST[__NAMESPACE__])) return; foreach((array)$_REQUEST[__NAMESPACE__] as $action => $args) if(method_exists($this, $action)) $this->{$action}($args); @@ -15,21 +19,21 @@ public function __construct() public function wipe_cache($args) { - if(!current_user_can(plugin()->network_cap)) + if(!current_user_can($this->plugin->network_cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) return; // Unauthenticated POST data. - $counter = plugin()->wipe_cache(TRUE); // Counter. + $counter = $this->plugin->wipe_cache(TRUE); // Counter. - if(plugin()->options['cache_clear_s2clean_enable']) + if($this->plugin->options['cache_clear_s2clean_enable']) if(function_exists('s2clean')) $s2clean_counter = s2clean()->md_cache_clear(); - if(plugin()->options['cache_clear_eval_code']) // Custom code? + if($this->plugin->options['cache_clear_eval_code']) // Custom code? { ob_start(); // Buffer output from PHP code. - eval('?>'.plugin()->options['cache_clear_eval_code'].''.$this->plugin->options['cache_clear_eval_code'].'network_cap)) + if(!current_user_can($this->plugin->network_cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) return; // Unauthenticated POST data. - $counter = plugin()->wipe_cache(TRUE); // Counter. + $counter = $this->plugin->wipe_cache(TRUE); // Counter. - if(plugin()->options['cache_clear_s2clean_enable']) + if($this->plugin->options['cache_clear_s2clean_enable']) if(function_exists('s2clean')) $s2clean_counter = s2clean()->md_cache_clear(); - if(plugin()->options['cache_clear_eval_code']) // Custom code? + if($this->plugin->options['cache_clear_eval_code']) // Custom code? { ob_start(); // Buffer output from PHP code. - eval('?>'.plugin()->options['cache_clear_eval_code'].''.$this->plugin->options['cache_clear_eval_code'].'Wiped a total of %1$s cache files.

', plugin()->text_domain), $counter); - $response .= __('

Cache wiped for all sites; recreation will occur automatically over time.

', plugin()->text_domain); - if(isset($s2clean_counter)) $response .= sprintf(__('

Also wiped %1$s s2Clean cache files.

', plugin()->text_domain), $s2clean_counter); + $response = sprintf(__('

Wiped a total of %1$s cache files.

', $this->plugin->text_domain), $counter); + $response .= __('

Cache wiped for all sites; recreation will occur automatically over time.

', $this->plugin->text_domain); + if(isset($s2clean_counter)) $response .= sprintf(__('

Also wiped %1$s s2Clean cache files.

', $this->plugin->text_domain), $s2clean_counter); if(!empty($eval_output)) $response .= $eval_output; // Custom output (perhaps even multiple messages). exit($response); // JavaScript will take it from here. @@ -68,21 +72,21 @@ public function ajax_wipe_cache($args) public function clear_cache($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) return; // Unauthenticated POST data. - $counter = plugin()->clear_cache(TRUE); // Counter. + $counter = $this->plugin->clear_cache(TRUE); // Counter. - if(plugin()->options['cache_clear_s2clean_enable']) + if($this->plugin->options['cache_clear_s2clean_enable']) if(function_exists('s2clean')) $s2clean_counter = s2clean()->md_cache_clear(); - if(plugin()->options['cache_clear_eval_code']) // Custom code? + if($this->plugin->options['cache_clear_eval_code']) // Custom code? { ob_start(); // Buffer output from PHP code. - eval('?>'.plugin()->options['cache_clear_eval_code'].''.$this->plugin->options['cache_clear_eval_code'].'cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) return; // Unauthenticated POST data. - $counter = plugin()->clear_cache(TRUE); // Counter. + $counter = $this->plugin->clear_cache(TRUE); // Counter. - if(plugin()->options['cache_clear_s2clean_enable']) + if($this->plugin->options['cache_clear_s2clean_enable']) if(function_exists('s2clean')) $s2clean_counter = s2clean()->md_cache_clear(); - if(plugin()->options['cache_clear_eval_code']) // Custom code? + if($this->plugin->options['cache_clear_eval_code']) // Custom code? { ob_start(); // Buffer output from PHP code. - eval('?>'.plugin()->options['cache_clear_eval_code'].''.$this->plugin->options['cache_clear_eval_code'].'Cleared a total of %1$s cache files.

', plugin()->text_domain), $counter); - $response .= __('

Cache cleared for this site; recreation will occur automatically over time.

', plugin()->text_domain); - if(isset($s2clean_counter)) $response .= sprintf(__('

Also cleared %1$s s2Clean cache files.

', plugin()->text_domain), $s2clean_counter); + $response = sprintf(__('

Cleared a total of %1$s cache files.

', $this->plugin->text_domain), $counter); + $response .= __('

Cache cleared for this site; recreation will occur automatically over time.

', $this->plugin->text_domain); + if(isset($s2clean_counter)) $response .= sprintf(__('

Also cleared %1$s s2Clean cache files.

', $this->plugin->text_domain), $s2clean_counter); if(!empty($eval_output)) $response .= $eval_output; // Custom output (perhaps even multiple messages). exit($response); // JavaScript will take it from here. @@ -121,7 +125,7 @@ public function ajax_clear_cache($args) public function save_options($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) @@ -141,38 +145,38 @@ public function save_options($args) if(isset($args['base_dir'])) // No leading/trailing slashes please. $args['base_dir'] = trim($args['base_dir'], '\\/'." \t\n\r\0\x0B"); - plugin()->options = array_merge(plugin()->default_options, $args); + $this->plugin->options = array_merge($this->plugin->default_options, $args); - if(!trim(plugin()->options['base_dir'], '\\/'." \t\n\r\0\x0B") // Empty? - || strpos(basename(plugin()->options['base_dir']), 'wp-') === 0 // Reserved? - ) plugin()->options['base_dir'] = plugin()->default_options['base_dir']; + if(!trim($this->plugin->options['base_dir'], '\\/'." \t\n\r\0\x0B") // Empty? + || strpos(basename($this->plugin->options['base_dir']), 'wp-') === 0 // Reserved? + ) $this->plugin->options['base_dir'] = $this->plugin->default_options['base_dir']; - update_option(__NAMESPACE__.'_options', plugin()->options); // Blog-specific. - if(is_multisite()) update_site_option(__NAMESPACE__.'_options', plugin()->options); + update_option(__NAMESPACE__.'_options', $this->plugin->options); // Blog-specific. + if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->plugin->options); $redirect_to = self_admin_url('/admin.php'); // Redirect preparations. $query_args = array('page' => __NAMESPACE__, __NAMESPACE__.'__updated' => '1'); - plugin()->auto_wipe_cache(); // May produce a notice. + $this->plugin->auto_wipe_cache(); // May produce a notice. - if(plugin()->options['enable']) // Enable. + if($this->plugin->options['enable']) // Enable. { - if(!($add_wp_cache_to_wp_config = plugin()->add_wp_cache_to_wp_config())) + if(!($add_wp_cache_to_wp_config = $this->plugin->add_wp_cache_to_wp_config())) $query_args[__NAMESPACE__.'__wp_config_wp_cache_add_failure'] = '1'; - if(!($add_advanced_cache = plugin()->add_advanced_cache())) + if(!($add_advanced_cache = $this->plugin->add_advanced_cache())) $query_args[__NAMESPACE__.'__advanced_cache_add_failure'] = ($add_advanced_cache === NULL) ? 'qc-advanced-cache' : '1'; - plugin()->update_blog_paths(); + $this->plugin->update_blog_paths(); } else // We need to disable Quick Cache in this case. { - if(!($remove_wp_cache_from_wp_config = plugin()->remove_wp_cache_from_wp_config())) + if(!($remove_wp_cache_from_wp_config = $this->plugin->remove_wp_cache_from_wp_config())) $query_args[__NAMESPACE__.'__wp_config_wp_cache_remove_failure'] = '1'; - if(!($remove_advanced_cache = plugin()->remove_advanced_cache())) + if(!($remove_advanced_cache = $this->plugin->remove_advanced_cache())) $query_args[__NAMESPACE__.'__advanced_cache_remove_failure'] = '1'; } $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to); @@ -182,40 +186,39 @@ public function save_options($args) public function restore_default_options($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) return; // Unauthenticated POST data. delete_option(__NAMESPACE__.'_options'); // Blog-specific. - delete_option('ws_plugin__qcache_options'); // Blog-specific. if(is_multisite()) delete_site_option(__NAMESPACE__.'_options'); - plugin()->options = plugin()->default_options; + $this->plugin->options = $this->plugin->default_options; $redirect_to = self_admin_url('/admin.php'); // Redirect preparations. $query_args = array('page' => __NAMESPACE__, __NAMESPACE__.'__restored' => '1'); - plugin()->auto_wipe_cache(); // May produce a notice. + $this->plugin->auto_wipe_cache(); // May produce a notice. - if(plugin()->options['enable']) // Enable. + if($this->plugin->options['enable']) // Enable. { - if(!($add_wp_cache_to_wp_config = plugin()->add_wp_cache_to_wp_config())) + if(!($add_wp_cache_to_wp_config = $this->plugin->add_wp_cache_to_wp_config())) $query_args[__NAMESPACE__.'__wp_config_wp_cache_add_failure'] = '1'; - if(!($add_advanced_cache = plugin()->add_advanced_cache())) + if(!($add_advanced_cache = $this->plugin->add_advanced_cache())) $query_args[__NAMESPACE__.'__advanced_cache_add_failure'] = ($add_advanced_cache === NULL) ? 'qc-advanced-cache' : '1'; - plugin()->update_blog_paths(); + $this->plugin->update_blog_paths(); } else // We need to disable Quick Cache in this case. { - if(!($remove_wp_cache_from_wp_config = plugin()->remove_wp_cache_from_wp_config())) + if(!($remove_wp_cache_from_wp_config = $this->plugin->remove_wp_cache_from_wp_config())) $query_args[__NAMESPACE__.'__wp_config_wp_cache_remove_failure'] = '1'; - if(!($remove_advanced_cache = plugin()->remove_advanced_cache())) + if(!($remove_advanced_cache = $this->plugin->remove_advanced_cache())) $query_args[__NAMESPACE__.'__advanced_cache_remove_failure'] = '1'; } $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to); @@ -225,7 +228,7 @@ public function restore_default_options($args) public function export_options($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) @@ -237,7 +240,7 @@ public function export_options($args) while(@ob_end_clean()) ; // Cleans output buffers. - $export = json_encode(plugin()->options); + $export = json_encode($this->plugin->options); $file_name = __NAMESPACE__.'-options.json'; nocache_headers(); @@ -251,7 +254,7 @@ public function export_options($args) public function update_sync($args) { - if(!current_user_can(plugin()->update_cap)) + if(!current_user_can($this->plugin->update_cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) @@ -259,9 +262,9 @@ public function update_sync($args) $args = array_map('trim', stripslashes_deep((array)$args)); - if(empty($args['username'])) $args['username'] = plugin()->options['update_sync_username']; - if(empty($args['password'])) $args['password'] = plugin()->options['update_sync_password']; - if(!isset($args['version_check'])) $args['version_check'] = plugin()->options['update_sync_version_check']; + if(empty($args['username'])) $args['username'] = $this->plugin->options['update_sync_username']; + if(empty($args['password'])) $args['password'] = $this->plugin->options['update_sync_password']; + if(!isset($args['version_check'])) $args['version_check'] = $this->plugin->options['update_sync_version_check']; $update_sync_url = 'https://www.websharks-inc.com/products/update-sync.php'; $update_sync_post_vars = array('data' => array('slug' => str_replace('_', '-', __NAMESPACE__).'-pro', 'version' => 'latest-stable', @@ -275,7 +278,7 @@ public function update_sync($args) ) // Report errors in all of these cases. Redirect errors to `update-sync` page. { if(!empty($update_sync_response['error'])) $error = $update_sync_response['error']; - else $error = __('Unknown error. Please wait 15 minutes and try again.', plugin()->text_domain); + else $error = __('Unknown error. Please wait 15 minutes and try again.', $this->plugin->text_domain); $redirect_to = self_admin_url('/admin.php'); // Redirect preparations. $query_args = array('page' => __NAMESPACE__.'-update-sync', __NAMESPACE__.'__error' => $error); @@ -283,20 +286,20 @@ public function update_sync($args) wp_redirect($redirect_to).exit(); // Done; with errors. } - plugin()->options['update_sync_username'] = $args['username']; // Update username. - plugin()->options['update_sync_password'] = $args['password']; // Update password. - plugin()->options['update_sync_version_check'] = $args['version_check']; // Check version? - plugin()->options['last_update_sync_version_check'] = time(); // Update this; we just checked :-) - update_option(__NAMESPACE__.'_options', plugin()->options); // Save each of these options. - if(is_multisite()) update_site_option(__NAMESPACE__.'_options', plugin()->options); + $this->plugin->options['update_sync_username'] = $args['username']; // Update username. + $this->plugin->options['update_sync_password'] = $args['password']; // Update password. + $this->plugin->options['update_sync_version_check'] = $args['version_check']; // Check version? + $this->plugin->options['last_update_sync_version_check'] = time(); // Update this; we just checked :-) + update_option(__NAMESPACE__.'_options', $this->plugin->options); // Save each of these options. + if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->plugin->options); $notices = (is_array($notices = get_option(__NAMESPACE__.'_notices'))) ? $notices : array(); unset($notices['persistent-update-sync-version']); // Dismiss this notice. update_option(__NAMESPACE__.'_notices', $notices); // Update notices. $redirect_to = self_admin_url('/update.php'); // Runs update routines in WordPress. - $query_args = array('action' => 'upgrade-plugin', 'plugin' => plugin_basename(plugin()->file), - '_wpnonce' => wp_create_nonce('upgrade-plugin_'.plugin_basename(plugin()->file)), + $query_args = array('action' => 'upgrade-plugin', 'plugin' => plugin_basename($this->plugin->file), + '_wpnonce' => wp_create_nonce('upgrade-plugin_'.plugin_basename($this->plugin->file)), __NAMESPACE__.'__update_version' => $update_sync_response['version'], __NAMESPACE__.'__update_zip' => base64_encode($update_sync_response['zip'])); $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to); @@ -306,7 +309,7 @@ public function update_sync($args) public function dismiss_notice($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) @@ -324,7 +327,7 @@ public function dismiss_notice($args) public function dismiss_error($args) { - if(!current_user_can(plugin()->cap)) + if(!current_user_can($this->plugin->cap)) return; // Nothing to do. if(empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'])) diff --git a/quick-cache-pro/includes/advanced-cache.tpl.php b/quick-cache-pro/includes/advanced-cache.tpl.php index 5b1d97d0..5ace7796 100644 --- a/quick-cache-pro/includes/advanced-cache.tpl.php +++ b/quick-cache-pro/includes/advanced-cache.tpl.php @@ -100,13 +100,13 @@ if(!defined('QUICK_CACHE_DIR')) /** - * Directory used to store cache files; relative to `ABSPATH`. + * Directory used to store cache files; relative to `WP_CONTENT_DIR`. * * @since 140422 First documented version. * * @var string Absolute server directory path. */ - define('QUICK_CACHE_DIR', ABSPATH.'%%QUICK_CACHE_DIR%%'); + define('QUICK_CACHE_DIR', WP_CONTENT_DIR.'/'.'%%QUICK_CACHE_DIR%%'); if(!defined('QUICK_CACHE_MAX_AGE')) /** @@ -218,7 +218,7 @@ * * @var string Absolute server directory path. */ - define('QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC', ABSPATH.'%%QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC%%'); + define('QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC', WP_CONTENT_DIR.'/'.'%%QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC%%'); if(!defined('QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE')) /** @@ -228,7 +228,7 @@ * * @var string Absolute server directory path. */ - define('QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE', ABSPATH.'%%QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE%%'); + define('QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE', WP_CONTENT_DIR.'/'.'%%QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE%%'); if(!defined('QUICK_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_BODY_CSS')) /** @@ -331,16 +331,16 @@ * @package quick_cache\advanced_cache * @since 140422 First documented version. */ - class advanced_cache # `/wp-content/advanced-cache.php` + class advanced_cache extends share # `/wp-content/advanced-cache.php` { /** - * Identifies the pro version of Quick Cache. + * Microtime; defined by class constructor for debugging purposes. * * @since 140422 First documented version. * - * @var boolean `TRUE` for Quick Cache Pro; else `FALSE`. + * @var float Result of a call to {@link \microtime()}. */ - public $is_pro = TRUE; + public $timer = 0; /** * Flagged as `TRUE` if QC advanced cache is active & running. @@ -351,15 +351,6 @@ class advanced_cache # `/wp-content/advanced-cache.php` */ public $is_running = FALSE; - /** - * Microtime; defined by class constructor for debugging purposes. - * - * @since 140422 First documented version. - * - * @var float Result of a call to {@link \microtime()}. - */ - public $timer = 0; - /** * Calculated protocol; one of `http://` or `https://`. * @@ -441,17 +432,6 @@ class advanced_cache # `/wp-content/advanced-cache.php` 'set_debug_info' => QUICK_CACHE_DEBUGGING_ENABLE, ); - /** - * Last HTTP status code passed through {@link \status_header}. - * - * @since 140422 First documented version. - * - * @var null|integer Last HTTP status code (if applicable). - * - * @see maybe_filter_status_header_postload() - */ - public $http_status; - /** * An array of debug info. * @@ -484,37 +464,37 @@ class advanced_cache # `/wp-content/advanced-cache.php` public $is_404 = FALSE; /** - * Is the current request a WordPress content type? + * Last HTTP status code passed through {@link \status_header}. * - * @since 140605 Improving debug notes display. + * @since 140422 First documented version. * - * @var boolean `TRUE` if is a WP content type. + * @var integer Last HTTP status code (if applicable). * - * @see wp_main_query_postload() + * @see maybe_filter_status_header_postload() */ - public $is_a_wp_content_type = FALSE; + public $http_status = 0; /** - * Current WordPress {@link \site_url()}. + * Is the current request a WordPress content type? * - * @since 140422 First documented version. + * @since 140605 Improving debug notes display. * - * @var string Current WordPress {@link \site_url()}. + * @var boolean `TRUE` if is a WP content type. * * @see wp_main_query_postload() */ - public $site_url = ''; + public $is_a_wp_content_type = FALSE; /** - * Current WordPress {@link \home_url()}. + * Current WordPress {@link \content_url()}. * - * @since 140422 First documented version. + * @since 14xxxx Reorganizing class members. * - * @var string Current WordPress {@link \home_url()}. + * @var string Current WordPress {@link \content_url()}. * * @see wp_main_query_postload() */ - public $home_url = ''; + public $content_url = ''; /** * Flag for {@link \is_user_loged_in()}. @@ -549,43 +529,6 @@ class advanced_cache # `/wp-content/advanced-cache.php` */ public $plugin_file = QUICK_CACHE_PLUGIN_FILE; - /** - * Flag indicating the current user login cookie is expired or invalid. - * - * @since 140429 Improving user cache handlers. - * - * @var boolean `TRUE` if current user login cookie is expired or invalid. - * See also {@link user_token()} and {@link maybe_start_ob_when_logged_in_postload()}. - */ - public $user_login_cookie_expired_or_invalid = FALSE; - - /** - * Text domain for translations; based on `__NAMESPACE__`. - * - * @since 140422 First documented version. - * - * @var string Defined by class constructor; for translations. - */ - public $text_domain = ''; - - /** - * Array of hooks added by plugins. - * - * @since 140422 First documented version. - * - * @var array An array of any hooks added by plugins. - */ - public $hooks = array(); - - /** - * Easy reference to the {@link share} class instance. - * - * @since 14xxxx Reorganizing class members. - * - * @var share References {@link share} class. - */ - public $share; // Set by constructor. - /** * No-cache because of the current {@link \PHP_SAPI}. * @@ -854,16 +797,16 @@ class advanced_cache # `/wp-content/advanced-cache.php` */ public function __construct() { + parent::__construct(); // Shared constructor. + if(!WP_CACHE || !QUICK_CACHE_ENABLE) return; // Not enabled. if(defined('WP_INSTALLING') || defined('RELOCATE')) return; // N/A; installing|relocating. - $this->is_running = TRUE; - $this->timer = microtime(TRUE); - $this->text_domain = str_replace('_', '-', __NAMESPACE__); - $this->share = $GLOBALS[__NAMESPACE__.'__share']; + $this->is_running = TRUE; + $this->timer = microtime(TRUE); $this->load_ac_plugins(); $this->register_shutdown_flag(); @@ -1237,19 +1180,14 @@ public function wp_main_query_postload() if($this->is_wp_loaded_query || is_admin()) return; // Nothing to do. - if(!is_main_query()) - return; // Not the main query. + if(!is_main_query()) return; // Not main query. $this->is_wp_loaded_query = TRUE; $this->is_404 = is_404(); - $this->site_url = site_url(); - $this->home_url = home_url(); $this->is_user_logged_in = is_user_logged_in(); + $this->content_url = rtrim(content_url(), '/'); $this->is_maintenance = function_exists('is_maintenance') && is_maintenance(); $this->is_a_wp_content_type = $this->is_404 || $this->is_maintenance || is_front_page() || is_home() || is_singular() || is_archive() || is_post_type_archive() || is_tax() || is_search() || is_feed(); - - if(function_exists('\\'.__NAMESPACE__.'\\plugin')) - $this->plugin_file = plugin()->file; } /** @@ -1349,7 +1287,7 @@ public function output_buffer_callback_handler($buffer, $phase) if(QUICK_CACHE_DEBUGGING_ENABLE && $this->is_html_xml_doc($cache)) // Only if HTML comments are possible. { $total_time = number_format(microtime(TRUE) - $this->timer, 5, '.', ''); - $cache .= "\n".''; + $cache .= "\n".''; $cache .= "\n".''; $cache .= "\n".''; @@ -1385,8 +1323,10 @@ public function output_buffer_callback_handler($buffer, $phase) */ public function maybe_compress_html($cache) { - if(!$this->site_url) return $cache; // Not possible. - if(!QUICK_CACHE_HTMLC_ENABLE || !$this->plugin_file) + if(!$this->content_url) + return $cache; // Not possible. + + if(!QUICK_CACHE_HTMLC_ENABLE) return $cache; // Nothing to do here. require_once dirname($this->plugin_file).'/includes/html-compressor/stub.php'; @@ -1408,7 +1348,7 @@ public function maybe_compress_html($cache) 'cache_expiration_time' => QUICK_CACHE_HTMLC_CACHE_EXPIRATION_TIME, 'cache_dir_public' => QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC.$host_dir_token, - 'cache_dir_url_public' => $this->site_url.'/'.str_replace(ABSPATH, '', QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC.$host_dir_token), + 'cache_dir_url_public' => $this->content_url.str_replace(WP_CONTENT_DIR, '', QUICK_CACHE_HTMLC_CACHE_DIR_PUBLIC.$host_dir_token), 'cache_dir_private' => QUICK_CACHE_HTMLC_CACHE_DIR_PRIVATE.$host_dir_token, 'compress_combine_head_body_css' => QUICK_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_BODY_CSS, @@ -1587,811 +1527,6 @@ public function maybe_get_nc_debug_info($reason_code = '', $reason = '') } return "\n".''; } - - /* - * See also: `quick-cache-pro.inc.php` duplicates. - * @TODO Find a way to centralize this section so it can be shared between both classes easily. - */ - - /** - * Exclude scheme from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_SCHEME = 1; - - /** - * Exclude host (i.e. domain name) from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_HOST = 2; - - /** - * Exclude path from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_PATH = 4; - - /** - * Exclude path index (i.e. no default `index`) from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_PATH_INDEX = 8; - - /** - * Exclude query, user & version salt from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_QUV = 16; - - /** - * Exclude query string from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_QUERY = 32; - - /** - * Exclude user token from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_USER = 64; - - /** - * Exclude version salt from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_VSALT = 128; - - /** - * Exclude extension from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_EXT = 256; - - /** - * Converts a URL into a `cache/path`. - * - * @since 140422 First documented version. - * - * @param string $url The input URL to convert. - * @param string $with_user_token Optional user token (if applicable). - * @param string $with_version_salt Optional version salt (if applicable). - * @param integer $flags Optional flags; a bitmask provided by `CACHE_PATH_*` constants. - * - * @return string The resulting `cache/path` based on the input `$url`. - */ - public function url_to_cache_path($url, $with_user_token = '', $with_version_salt = '', $flags = 0) - { - $cache_path = ''; // Initialize. - $url = trim((string)$url); - $with_user_token = trim((string)$with_user_token); - $with_version_salt = trim((string)$with_version_salt); - - if($url && strpos($url, '://') === FALSE) - $url = '//'.ltrim($url, '/'); - - if(!$url || !($url = parse_url($url))) - return ''; // Invalid URL. - - if(!($flags & $this::CACHE_PATH_NO_SCHEME)) - { - if(!empty($url['scheme'])) - $cache_path .= $url['scheme'].'/'; - else $cache_path .= $this->is_ssl() ? 'https/' : 'http/'; - } - if(!($flags & $this::CACHE_PATH_NO_HOST)) - { - if(!empty($url['host'])) - $cache_path .= $url['host'].'/'; - else $cache_path .= $_SERVER['HTTP_HOST'].'/'; - } - if(!($flags & $this::CACHE_PATH_NO_PATH)) - { - if(!empty($url['path']) && strlen($url['path'] = trim($url['path'], '\\/'." \t\n\r\0\x0B"))) - $cache_path .= $url['path'].'/'; - else if(!($flags & $this::CACHE_PATH_NO_PATH_INDEX)) $cache_path .= 'index/'; - } - if($this->is_extension_loaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) - $cache_path = mb_strtolower($cache_path, 'UTF-8'); - $cache_path = str_replace('.', '-', strtolower($cache_path)); - - if(!($flags & $this::CACHE_PATH_NO_QUV)) - { - if(!($flags & $this::CACHE_PATH_NO_QUERY)) - if(isset($url['query']) && $url['query'] !== '') - $cache_path = rtrim($cache_path, '/').'.q/'.md5($url['query']).'/'; - - if(!($flags & $this::CACHE_PATH_NO_USER)) - if($with_user_token !== '') // Allow a `0` value if desirable. - $cache_path = rtrim($cache_path, '/').'.u/'.str_replace(array('/', '\\'), '-', $with_user_token).'/'; - - if(!($flags & $this::CACHE_PATH_NO_VSALT)) - if($with_version_salt !== '') // Allow a `0` value if desirable. - $cache_path = rtrim($cache_path, '/').'.v/'.str_replace(array('/', '\\'), '-', $with_version_salt).'/'; - } - $cache_path = trim(preg_replace('/\/+/', '/', $cache_path), '/'); - $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path); - - if(!($flags & $this::CACHE_PATH_NO_EXT)) - $cache_path .= '.html'; - - return $cache_path; - } - - /** - * Produces a token based on the current `$_SERVER['HTTP_HOST']`. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Token based on the current `$_SERVER['HTTP_HOST']`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function host_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $host = strtolower($_SERVER['HTTP_HOST']); - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host), '-') : $host; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces a token based on the current site's base directory. - * - * @since 140605 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Produces a token based on the current site's base directory; - * (i.e. in the case of a sub-directory multisite network). - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see plugin\clear_cache() - * @see plugin\update_blog_paths() - */ - public function host_base_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $host_base_token = '/'; // Assume NOT multisite; or running it's own domain. - - if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) - { // Multisite w/ sub-directories; need a valid sub-directory token. - - if(defined('PATH_CURRENT_SITE')) $host_base_token = PATH_CURRENT_SITE; - else if(!empty($GLOBALS['base'])) $host_base_token = $GLOBALS['base']; - - $host_base_token = trim($host_base_token, '\\/'." \t\n\r\0\x0B"); - $host_base_token = (isset($host_base_token[0])) ? '/'.$host_base_token.'/' : '/'; - } - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_base_token), '-') : $host_base_token; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces a token based on the current blog's sub-directory. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Produces a token based on the current blog sub-directory - * (i.e. in the case of a sub-directory multisite network). - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see plugin\clear_cache() - * @see plugin\update_blog_paths() - */ - public function host_dir_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $host_dir_token = '/'; // Assume NOT multisite; or running it's own domain. - - if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) - { // Multisite w/ sub-directories; need a valid sub-directory token. - - $uri_minus_base = // Supports `/sub-dir/child-blog-sub-dir/` also. - preg_replace('/^'.preg_quote($this->host_base_token(), '/').'/', '', $_SERVER['REQUEST_URI']); - - list($host_dir_token) = explode('/', trim($uri_minus_base, '/')); - $host_dir_token = (isset($host_dir_token[0])) ? '/'.$host_dir_token.'/' : '/'; - - if($host_dir_token !== '/' // Perhaps NOT the main site? - && (!is_file(QUICK_CACHE_DIR.'/qc-blog-paths') // NOT a read/valid blog path? - || !in_array($host_dir_token, unserialize(file_get_contents(QUICK_CACHE_DIR.'/qc-blog-paths')), TRUE)) - ) $host_dir_token = '/'; // Main site; e.g. this is NOT a real/valid child blog path. - } - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_dir_token), '-') : $host_dir_token; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces tokens for the current site's base directory & current blog's sub-directory. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Tokens for the current site's base directory & current blog's sub-directory. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see clear_cache() - * @see update_blog_paths() - */ - public function host_base_dir_tokens($dashify = FALSE) - { - return preg_replace('/\/{2,}/', '/', $this->host_base_token($dashify).$this->host_dir_token($dashify)); - } - - /** - * Produces a token based on the current user. - * - * @since 140422 First documented version. - * - * @return string Produces a token based on the current user; - * else an empty string if that's not possible to do. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @note This routine may trigger a flag which indicates that the current user was logged-in at some point, - * but now the login cookie can no longer be validated by WordPress; i.e. they are NOT actually logged in any longer. - * See {@link $user_login_cookie_expired_or_invalid} - */ - public function user_token() - { - static $token; // Cache. - if(isset($token)) return $token; - - if(function_exists('wp_validate_auth_cookie') && ($user_id = (integer)wp_validate_auth_cookie('', 'logged_in'))) - return ($token = $user_id); // A real user in this case. - - else if(!empty($_COOKIE['comment_author_email_'.COOKIEHASH]) && is_string($_COOKIE['comment_author_email_'.COOKIEHASH])) - return ($token = md5(strtolower(stripslashes($_COOKIE['comment_author_email_'.COOKIEHASH])))); - - else if(!empty($_COOKIE['wp-postpass_'.COOKIEHASH]) && is_string($_COOKIE['wp-postpass_'.COOKIEHASH])) - return ($token = md5(stripslashes($_COOKIE['wp-postpass_'.COOKIEHASH]))); - - else if(defined('SID') && SID) return ($token = preg_replace('/[^a-z0-9]/i', '', SID)); - - if(function_exists('wp_validate_auth_cookie') // We were unable to validate the login cookie? - && !empty($_COOKIE['wordpress_logged_in_'.COOKIEHASH]) && is_string($_COOKIE['wordpress_logged_in_'.COOKIEHASH]) - ) $this->user_login_cookie_expired_or_invalid = TRUE; // Flag as `TRUE`. - - return ($token = ''); - } - - /** - * Recursive directory iterator based on a regex pattern. - * - * @since 140422 First documented version. - * - * @param string $dir An absolute server directory path. - * @param string $regex A regex pattern; compares to each full file path. - * - * @return \RegexIterator Navigable with {@link \foreach()}; where each item - * is a {@link \RecursiveDirectoryIterator}. - */ - public function dir_regex_iteration($dir, $regex) - { - $dir_iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS); - $iterator_iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST); - $regex_iterator = new \RegexIterator($iterator_iterator, $regex, \RegexIterator::MATCH, \RegexIterator::USE_KEY); - - return $regex_iterator; - } - - /** - * Is the current request method `POST|PUT|DELETE`? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_post_put_del_request() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(!empty($_SERVER['REQUEST_METHOD'])) - if(in_array(strtoupper($_SERVER['REQUEST_METHOD']), array('POST', 'PUT', 'DELETE'), TRUE)) - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Does the current request include a query string? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_get_request_w_query() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(!empty($_GET) || isset($_SERVER['QUERY_STRING'][0])) - if(!(isset($_GET['qcABC']) && count($_GET) === 1)) // Ignore this special case. - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Should the current user be considered a logged-in user? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_like_user_logged_in() - { - static $is; // Cache. - if(isset($is)) return $is; - - /* This checks for a PHP session; i.e. session_start() in PHP where you're dealing with a user session. - * WordPress itself does not use sessions, but some plugins/themes do. If you have a theme/plugin using - * sessions, and there is an active session open, we consider you logged in; and thus, no caching. - * SID is a PHP internal constant to identify a PHP session. It's the same regardless of the app. If PHP - * starts a session, SID is defined. - */ - if(defined('SID') && SID) return ($is = TRUE); // Session. - - $logged_in_cookies[] = 'comment_author_'; // Comment (and/or reply) authors. - $logged_in_cookies[] = 'wp-postpass_'; // Password access to protected posts. - - $logged_in_cookies[] = (defined('AUTH_COOKIE')) ? AUTH_COOKIE : 'wordpress_'; - $logged_in_cookies[] = (defined('SECURE_AUTH_COOKIE')) ? SECURE_AUTH_COOKIE : 'wordpress_sec_'; - $logged_in_cookies[] = (defined('LOGGED_IN_COOKIE')) ? LOGGED_IN_COOKIE : 'wordpress_logged_in_'; - $logged_in_cookies = '/^(?:'.implode('|', array_map(function ($logged_in_cookie) - { - return preg_quote($logged_in_cookie, '/'); // Escape. - - }, $logged_in_cookies)).')/'; - $test_cookie = (defined('TEST_COOKIE')) ? TEST_COOKIE : 'wordpress_test_cookie'; - - foreach($_COOKIE as $_key => $_value) if($_key !== $test_cookie) - if(preg_match($logged_in_cookies, $_key) && $_value) return ($is = TRUE); - unset($_key, $_value); // Housekeeping. - - return ($is = FALSE); - } - - /** - * Are we in a LOCALHOST environment? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_localhost() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(defined('LOCALHOST') && LOCALHOST) return ($is = TRUE); - - if(!defined('LOCALHOST') && !empty($_SERVER['HTTP_HOST'])) - if(preg_match('/localhost|127\.0\.0\.1/i', $_SERVER['HTTP_HOST'])) - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Is the current request for the Auto-Cache Engine? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_auto_cache_engine() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(!empty($_SERVER['HTTP_USER_AGENT'])) - if(stripos($_SERVER['HTTP_USER_AGENT'], __NAMESPACE__) !== FALSE) - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Is the current request for a feed? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_feed() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) - return ($is = TRUE); - - if(isset($_REQUEST['feed'])) - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Is the current request over SSL? - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if yes; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_ssl() - { - static $is; // Cache. - if(isset($is)) return $is; - - if(!empty($_SERVER['SERVER_PORT'])) - if($_SERVER['SERVER_PORT'] === '443') - return ($is = TRUE); - - if(!empty($_SERVER['HTTPS'])) - if($_SERVER['HTTPS'] === '1' || strcasecmp($_SERVER['HTTPS'], 'on') === 0) - return ($is = TRUE); - - if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) - if(strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) - return ($is = TRUE); - - return ($is = FALSE); - } - - /** - * Is a document/string an HTML/XML doc; or no? - * - * @since 140422 First documented version. - * - * @param string $doc Input string/document to check. - * - * @return boolean `TRUE` if yes; else `FALSE`. - */ - public function is_html_xml_doc($doc) - { - if(($doc = (string)$doc)) - if(stripos($doc, '') !== FALSE || stripos($doc, 'http_status = $http_response_code; - - $http_status = (string)$this->http_status; // So we can check indexes. - if(isset($http_status[0]) && $http_status[0] !== '2' && $http_status !== '404') - return ($has = FALSE); // A non-2xx & non-404 status code. - /* - * PHP's `headers_list()` currently does NOT include `HTTP/` headers. - * This means the following routine will never catch a status sent by `status_header()`. - * However, I'm leaving this check in place in case a future version of PHP adds support for this. - * - * For now, we monitor `status_header()` via {@link maybe_filter_status_header_postload()} so that will suffice. - */ - foreach(headers_list() as $_header) - if(preg_match('/^(?:Retry\-After\:\s+(?P.+)|Status\:\s+(?P[0-9]+)|HTTP\/[0-9]+\.[0-9]+\s+(?P[0-9]+))/i', $_header, $_m)) - if(!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404') - || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404') - ) return ($has = FALSE); // Don't cache (anything that's NOT a 2xx or 404 status). - unset($_header); // Just a little housekeeping. - - return ($has = TRUE); // Assume that it is by default, we are within WP after all. - } - - /** - * Checks if a PHP extension is loaded up. - * - * @since 140422 First documented version. - * - * @param string $extension A PHP extension slug (i.e. extension name). - * - * @return boolean `TRUE` if the extension is loaded; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_extension_loaded($extension) - { - static $is = array(); // Static cache. - if(isset($is[$extension])) return $is[$extension]; - return ($is[$extension] = extension_loaded($extension)); - } - - /** - * Assigns an ID to each callable attached to a hook/filter. - * - * @since 140422 First documented version. - * - * @param string|callable|mixed $function A string or a callable. - * - * @return string Hook ID for the given `$function`. - * - * @throws \exception If the hook/function is invalid (i.e. it's not possible to generate an ID). - */ - public function hook_id($function) - { - if(is_string($function)) - return $function; - - if(is_object($function)) // Closure. - $function = array($function, ''); - else $function = (array)$function; - - if(is_object($function[0])) - return spl_object_hash($function[0]).$function[1]; - - else if(is_string($function[0])) - return $function[0].'::'.$function[1]; - - throw new \exception(__('Invalid hook.', $this->text_domain)); - } - - /** - * Adds a new hook (works with both actions & filters). - * - * @since 140422 First documented version. - * - * @param string $hook The name of a hook to attach to. - * @param string|callable|mixed $function A string or a callable. - * @param integer $priority Hook priority; defaults to `10`. - * @param integer $accepted_args Max number of args that should be passed to the `$function`. - * - * @return boolean This always returns a `TRUE` value. - */ - public function add_hook($hook, $function, $priority = 10, $accepted_args = 1) - { - $this->hooks[$hook][$priority][$this->hook_id($function)] - = array('function' => $function, 'accepted_args' => (integer)$accepted_args); - return TRUE; // Always returns true. - } - - /** - * Adds a new action hook. - * - * @since 140422 First documented version. - * - * @return boolean This always returns a `TRUE` value. - * - * @see add_hook() - */ - public function add_action() // Simple `add_hook()` alias. - { - return call_user_func_array(array($this, 'add_hook'), func_get_args()); - } - - /** - * Adds a new filter. - * - * @since 140422 First documented version. - * - * @return boolean This always returns a `TRUE` value. - * - * @see add_hook() - */ - public function add_filter() // Simple `add_hook()` alias. - { - return call_user_func_array(array($this, 'add_hook'), func_get_args()); - } - - /** - * Removes a hook (works with both actions & filters). - * - * @since 140422 First documented version. - * - * @param string $hook The name of a hook to remove. - * @param string|callable|mixed $function A string or a callable. - * @param integer $priority Hook priority; defaults to `10`. - * - * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. - */ - public function remove_hook($hook, $function, $priority = 10) - { - if(!isset($this->hooks[$hook][$priority][$this->hook_id($function)])) - return FALSE; // Nothing to remove in this case. - - unset($this->hooks[$hook][$priority][$this->hook_id($function)]); - if(!$this->hooks[$hook][$priority]) unset($this->hooks[$hook][$priority]); - return TRUE; // Existed before it was removed in this case. - } - - /** - * Removes an action. - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. - * - * @see remove_hook() - */ - public function remove_action() // Simple `remove_hook()` alias. - { - return call_user_func_array(array($this, 'remove_hook'), func_get_args()); - } - - /** - * Removes a filter. - * - * @since 140422 First documented version. - * - * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. - * - * @see remove_hook() - */ - public function remove_filter() // Simple `remove_hook()` alias. - { - return call_user_func_array(array($this, 'remove_hook'), func_get_args()); - } - - /** - * Runs any callables attached to an action. - * - * @since 140422 First documented version. - */ - public function do_action($hook) - { - if(empty($this->hooks[$hook])) - return; // No hooks. - - $hook_actions = $this->hooks[$hook]; - ksort($hook_actions); // Sort by priority. - - $args = func_get_args(); // We'll need these below. - foreach($hook_actions as $_hook_action) foreach($_hook_action as $_action) - { - if(!isset($_action['function'], $_action['accepted_args'])) - continue; // Not a valid filter in this case. - - call_user_func_array($_action['function'], array_slice($args, 1, $_action['accepted_args'])); - } - unset($_hook_action, $_action); // Housekeeping. - } - - /** - * Runs any callables attached to a filter. - * - * @since 140422 First documented version. - * - * @param string $hook The name of a filter hook. - * @param mixed $value The value to filter. - * - * @return mixed The filtered `$value`. - */ - public function apply_filters($hook, $value) - { - if(empty($this->hooks[$hook])) - return $value; // No hooks. - - $hook_filters = $this->hooks[$hook]; - ksort($hook_filters); // Sort by priority. - - $args = func_get_args(); // We'll need these below. - foreach($hook_filters as $_hook_filter) foreach($_hook_filter as $_filter) - { - if(!isset($_filter['function'], $_filter['accepted_args'])) - continue; // Not a valid filter in this case. - - $args[1] = $value; // Continously update the argument `$value`. - $value = call_user_func_array($_filter['function'], array_slice($args, 1, $_filter['accepted_args'])); - } - unset($_hook_filter, $_filter); // Housekeeping. - - return $value; // With applied filters. - } - - /** - * Apache `.htaccess` rules that deny public access to the contents of a directory. - * - * @since 140422 First documented version. - * - * @var string `.htaccess` fules. - */ - public $htaccess_deny = "\n\tRequire all denied\n\n\n\tdeny from all\n"; } /** diff --git a/quick-cache-pro/includes/auto-cache.php b/quick-cache-pro/includes/auto-cache.php index 0121ca40..60208bc8 100644 --- a/quick-cache-pro/includes/auto-cache.php +++ b/quick-cache-pro/includes/auto-cache.php @@ -28,6 +28,7 @@ class auto_cache public function __construct() { $this->plugin = plugin(); + $this->run(); // Run! } /** @@ -45,7 +46,7 @@ public function run() if(!$this->plugin->options['auto_cache_other_urls']) return; // Nothing to do. - $cache_dir = $this->plugin->abspath_to($this->plugin->cache_sub_dir); + $cache_dir = $this->plugin->cache_dir(); if(!is_dir($cache_dir) || !is_writable($cache_dir)) return; // Not possible in this case. @@ -94,7 +95,7 @@ protected function auto_cache_url($url) return; // We're NOT caching URLs with a query string. $cache_path = $this->plugin->url_to_cache_path($url); - $cache_file_path = $this->plugin->abspath_to($this->plugin->cache_sub_dir.'/'.$cache_path); + $cache_file_path = $this->plugin->cache_dir($cache_path); if(is_file($cache_file_path)) // If it's already cached (and still fresh); just bypass silently. if(filemtime($cache_file_path) >= strtotime('-'.$this->plugin->options['cache_max_age'])) @@ -114,7 +115,7 @@ protected function auto_cache_url($url) */ protected function log_auto_cache_url($url, $wp_remote_get_response) { - $cache_dir = $this->plugin->abspath_to($this->plugin->cache_sub_dir); + $cache_dir = $this->plugin->cache_dir(); $auto_cache_log_file = $cache_dir.'/auto-cache.log'; if(is_file($auto_cache_log_file) && !is_writable($auto_cache_log_file)) @@ -139,7 +140,7 @@ protected function log_auto_cache_url($url, $wp_remote_get_response) */ protected function log_auto_cache_run($total_urls, $total_time) { - $cache_dir = $this->plugin->abspath_to($this->plugin->cache_sub_dir); + $cache_dir = $this->plugin->cache_dir(); $auto_cache_log_file = $cache_dir.'/auto-cache.log'; if(is_file($auto_cache_log_file) && !is_writable($auto_cache_log_file)) diff --git a/quick-cache-pro/includes/menu-pages.php b/quick-cache-pro/includes/menu-pages.php index 46ad2e80..7a47ebd2 100644 --- a/quick-cache-pro/includes/menu-pages.php +++ b/quick-cache-pro/includes/menu-pages.php @@ -6,6 +6,13 @@ class menu_pages // Plugin options. { + protected $plugin; // Set by constructor. + + public function __construct() + { + $this->plugin = plugin(); + } + public function options() { echo '
'."\n"; if(is_multisite()) // Wipes entire cache (e.g. this clears ALL sites in a network). - echo ' '."\n"; + ' '.__('Wipe', $this->plugin->text_domain).' '."\n"; - echo ' '."\n"; + ' '.__('Clear', $this->plugin->text_domain).' '."\n"; echo ' '."\n"; + ' '.__('Restore', $this->plugin->text_domain).' '."\n"; - echo '
'."\n"; + echo '
'."\n"; echo ' '."\n"; echo ' '."\n"; echo '
'."\n"; echo ' '."\n"; - echo ' '.esc_attr(__('Plugin Options', plugin()->text_domain)).''."\n"; + echo ' '.esc_attr(__('Plugin Options', $this->plugin->text_domain)).''."\n"; echo '
'."\n"; if(!empty($_REQUEST[__NAMESPACE__.'__updated'])) // Options updated successfully? { echo '
'."\n"; - echo ' '.__('Options updated successfully.', plugin()->text_domain)."\n"; + echo ' '.__('Options updated successfully.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__restored'])) // Restored default options? { echo '
'."\n"; - echo ' '.__('Default options successfully restored.', plugin()->text_domain)."\n"; + echo ' '.__('Default options successfully restored.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__cache_wiped'])) { echo '
'."\n"; - echo ' '.__('Cache wiped across all sites; recreation will occur automatically over time.', plugin()->text_domain)."\n"; + echo ' '.__('Cache wiped across all sites; recreation will occur automatically over time.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__cache_cleared'])) { echo '
'."\n"; - echo ' '.__('Cache cleared for this site; recreation will occur automatically over time.', plugin()->text_domain)."\n"; + echo ' '.__('Cache cleared for this site; recreation will occur automatically over time.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__wp_config_wp_cache_add_failure'])) { echo '
'."\n"; - echo ' '.__('Failed to update your /wp-config.php file automatically. Please add the following line to your /wp-config.php file (right after the opening <?php tag; on it\'s own line).
<?php
define(\'WP_CACHE\', TRUE);
', plugin()->text_domain)."\n"; + echo ' '.__('Failed to update your /wp-config.php file automatically. Please add the following line to your /wp-config.php file (right after the opening <?php tag; on it\'s own line).
<?php
define(\'WP_CACHE\', TRUE);
', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__wp_config_wp_cache_remove_failure'])) { echo '
'."\n"; - echo ' '.__('Failed to update your /wp-config.php file automatically. Please remove the following line from your /wp-config.php file, or set WP_CACHE to a FALSE value.
define(\'WP_CACHE\', TRUE);
', plugin()->text_domain)."\n"; + echo ' '.__('Failed to update your /wp-config.php file automatically. Please remove the following line from your /wp-config.php file, or set WP_CACHE to a FALSE value.
define(\'WP_CACHE\', TRUE);
', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__advanced_cache_add_failure'])) { echo '
'."\n"; if($_REQUEST[__NAMESPACE__.'__advanced_cache_add_failure'] === 'qc-advanced-cache') - echo ' '.sprintf(__('Failed to update your /wp-content/advanced-cache.php file. Cannot write stat file: %1$s/qc-advanced-cache. Please be sure this directory exists (and that it\'s writable): %1$s. Please use directory permissions 755 or higher (perhaps 777). Once you\'ve done this, please try again.', plugin()->text_domain), esc_html(plugin()->abspath_to(plugin()->cache_sub_dir)))."\n"; - else echo ' '.__('Failed to update your /wp-content/advanced-cache.php file. Most likely a permissions error. Please create an empty file here: /wp-content/advanced-cache.php (just an empty PHP file, with nothing in it); give it permissions 644 or higher (perhaps 666). Once you\'ve done this, please try again.', plugin()->text_domain)."\n"; + echo ' '.sprintf(__('Failed to update your /wp-content/advanced-cache.php file. Cannot write stat file: %1$s/qc-advanced-cache. Please be sure this directory exists (and that it\'s writable): %1$s. Please use directory permissions 755 or higher (perhaps 777). Once you\'ve done this, please try again.', $this->plugin->text_domain), esc_html($this->plugin->cache_dir()))."\n"; + else echo ' '.__('Failed to update your /wp-content/advanced-cache.php file. Most likely a permissions error. Please create an empty file here: /wp-content/advanced-cache.php (just an empty PHP file, with nothing in it); give it permissions 644 or higher (perhaps 666). Once you\'ve done this, please try again.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } if(!empty($_REQUEST[__NAMESPACE__.'__advanced_cache_remove_failure'])) { echo '
'."\n"; - echo ' '.__('Failed to remove your /wp-content/advanced-cache.php file. Most likely a permissions error. Please delete (or empty the contents of) this file: /wp-content/advanced-cache.php.', plugin()->text_domain)."\n"; + echo ' '.__('Failed to remove your /wp-content/advanced-cache.php file. Most likely a permissions error. Please delete (or empty the contents of) this file: /wp-content/advanced-cache.php.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } - if(!plugin()->options['enable']) // Not enabled yet? + if(!$this->plugin->options['enable']) // Not enabled yet? { echo '
'."\n"; - echo ' '.__('Quick Cache is currently disabled; please review options below.', plugin()->text_domain)."\n"; + echo ' '.__('Quick Cache is currently disabled; please review options below.', $this->plugin->text_domain)."\n"; echo '
'."\n"; } echo '
'."\n"; echo '
'."\n"; - echo '
'."\n"; - echo ' '.__('Enable/Disable', plugin()->text_domain)."\n"; + echo '
'."\n"; + echo ' '.__('Enable/Disable', $this->plugin->text_domain)."\n"; echo '
'."\n"; - echo '
'."\n"; + echo '
'."\n"; echo '

Quick Cache = SPEED!!

'."\n"; - echo '

   

'."\n"; + echo '

   

'."\n"; echo '
'."\n"; - echo '

'.__('HUGE Time-Saver: Approx. 95% of all WordPress sites running Quick Cache, simply enable it here; and that\'s it :-) No further configuration is necessary (really). All of the other options (down below) are already tuned for the BEST performance on a typical WordPress installation. Simply enable Quick Cache here and click "Save All Changes". If you get any warnings please follow the instructions given. Otherwise, you\'re good . This plugin is designed to run just fine like it is. Take it for a spin right away; you can always fine-tune things later if you deem necessary.', plugin()->text_domain).'

'."\n"; + echo '

'.__('HUGE Time-Saver: Approx. 95% of all WordPress sites running Quick Cache, simply enable it here; and that\'s it :-) No further configuration is necessary (really). All of the other options (down below) are already tuned for the BEST performance on a typical WordPress installation. Simply enable Quick Cache here and click "Save All Changes". If you get any warnings please follow the instructions given. Otherwise, you\'re good . This plugin is designed to run just fine like it is. Take it for a spin right away; you can always fine-tune things later if you deem necessary.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; - echo ' '."\n"; - echo '

'.__('How Can I Tell Quick Cache is Working?', plugin()->text_domain).'

'."\n"; - echo '

'.__('First of all, please make sure that you\'ve enabled Quick Cache here; then scroll down to the bottom of this page and click "Save All Changes". All of the other options (below) are already pre-configured for typical usage. Feel free to skip them all for now. You can go back through all of these later and fine-tune things the way you like them.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Once Quick Cache has been enabled, you\'ll need to log out (and/or clear browser cookies). By default, cache files are NOT served to visitors who are logged-in, and that includes you too ;-) Cache files are NOT served to recent comment authors either. If you\'ve commented (or replied to a comment lately); please clear your browser cookies before testing.', plugin()->text_domain).'

'."\n"; - echo '

'.__('To verify that Quick Cache is working, navigate your site like a normal visitor would. Right-click on any page (choose View Source), then scroll to the very bottom of the document. At the bottom, you\'ll find comments that show Quick Cache stats and information. You should also notice that page-to-page navigation is lightning fast now that Quick Cache is running; and it gets faster over time!', plugin()->text_domain).'

'."\n"; + echo ' '."\n"; + echo '

'.__('How Can I Tell Quick Cache is Working?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('First of all, please make sure that you\'ve enabled Quick Cache here; then scroll down to the bottom of this page and click "Save All Changes". All of the other options (below) are already pre-configured for typical usage. Feel free to skip them all for now. You can go back through all of these later and fine-tune things the way you like them.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Once Quick Cache has been enabled, you\'ll need to log out (and/or clear browser cookies). By default, cache files are NOT served to visitors who are logged-in, and that includes you too ;-) Cache files are NOT served to recent comment authors either. If you\'ve commented (or replied to a comment lately); please clear your browser cookies before testing.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('To verify that Quick Cache is working, navigate your site like a normal visitor would. Right-click on any page (choose View Source), then scroll to the very bottom of the document. At the bottom, you\'ll find comments that show Quick Cache stats and information. You should also notice that page-to-page navigation is lightning fast now that Quick Cache is running; and it gets faster over time!', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; echo '
'."\n"; @@ -129,16 +136,16 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Deactivation Safeguards', plugin()->text_domain)."\n"; + echo ' '.__('Deactivation Safeguards', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Uninstall on Deactivation; or Safeguard Options?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Tip: By default, if you deactivate Quick Cache from the plugins menu in WordPress; nothing is lost. However, if you want to uninstall Quick Cache you should set this to Yes and THEN deactivate it from the plugins menu in WordPress. This way Quick Cache will erase your options for the plugin, clear the cache, remove the advanced-cache.php file, terminate CRON jobs, etc. It erases itself from existence completely.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Uninstall on Deactivation; or Safeguard Options?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Tip: By default, if you deactivate Quick Cache from the plugins menu in WordPress; nothing is lost. However, if you want to uninstall Quick Cache you should set this to Yes and THEN deactivate it from the plugins menu in WordPress. This way Quick Cache will erase your options for the plugin, clear the cache, remove the advanced-cache.php file, terminate CRON jobs, etc. It erases itself from existence completely.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; echo '
'."\n"; @@ -147,71 +154,71 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Clearing the Cache', plugin()->text_domain)."\n"; + echo ' '.__('Clearing the Cache', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('Clearing the Cache (Manually)', plugin()->text_domain).'

'."\n"; - echo ' '."\n"; - echo '

'.__('Once Quick Cache is enabled, you will find this new option in your WordPress Admin Bar (see screenshot on right). Clicking this button will clear the cache and you can start fresh at anytime (e.g. you can do this manually; and as often as you wish).', plugin()->text_domain).'

'."\n"; - echo '

'.__('Depending on the structure of your site, there could be many reasons to clear the cache. However, the most common reasons are related to Post/Page edits or deletions, Category/Tag edits or deletions, and Theme changes. Quick Cache handles most scenarios all by itself. However, many site owners like to clear the cache manually; for a variety of reasons (just to force a refresh).', plugin()->text_domain).'

'."\n"; + echo '

'.__('Clearing the Cache (Manually)', $this->plugin->text_domain).'

'."\n"; + echo ' '."\n"; + echo '

'.__('Once Quick Cache is enabled, you will find this new option in your WordPress Admin Bar (see screenshot on right). Clicking this button will clear the cache and you can start fresh at anytime (e.g. you can do this manually; and as often as you wish).', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Depending on the structure of your site, there could be many reasons to clear the cache. However, the most common reasons are related to Post/Page edits or deletions, Category/Tag edits or deletions, and Theme changes. Quick Cache handles most scenarios all by itself. However, many site owners like to clear the cache manually; for a variety of reasons (just to force a refresh).', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Running the s2Clean Theme by WebSharks?', plugin()->text_domain).'

'."\n"; - echo '

'.__('If s2Clean is installed, Quick Cache can be configured to clear the Markdown cache too (if you\'ve enabled Markdown processing with s2Clean). The s2Clean Markdown cache is only cleared when you manually clear the cache (with Quick Cache); and only if you enable this option here. Note: s2Clean\'s Markdown cache is extremely dynamic. Just like the rest of your site, s2Clean caches do NOT need to be cleared away at all, as this happens automatically when your content changes. However, some developers find this feature useful while developing their site; just to force a refresh.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Running the s2Clean Theme by WebSharks?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('If s2Clean is installed, Quick Cache can be configured to clear the Markdown cache too (if you\'ve enabled Markdown processing with s2Clean). The s2Clean Markdown cache is only cleared when you manually clear the cache (with Quick Cache); and only if you enable this option here. Note: s2Clean\'s Markdown cache is extremely dynamic. Just like the rest of your site, s2Clean caches do NOT need to be cleared away at all, as this happens automatically when your content changes. However, some developers find this feature useful while developing their site; just to force a refresh.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Process Other Custom PHP Code?', plugin()->text_domain).'

'."\n"; - echo '

'.__('If you have other custom routines you\'d like to process when the cache is cleared manually, please type your custom PHP code here. The PHP code that you provide is only evaluated when you manually clear the cache (with Quick Cache); and only if the field below contains PHP code. Note: if your PHP code outputs a message (e.g. if you have echo \'<p>My message</p>\';); your message will be displayed along with any other notes from Quick Cache itself. This could be useful to developers that need to clear server caches too (such as APC or memcache).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Example: <?php apc_clear_cache(); echo \'<p>Also cleared APC cache.</p>\'; ?>', plugin()->text_domain).'

'."\n"; + echo '

'.__('Process Other Custom PHP Code?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('If you have other custom routines you\'d like to process when the cache is cleared manually, please type your custom PHP code here. The PHP code that you provide is only evaluated when you manually clear the cache (with Quick Cache); and only if the field below contains PHP code. Note: if your PHP code outputs a message (e.g. if you have echo \'<p>My message</p>\';); your message will be displayed along with any other notes from Quick Cache itself. This could be useful to developers that need to clear server caches too (such as APC or memcache).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Example: <?php apc_clear_cache(); echo \'<p>Also cleared APC cache.</p>\'; ?>', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; - echo '

'.__('Purging the Cache (Automatically)', plugin()->text_domain).'

'."\n"; - echo ' '."\n"; - echo '

'.__('This is built into the Quick Cache plugin; e.g. this functionality is "always on". If you edit a Post/Page (or delete one), Quick Cache will automatically purge the cache file(s) associated with that content. This way a new updated version of the cache will be created automatically the next time this content is accessed. Simple updates like this occur each time you make changes in the Dashboard, and Quick Cache will notify you of these as they occur. Quick Cache monitors changes to Posts (of any kind, including Pages), Categories, Tags, Links, Themes (even Users); and more. Notifications in the Dashboard regarding these detections can be enabled/disabled below.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Purging the Cache (Automatically)', $this->plugin->text_domain).'

'."\n"; + echo ' '."\n"; + echo '

'.__('This is built into the Quick Cache plugin; e.g. this functionality is "always on". If you edit a Post/Page (or delete one), Quick Cache will automatically purge the cache file(s) associated with that content. This way a new updated version of the cache will be created automatically the next time this content is accessed. Simple updates like this occur each time you make changes in the Dashboard, and Quick Cache will notify you of these as they occur. Quick Cache monitors changes to Posts (of any kind, including Pages), Categories, Tags, Links, Themes (even Users); and more. Notifications in the Dashboard regarding these detections can be enabled/disabled below.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge Designated "Home Page" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('On many sites, the Home Page (aka: the Front Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the "Home Page"?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge Designated "Home Page" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('On many sites, the Home Page (aka: the Front Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the "Home Page"?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge Designated "Posts Page" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('On many sites, the Posts Page (aka: the Blog Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the "Posts Page"?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge Designated "Posts Page" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('On many sites, the Posts Page (aka: the Blog Page) offers an archive view of all Posts (or even Pages). Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the "Posts Page"?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge "Author Page" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('On many sites, each author has a related "Author Page" that offers an archive view of all posts associated with that author. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the related "Author Page"?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge "Author Page" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('On many sites, each author has a related "Author Page" that offers an archive view of all posts associated with that author. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the related "Author Page"?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge "Category Archives" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('On many sites, each post is associated with at least one Category. Each category then has an archive view that contains all the posts within that category. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Category archive views?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge "Category Archives" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('On many sites, each post is associated with at least one Category. Each category then has an archive view that contains all the posts within that category. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Category archive views?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge "Tag Archives" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('On many sites, each post may be associated with at least one Tag. Each tag then has an archive view that contains all the posts assigned that tag. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Tag archive views?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge "Tag Archives" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('On many sites, each post may be associated with at least one Tag. Each tag then has an archive view that contains all the posts assigned that tag. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Tag archive views?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Auto-Purge "Custom Term Archives" Too?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Most sites do not use any custom Terms so it should be safe to leave this disabled. However, if your site uses custom Terms and they have their own Term archive views, you may want to clear those when the associated post is cleared. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Tag archive views?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Purge "Custom Term Archives" Too?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Most sites do not use any custom Terms so it should be safe to leave this disabled. However, if your site uses custom Terms and they have their own Term archive views, you may want to clear those when the associated post is cleared. Therefore, if a single Post/Page is changed in some way; and Quick Cache purges/resets the cache for a single Post/Page, would you like Quick Cache to also purge any existing cache files for the associated Tag archive views?', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; echo '
'."\n"; @@ -220,22 +227,22 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Directory / Expiration Time', plugin()->text_domain)."\n"; + echo ' '.__('Directory / Expiration Time', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('Base Cache Directory (Must be Writable; e.g. Permissions 755 or Higher)', plugin()->text_domain).'

'."\n"; - echo '

'.__('This is where Quick Cache will store the cached version of your site. If you\'re not sure how to deal with directory permissions, don\'t worry too much about this. If there is a problem, Quick Cache will let you know about it. By default, this directory is created by Quick Cache and the permissions are setup automatically. In most cases there is nothing more you need to do.', plugin()->text_domain).'

'."\n"; - echo '
'.esc_html(ABSPATH).'/
'."\n"; + echo '

'.__('Base Cache Directory (Must be Writable; e.g. Permissions 755 or Higher)', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('This is where Quick Cache will store the cached version of your site. If you\'re not sure how to deal with directory permissions, don\'t worry too much about this. If there is a problem, Quick Cache will let you know about it. By default, this directory is created by Quick Cache and the permissions are setup automatically. In most cases there is nothing more you need to do.', $this->plugin->text_domain).'

'."\n"; + echo '
'.esc_html(WP_CONTENT_DIR).'/
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Automatic Expiration Time (Max Age)', plugin()->text_domain).'

'."\n"; - echo '

'.__('If you don\'t update your site much, you could set this to 6 months and optimize everything even further. The longer the Cache Expiration Time is, the greater your performance gain. Alternatively, the shorter the Expiration Time, the fresher everything will remain on your site. A default value of 7 days (recommended); is a good conservative middle-ground.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Keep in mind that your Expiration Time is only one part of the big picture. Quick Cache will also purge the cache automatically as changes are made to the site (i.e. you edit a post, someone comments on a post, you change your theme, you add a new navigation menu item, etc., etc.). Thus, your Expiration Time is really just a fallback; e.g. the maximum amount of time that a cache file could ever possibly live.', plugin()->text_domain).'

'."\n"; - echo '

'.__('All of that being said, you could set this to just 60 seconds and you would still see huge differences in speed and performance. If you\'re just starting out with Quick Cache (perhaps a bit nervous about old cache files being served to your visitors); you could set this to something like 30 minutes, and experiment with it while you build confidence in Quick Cache. It\'s not necessary to do so, but many site owners have reported this makes them feel like they\'re more-in-control when the cache has a short expiration time. All-in-all, it\'s a matter of preference .', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Tip: the value that you specify here MUST be compatible with PHP\'s strtotime() function. Examples: 30 seconds, 2 hours, 7 days, 6 months, 1 year.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: Quick Cache will never serve a cache file that is older than what you specify here (even if one exists in your cache directory; stale cache files are never used). In addition, a WP Cron job will automatically cleanup your cache directory (once daily); purging expired cache files periodically. This prevents a HUGE cache from building up over time, creating a potential storage issue.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Automatic Expiration Time (Max Age)', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('If you don\'t update your site much, you could set this to 6 months and optimize everything even further. The longer the Cache Expiration Time is, the greater your performance gain. Alternatively, the shorter the Expiration Time, the fresher everything will remain on your site. A default value of 7 days (recommended); is a good conservative middle-ground.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Keep in mind that your Expiration Time is only one part of the big picture. Quick Cache will also purge the cache automatically as changes are made to the site (i.e. you edit a post, someone comments on a post, you change your theme, you add a new navigation menu item, etc., etc.). Thus, your Expiration Time is really just a fallback; e.g. the maximum amount of time that a cache file could ever possibly live.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('All of that being said, you could set this to just 60 seconds and you would still see huge differences in speed and performance. If you\'re just starting out with Quick Cache (perhaps a bit nervous about old cache files being served to your visitors); you could set this to something like 30 minutes, and experiment with it while you build confidence in Quick Cache. It\'s not necessary to do so, but many site owners have reported this makes them feel like they\'re more-in-control when the cache has a short expiration time. All-in-all, it\'s a matter of preference .', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Tip: the value that you specify here MUST be compatible with PHP\'s strtotime() function. Examples: 30 seconds, 2 hours, 7 days, 6 months, 1 year.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: Quick Cache will never serve a cache file that is older than what you specify here (even if one exists in your cache directory; stale cache files are never used). In addition, a WP Cron job will automatically cleanup your cache directory (once daily); purging expired cache files periodically. This prevents a HUGE cache from building up over time, creating a potential storage issue.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -243,22 +250,22 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Client-Side Cache', plugin()->text_domain)."\n"; + echo ' '.__('Client-Side Cache', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Allow Double-Caching In The Client-Side Browser?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Recommended setting: No (for membership sites, very important). Otherwise, Yes would be better (if users do NOT log in/out of your site).', plugin()->text_domain).'

'."\n"; - echo '

'.__('Quick Cache handles content delivery through its ability to communicate with a browser using PHP. If you allow a browser to (cache) the caching system itself, you are momentarily losing some control; and this can have a negative impact on users that see more than one version of your site; e.g. one version while logged-in, and another while NOT logged-in. For instance, a user may log out of your site, but upon logging out they report seeing pages on the site which indicate they are STILL logged in (even though they\'re not — that\'s bad). This can happen if you allow a client-side cache, because their browser may cache web pages they visited while logged into your site which persist even after logging out. Sending no-cache headers will work to prevent this issue.', plugin()->text_domain).'

'."\n"; - echo '

'.__('All of that being said, if all you care about is blazing fast speed and users don\'t log in/out of your site (only you do); you can safely set this to Yes (recommended in this case). Allowing a client-side browser cache will improve speed and reduce outgoing bandwidth when this option is feasible.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Allow Double-Caching In The Client-Side Browser?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Recommended setting: No (for membership sites, very important). Otherwise, Yes would be better (if users do NOT log in/out of your site).', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Quick Cache handles content delivery through its ability to communicate with a browser using PHP. If you allow a browser to (cache) the caching system itself, you are momentarily losing some control; and this can have a negative impact on users that see more than one version of your site; e.g. one version while logged-in, and another while NOT logged-in. For instance, a user may log out of your site, but upon logging out they report seeing pages on the site which indicate they are STILL logged in (even though they\'re not — that\'s bad). This can happen if you allow a client-side cache, because their browser may cache web pages they visited while logged into your site which persist even after logging out. Sending no-cache headers will work to prevent this issue.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('All of that being said, if all you care about is blazing fast speed and users don\'t log in/out of your site (only you do); you can safely set this to Yes (recommended in this case). Allowing a client-side browser cache will improve speed and reduce outgoing bandwidth when this option is feasible.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Tip: Setting this to No is highly recommended when running a membership plugin like s2Member (as one example). In fact, many plugins like s2Member will send nocache_headers() on their own, so your configuration here will likely be overwritten when you run such plugins (which is better anyway). In short, if you run a membership plugin, you should NOT allow a client-side browser cache.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Tip: Setting this to No will NOT impact static content; e.g. CSS, JS, images, or other media. This setting pertains only to dynamic PHP scripts which produce content generated by WordPress.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Advanced Tip: if you have this set to No, but you DO want to allow a few special URLs to be cached by the browser; you can add this parameter to your URL ?qcABC=1. This tells Quick Cache that it\'s OK for the browser to cache that particular URL. In other words, the qcABC=1 parameter tells Quick Cache NOT to send no-cache headers to the browser.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Tip: Setting this to No is highly recommended when running a membership plugin like s2Member (as one example). In fact, many plugins like s2Member will send nocache_headers() on their own, so your configuration here will likely be overwritten when you run such plugins (which is better anyway). In short, if you run a membership plugin, you should NOT allow a client-side browser cache.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Tip: Setting this to No will NOT impact static content; e.g. CSS, JS, images, or other media. This setting pertains only to dynamic PHP scripts which produce content generated by WordPress.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Advanced Tip: if you have this set to No, but you DO want to allow a few special URLs to be cached by the browser; you can add this parameter to your URL ?qcABC=1. This tells Quick Cache that it\'s OK for the browser to cache that particular URL. In other words, the qcABC=1 parameter tells Quick Cache NOT to send no-cache headers to the browser.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -266,22 +273,22 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Logged-In Users', plugin()->text_domain)."\n"; + echo ' '.__('Logged-In Users', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Caching Enabled for Logged-In Users & Comment Authors?', plugin()->text_domain).'

'."\n"; - echo '

'.__('This should almost ALWAYS be set to No. Most sites will NOT want to cache content generated while a user is logged-in. Doing so could result in a cache of dynamic content generated specifically for a particular user, where the content being cached may contain details that pertain only to the user that was logged-in when the cache was generated. Imagine visiting a website that says you\'re logged-in as Billy Bob (but you\'re not Billy Bob; NOT good). In short, do NOT turn this on unless you know what you\'re doing.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Caching Enabled for Logged-In Users & Comment Authors?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('This should almost ALWAYS be set to No. Most sites will NOT want to cache content generated while a user is logged-in. Doing so could result in a cache of dynamic content generated specifically for a particular user, where the content being cached may contain details that pertain only to the user that was logged-in when the cache was generated. Imagine visiting a website that says you\'re logged-in as Billy Bob (but you\'re not Billy Bob; NOT good). In short, do NOT turn this on unless you know what you\'re doing.', $this->plugin->text_domain).'

'."\n"; echo ' '."\n"; - echo '

'.__('Exception (Membership Sites): If you run a site with many users and the majority of your traffic comes from users who ARE logged-in, please choose: Yes (maintain separate cache). Quick Cache will operate normally; but when a user is logged-in, the cache is user-specific. Quick Cache will intelligently refresh the cache when/if a user submits a form on your site with the GET or POST method. Or, if you make changes to their account (or another plugin makes changes to their account); including user option|meta additions, updates & deletions too. However, please note that enabling this feature (e.g. user-specific cache entries); will eat up MUCH more disk space. That being said, the benefits of this feature for most sites will outweigh the disk overhead (e.g. it\'s NOT an issue in most cases). Unless you are short on disk space (or you have MANY thousands of users), the disk overhead is neglible.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Exception (Membership Sites): If you run a site with many users and the majority of your traffic comes from users who ARE logged-in, please choose: Yes (maintain separate cache). Quick Cache will operate normally; but when a user is logged-in, the cache is user-specific. Quick Cache will intelligently refresh the cache when/if a user submits a form on your site with the GET or POST method. Or, if you make changes to their account (or another plugin makes changes to their account); including user option|meta additions, updates & deletions too. However, please note that enabling this feature (e.g. user-specific cache entries); will eat up MUCH more disk space. That being said, the benefits of this feature for most sites will outweigh the disk overhead (e.g. it\'s NOT an issue in most cases). Unless you are short on disk space (or you have MANY thousands of users), the disk overhead is neglible.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Note: For most sites, the majority of their traffic (if not all of their traffic) comes from visitors who are not logged in, so disabling the cache for logged-in users is NOT ordinarily a performance issue. When a user IS logged-in, disabling the cache is considered ideal, because a logged-in user has a session open with your site; and the content they view should remain very dynamic in this scenario.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: This setting includes some users who AREN\'T actually logged into the system, but who HAVE authored comments recently. Quick Cache includes comment authors as part of it\'s logged-in user check. This way comment authors will be able to see updates to the comment thread immediately; and, so that any dynamically-generated messages displayed by your theme will work as intended. In short, Quick Cache thinks of a comment author as a logged-in user, even though technically they are not. ~ Users who gain access to password-protected Posts/Pages are also included.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Note: For most sites, the majority of their traffic (if not all of their traffic) comes from visitors who are not logged in, so disabling the cache for logged-in users is NOT ordinarily a performance issue. When a user IS logged-in, disabling the cache is considered ideal, because a logged-in user has a session open with your site; and the content they view should remain very dynamic in this scenario.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: This setting includes some users who AREN\'T actually logged into the system, but who HAVE authored comments recently. Quick Cache includes comment authors as part of it\'s logged-in user check. This way comment authors will be able to see updates to the comment thread immediately; and, so that any dynamically-generated messages displayed by your theme will work as intended. In short, Quick Cache thinks of a comment author as a logged-in user, even though technically they are not. ~ Users who gain access to password-protected Posts/Pages are also included.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -289,19 +296,19 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('GET Requests', plugin()->text_domain)."\n"; + echo ' '.__('GET Requests', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Caching Enabled for GET (Query String) Requests?', plugin()->text_domain).'

'."\n"; - echo '

'.__('This should almost ALWAYS be set to No. UNLESS, you\'re using unfriendly Permalinks. In other words, if all of your URLs contain a query string (e.g. /?key=value); you\'re using unfriendly Permalinks. Ideally, you would refrain from doing this; and instead, update your Permalink options immediately; which also optimizes your site for search engines. That being said, if you really want to use unfriendly Permalinks, and ONLY if you\'re using unfriendly Permalinks, you should set this to Yes; and don\'t worry too much, the sky won\'t fall on your head :-)', plugin()->text_domain).'

'."\n"; + echo '

'.__('Caching Enabled for GET (Query String) Requests?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('This should almost ALWAYS be set to No. UNLESS, you\'re using unfriendly Permalinks. In other words, if all of your URLs contain a query string (e.g. /?key=value); you\'re using unfriendly Permalinks. Ideally, you would refrain from doing this; and instead, update your Permalink options immediately; which also optimizes your site for search engines. That being said, if you really want to use unfriendly Permalinks, and ONLY if you\'re using unfriendly Permalinks, you should set this to Yes; and don\'t worry too much, the sky won\'t fall on your head :-)', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Note: POST requests (i.e. forms with method="post") are always excluded from the cache, which is the way it should be. Any POST/PUT/DELETE request should NEVER (ever) be cached. CLI (and self-serve) requests are also excluded from the cache (always). A CLI request is one that comes from the command line; commonly used by CRON jobs and other automated routines. A self-serve request is an HTTP connection established from your site -› to your site. For instance, a WP Cron job, or any other HTTP request that is spawned not by a user, but by the server itself.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Advanced Tip: If you are NOT caching GET requests (recommended), but you DO want to allow some special URLs that include query string parameters to be cached; you can add this special parameter to any URL ?qcAC=1. This tells Quick Cache that it\'s OK to cache that particular URL, even though it contains query string arguments.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Note: POST requests (i.e. forms with method="post") are always excluded from the cache, which is the way it should be. Any POST/PUT/DELETE request should NEVER (ever) be cached. CLI (and self-serve) requests are also excluded from the cache (always). A CLI request is one that comes from the command line; commonly used by CRON jobs and other automated routines. A self-serve request is an HTTP connection established from your site -› to your site. For instance, a WP Cron job, or any other HTTP request that is spawned not by a user, but by the server itself.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Advanced Tip: If you are NOT caching GET requests (recommended), but you DO want to allow some special URLs that include query string parameters to be cached; you can add this special parameter to any URL ?qcAC=1. This tells Quick Cache that it\'s OK to cache that particular URL, even though it contains query string arguments.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -309,19 +316,19 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('404 Requests', plugin()->text_domain)."\n"; + echo ' '.__('404 Requests', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Caching Enabled for 404 Requests?', plugin()->text_domain).'

'."\n"; - echo '

'.__('When this is set to No, Quick Cache will ignore all 404 requests and no cache file will be served. While this is fine for most site owners, caching the 404 page on a high-traffic site may further reduce server load. When this is set to Yes, Quick Cache will cache the 404 page (see Creating an Error 404 Page) and then serve that single cache file to all future 404 requests.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Caching Enabled for 404 Requests?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('When this is set to No, Quick Cache will ignore all 404 requests and no cache file will be served. While this is fine for most site owners, caching the 404 page on a high-traffic site may further reduce server load. When this is set to Yes, Quick Cache will cache the 404 page (see Creating an Error 404 Page) and then serve that single cache file to all future 404 requests.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('How does Quick Cache cache 404 requests? Quick Cache will create a special cache file (----404----.html, see Advanced Tip below) for the first 404 request and then symlink future 404 requests to this special cache file. That way you don\'t end up with lots of 404 cache files that all contain the same thing (the contents of the 404 page). Instead, you\'ll have one 404 cache file and then several symlinks (i.e., references) to that 404 cache file.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Advanced Tip: The default 404 cache filename (----404----.html) is designed to minimize the chance of a collision with a cache file for a real page with the same name. However, if you want to override this default and define your own 404 cache filename, you can do so by adding define(\'QUICK_CACHE_404_CACHE_FILENAME\', \'your-404-cache-filename\'); to your wp-config.php file (note that the .html extension should be excluded when defining a new filename).', plugin()->text_domain).'

'."\n"; + echo '

'.__('How does Quick Cache cache 404 requests? Quick Cache will create a special cache file (----404----.html, see Advanced Tip below) for the first 404 request and then symlink future 404 requests to this special cache file. That way you don\'t end up with lots of 404 cache files that all contain the same thing (the contents of the 404 page). Instead, you\'ll have one 404 cache file and then several symlinks (i.e., references) to that 404 cache file.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Advanced Tip: The default 404 cache filename (----404----.html) is designed to minimize the chance of a collision with a cache file for a real page with the same name. However, if you want to override this default and define your own 404 cache filename, you can do so by adding define(\'QUICK_CACHE_404_CACHE_FILENAME\', \'your-404-cache-filename\'); to your wp-config.php file (note that the .html extension should be excluded when defining a new filename).', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -329,18 +336,18 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('RSS, RDF, and Atom Feeds', plugin()->text_domain)."\n"; + echo ' '.__('RSS, RDF, and Atom Feeds', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Caching Enabled for RSS, RDF, Atom Feeds?', plugin()->text_domain).'

'."\n"; - echo '

'.__('This should almost ALWAYS be set to No. UNLESS, you\'re sure that you want to cache your feeds. If you use a web feed management provider like Google® Feedburner and you set this option to Yes, you may experience delays in the detection of new posts.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Caching Enabled for RSS, RDF, Atom Feeds?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('This should almost ALWAYS be set to No. UNLESS, you\'re sure that you want to cache your feeds. If you use a web feed management provider like Google® Feedburner and you set this option to Yes, you may experience delays in the detection of new posts.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Note: This option affects all feeds served by WordPress, including the site feed, the site comment feed, post-specific comment feeds, author feeds, search feeds, and category and tag feeds. See also: WordPress Feeds.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Note: This option affects all feeds served by WordPress, including the site feed, the site comment feed, post-specific comment feeds, author feeds, search feeds, and category and tag feeds. See also: WordPress Feeds.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -348,15 +355,15 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('URI Exclusion Patterns', plugin()->text_domain)."\n"; + echo ' '.__('URI Exclusion Patterns', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('Don\'t Cache These Special URI Exclusion Patterns?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Sometimes there are certain cases where a particular file, or a particular group of files, should never be cached. This is where you will enter those if you need to (one per line). Searches are performed against the REQUEST_URI; i.e. /path/?query (case sensitive). So, don\'t put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard * character can also be used when necessary; e.g. /category/abc-followed-by-*; (where * = anything, 0 or more characters in length).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Tip: let\'s use this example URL: http://www.example.com/post/example-post-123. To exclude this URL, you would put this line into the field above: /post/example-post-123. Or, you could also just put in a small fragment, like: example or example-*-123 and that would exclude any URI containing that word fragment.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Don\'t Cache These Special URI Exclusion Patterns?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Sometimes there are certain cases where a particular file, or a particular group of files, should never be cached. This is where you will enter those if you need to (one per line). Searches are performed against the REQUEST_URI; i.e. /path/?query (case sensitive). So, don\'t put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard * character can also be used when necessary; e.g. /category/abc-followed-by-*; (where * = anything, 0 or more characters in length).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Tip: let\'s use this example URL: http://www.example.com/post/example-post-123. To exclude this URL, you would put this line into the field above: /post/example-post-123. Or, you could also just put in a small fragment, like: example or example-*-123 and that would exclude any URI containing that word fragment.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -364,15 +371,15 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('HTTP Referrer Exclusion Patterns', plugin()->text_domain)."\n"; + echo ' '.__('HTTP Referrer Exclusion Patterns', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('Don\'t Cache These Special HTTP Referrer Exclusion Patterns?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Sometimes there are special cases where a particular referring URL (or referring domain) that sends you traffic; or even a particular group of referring URLs or domains that send you traffic; should result in a page being loaded on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_REFERER (case sensitive). A wildcard * character can also be used when necessary; e.g. *.domain.com; (where * = anything, 0 or more characters in length).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Tip: let\'s use this example URL: http://www.referring-domain.com/search/?q=search+terms. To exclude this referring URL, you could put this line into the field above: www.referring-domain.com. Or, you could also just put in a small fragment, like: /search/ or q=*; and that would exclude any referrer containing that word fragment.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Don\'t Cache These Special HTTP Referrer Exclusion Patterns?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Sometimes there are special cases where a particular referring URL (or referring domain) that sends you traffic; or even a particular group of referring URLs or domains that send you traffic; should result in a page being loaded on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_REFERER (case sensitive). A wildcard * character can also be used when necessary; e.g. *.domain.com; (where * = anything, 0 or more characters in length).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Tip: let\'s use this example URL: http://www.referring-domain.com/search/?q=search+terms. To exclude this referring URL, you could put this line into the field above: www.referring-domain.com. Or, you could also just put in a small fragment, like: /search/ or q=*; and that would exclude any referrer containing that word fragment.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -380,15 +387,15 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('User-Agent Exclusion Patterns', plugin()->text_domain)."\n"; + echo ' '.__('User-Agent Exclusion Patterns', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('Don\'t Cache These Special User-Agent Exclusion Patterns?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Sometimes there are special cases when a particular user-agent (e.g. a specific browser or a specific type of device); should be shown a page on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_USER_AGENT (case insensitive). A wildcard * character can also be used when necessary; e.g. Android *; Chrome/* Mobile; (where * = anything, 0 or more characters in length).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Tip: if you wanted to exclude iPhones put this line into the field above: iPhone;*AppleWebKit. Or, you could also just put in a small fragment, like: iphone; and that would exclude any user-agent containing that word fragment. Note, this is just an example. With a default installation of Quick Cache, there is no compelling reason to exclude iOS devices (or any mobile device for that matter).', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Don\'t Cache These Special User-Agent Exclusion Patterns?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Sometimes there are special cases when a particular user-agent (e.g. a specific browser or a specific type of device); should be shown a page on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_USER_AGENT (case insensitive). A wildcard * character can also be used when necessary; e.g. Android *; Chrome/* Mobile; (where * = anything, 0 or more characters in length).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Tip: if you wanted to exclude iPhones put this line into the field above: iPhone;*AppleWebKit. Or, you could also just put in a small fragment, like: iphone; and that would exclude any user-agent containing that word fragment. Note, this is just an example. With a default installation of Quick Cache, there is no compelling reason to exclude iOS devices (or any mobile device for that matter).', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -396,29 +403,29 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Auto-Cache Engine', plugin()->text_domain)."\n"; + echo ' '.__('Auto-Cache Engine', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Enable the Auto-Cache Engine?', plugin()->text_domain).'

'."\n"; - echo '

'.__('After using Quick Cache for awhile (or any other page caching plugin, for that matter); it becomes obvious that at some point (based on your configured Expiration Time) Quick Cache has to refresh itself. It does this by ditching its cached version of a page, reloading the database-driven content, and then recreating the cache with the latest data. This is a never ending regeneration cycle that is based entirely on your configured Expiration Time.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Understanding this, you can see that 99% of your visitors are going to receive a lightning fast response from your server. However, there will always be around 1% of your visitors that land on a page for the very first time (before it\'s been cached), or land on a page that needs to have its cache regenerated, because the existing cache has become outdated. We refer to this as a First-Come Slow-Load Issue. Not a huge problem, but if you\'re optimizing your site for every once of speed possible, the Auto-Cache Engine can help with this. The Auto-Cache Engine has been designed to combat this issue by taking on the responsibility of being that first visitor to a page that has not yet been cached, or has an expired cache. The Auto-Cache Engine is powered, in part, by WP-Cron (already built into WordPress). The Auto-Cache Engine runs at 15-minute intervals via WP-Cron. It also uses the WP_Http class, which is also built into WordPress already.', plugin()->text_domain).'

'."\n"; - echo '

'.__('The Auto-Cache Engine obtains its list of URLs to auto-cache, from two different sources. It can read an XML Sitemap and/or a list of specific URLs that you supply. If you supply both sources, it will use both sources collectively. The Auto-Cache Engine takes ALL of your other configuration options into consideration too, including your Expiration Time, as well as any cache exclusion rules.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Enable the Auto-Cache Engine?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('After using Quick Cache for awhile (or any other page caching plugin, for that matter); it becomes obvious that at some point (based on your configured Expiration Time) Quick Cache has to refresh itself. It does this by ditching its cached version of a page, reloading the database-driven content, and then recreating the cache with the latest data. This is a never ending regeneration cycle that is based entirely on your configured Expiration Time.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Understanding this, you can see that 99% of your visitors are going to receive a lightning fast response from your server. However, there will always be around 1% of your visitors that land on a page for the very first time (before it\'s been cached), or land on a page that needs to have its cache regenerated, because the existing cache has become outdated. We refer to this as a First-Come Slow-Load Issue. Not a huge problem, but if you\'re optimizing your site for every once of speed possible, the Auto-Cache Engine can help with this. The Auto-Cache Engine has been designed to combat this issue by taking on the responsibility of being that first visitor to a page that has not yet been cached, or has an expired cache. The Auto-Cache Engine is powered, in part, by WP-Cron (already built into WordPress). The Auto-Cache Engine runs at 15-minute intervals via WP-Cron. It also uses the WP_Http class, which is also built into WordPress already.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('The Auto-Cache Engine obtains its list of URLs to auto-cache, from two different sources. It can read an XML Sitemap and/or a list of specific URLs that you supply. If you supply both sources, it will use both sources collectively. The Auto-Cache Engine takes ALL of your other configuration options into consideration too, including your Expiration Time, as well as any cache exclusion rules.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('XML Sitemap URL (or an XML Sitemap Index)', plugin()->text_domain).'

'."\n"; - echo '
'.esc_html(site_url('/')).'
'."\n"; - echo '

'.__('A List of URLs to Auto-Cache (One Per Line)', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; + echo '

'.__('XML Sitemap URL (or an XML Sitemap Index)', $this->plugin->text_domain).'

'."\n"; + echo '
'.esc_html(site_url('/')).'
'."\n"; + echo '

'.__('A List of URLs to Auto-Cache (One Per Line)', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; echo '
'."\n"; - echo '

'.__('Auto-Cache User-Agent String', plugin()->text_domain).'

'."\n"; - echo '
; '.esc_html(__NAMESPACE__.' '.plugin()->version).'
'."\n"; - echo '

'.__('This is how the Auto-Cache Engine identifies itself when connecting to URLs. See User Agent in the Wikipedia.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Auto-Cache User-Agent String', $this->plugin->text_domain).'

'."\n"; + echo '
; '.esc_html(__NAMESPACE__.' '.$this->plugin->version).'
'."\n"; + echo '

'.__('This is how the Auto-Cache Engine identifies itself when connecting to URLs. See User Agent in the Wikipedia.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -427,70 +434,70 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('HTML Compression (Experimental)', plugin()->text_domain)."\n"; + echo ' '.__('HTML Compression (Experimental)', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Enable WebSharks™ HTML Compression?', plugin()->text_domain).'

'."\n"; - echo '

'.__('This is an experimental feature, however it offers a potentially HUGE speed boost. You can learn more here. Please use with caution.', plugin()->text_domain).'

'."\n"; - if(!plugin()->is_extension_loaded('curl') || !is_array($_curl_version = curl_version()) || !($_curl_version['features'] & CURL_VERSION_SSL)) - echo '

'.__('WARNING: The HTML Compressor requires the cURL extension for PHP. cURL must also be compiled together with OpenSSL. Quick Cache has detected that one or both of these are currently missing. Please check with your hosting company to resolve this message.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Enable WebSharks™ HTML Compression?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('This is an experimental feature, however it offers a potentially HUGE speed boost. You can learn more here. Please use with caution.', $this->plugin->text_domain).'

'."\n"; + if(!$this->plugin->is_extension_loaded('curl') || !is_array($_curl_version = curl_version()) || !($_curl_version['features'] & CURL_VERSION_SSL)) + echo '

'.__('WARNING: The HTML Compressor requires the cURL extension for PHP. cURL must also be compiled together with OpenSSL. Quick Cache has detected that one or both of these are currently missing. Please check with your hosting company to resolve this message.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; - echo '

'.__('Note: This is experimental. Please report issues here.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Note: This is experimental. Please report issues here.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; - echo '

'.__('HTML Compression Options', plugin()->text_domain).'

'."\n"; - echo '

'.__('You can learn more about all of these options here.', plugin()->text_domain).'

'."\n"; + echo '

'.__('HTML Compression Options', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('You can learn more about all of these options here.', $this->plugin->text_domain).'

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '

'."\n"; echo '
'."\n"; - echo '

'.__('CSS Exclusion Patterns?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Sometimes there are special cases when a particular CSS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <link href=""> value, and also against the contents of any inline <style> tags (case insensitive). A wildcard * character can also be used when necessary; e.g. xy*-framework; (where * = anything, 0 or more characters in length).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', plugin()->text_domain).'

'."\n"; - echo '

'.__('JavaScript Exclusion Patterns?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Sometimes there are special cases when a particular JS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <script src=""> value, and also against the contents of any inline <script> tags (case insensitive). A wildcard * character can also be used when necessary; e.g. xy*-framework; (where * = anything, 0 or more characters in length).', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', plugin()->text_domain).'

'."\n"; + echo '

'.__('CSS Exclusion Patterns?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Sometimes there are special cases when a particular CSS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <link href=""> value, and also against the contents of any inline <style> tags (case insensitive). A wildcard * character can also be used when necessary; e.g. xy*-framework; (where * = anything, 0 or more characters in length).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('JavaScript Exclusion Patterns?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Sometimes there are special cases when a particular JS file should NOT be consolidated or compressed in any way. This is where you will enter those if you need to (one per line). Searches are performed against the <script src=""> value, and also against the contents of any inline <script> tags (case insensitive). A wildcard * character can also be used when necessary; e.g. xy*-framework; (where * = anything, 0 or more characters in length).', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g. one exclusion pattern per line.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; - echo '

'.__('HTML Compression Cache Expiration', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('Tip: the value that you specify here MUST be compatible with PHP\'s strtotime() function. Examples: 2 hours, 7 days, 6 months, 1 year.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: This does NOT impact the overall cache expiration time that you configure with Quick Cache. It only impacts the sub-routines provided by the HTML Compressor. In fact, this expiration time is mostly irrelevant. The HTML Compressor uses an internal checksum, and it also checks filemtime() before using an existing cache file. The HTML Compressor class also handles the automatic cleanup of your cache directories to keep it from growing too large over time. Therefore, unless you have VERY little disk space there is no reason to set this to a lower value (even if your site changes dynamically quite often). If anything, you might like to increase this value which could help to further reduce server load. You can learn more here. We recommend setting this value to at least double that of your overall Quick Cache expiration time.', plugin()->text_domain).'

'."\n"; + echo '

'.__('HTML Compression Cache Expiration', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('Tip: the value that you specify here MUST be compatible with PHP\'s strtotime() function. Examples: 2 hours, 7 days, 6 months, 1 year.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: This does NOT impact the overall cache expiration time that you configure with Quick Cache. It only impacts the sub-routines provided by the HTML Compressor. In fact, this expiration time is mostly irrelevant. The HTML Compressor uses an internal checksum, and it also checks filemtime() before using an existing cache file. The HTML Compressor class also handles the automatic cleanup of your cache directories to keep it from growing too large over time. Therefore, unless you have VERY little disk space there is no reason to set this to a lower value (even if your site changes dynamically quite often). If anything, you might like to increase this value which could help to further reduce server load. You can learn more here. We recommend setting this value to at least double that of your overall Quick Cache expiration time.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -499,15 +506,15 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('GZIP Compression', plugin()->text_domain)."\n"; + echo ' '.__('GZIP Compression', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo ' '."\n"; - echo '

'.__('GZIP Compression (Optional; Highly Recommended)', plugin()->text_domain).'

'."\n"; - echo '

'.__('You don\'t have to use an .htaccess file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an .htaccess file to accomplish that part.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Quick Cache fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your php.ini file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', plugin()->text_domain).'

'."\n"; - echo '

'.__('If you want to enable GZIP, create an .htaccess file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an .htaccess file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: video about GZIP Compression.', plugin()->text_domain).'

'."\n"; + echo ' '."\n"; + echo '

'.__('GZIP Compression (Optional; Highly Recommended)', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('You don\'t have to use an .htaccess file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an .htaccess file to accomplish that part.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Quick Cache fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your php.ini file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('If you want to enable GZIP, create an .htaccess file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an .htaccess file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: video about GZIP Compression.', $this->plugin->text_domain).'

'."\n"; echo '
'.esc_html(file_get_contents(dirname(__FILE__).'/gzip-htaccess.tpl.txt')).'
'."\n"; echo '
'."\n"; echo '

Or, if your server is missing mod_deflate/mod_filter; open your php.ini file and add this line: zlib.output_compression = on

'."\n"; @@ -518,23 +525,23 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Dynamic Version Salt', plugin()->text_domain)."\n"; + echo ' '.__('Dynamic Version Salt', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; - echo ' '."\n"; - echo '

'.__(' GEEK ALERT This is for VERY advanced users only...', plugin()->text_domain).'

'."\n"; - echo '

'.__('Note: Understanding the Quick Cache Branched Cache Structure is a prerequisite to understanding how Dynamic Version Salts are added to the mix.', plugin()->text_domain).'

'."\n"; - echo '

'.__('A Version Salt gives you the ability to dynamically create multiple variations of the cache, and those dynamic variations will be served on subsequent visits; e.g. if a visitor has a specific cookie (of a certain value) they will see pages which were cached with that version (i.e. w/ that Version Salt: the value of the cookie). A Version Salt can really be anything.', plugin()->text_domain).'

'."\n"; - echo '

'.__('A Version Salt can be a single variable like $_COOKIE[\'my_cookie\'], or it can be a combination of multiple variables, like $_COOKIE[\'my_cookie\'].$_COOKIE[\'my_other_cookie\']. (When using multiple variables, please separate them with a dot, as shown in the example.)', plugin()->text_domain).'

'."\n"; - echo '

'.__('Experts could even use PHP ternary expressions that evaluate into something. For example: ((preg_match(\'/iPhone/i\', $_SERVER[\'HTTP_USER_AGENT\'])) ? \'iPhones\' : \'\'). This would force a separate version of the cache to be created for iPhones (e.g., /cache/PROTOCOL/HOST/REQUEST-URI.v/iPhones.html).', plugin()->text_domain).'

'."\n"; - echo '

'.__('For more documentation, please see Dynamic Version Salts.', plugin()->text_domain).'

'."\n"; + echo ' '."\n"; + echo '

'.__(' GEEK ALERT This is for VERY advanced users only...', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Note: Understanding the Quick Cache Branched Cache Structure is a prerequisite to understanding how Dynamic Version Salts are added to the mix.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('A Version Salt gives you the ability to dynamically create multiple variations of the cache, and those dynamic variations will be served on subsequent visits; e.g. if a visitor has a specific cookie (of a certain value) they will see pages which were cached with that version (i.e. w/ that Version Salt: the value of the cookie). A Version Salt can really be anything.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('A Version Salt can be a single variable like $_COOKIE[\'my_cookie\'], or it can be a combination of multiple variables, like $_COOKIE[\'my_cookie\'].$_COOKIE[\'my_other_cookie\']. (When using multiple variables, please separate them with a dot, as shown in the example.)', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Experts could even use PHP ternary expressions that evaluate into something. For example: ((preg_match(\'/iPhone/i\', $_SERVER[\'HTTP_USER_AGENT\'])) ? \'iPhones\' : \'\'). This would force a separate version of the cache to be created for iPhones (e.g., /cache/PROTOCOL/HOST/REQUEST-URI.v/iPhones.html).', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('For more documentation, please see Dynamic Version Salts.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; - echo '

'.__('Create a Dynamic Version Salt For Quick Cache?       150% OPTIONAL', plugin()->text_domain).'

'."\n"; + echo '

'.__('Create a Dynamic Version Salt For Quick Cache?       150% OPTIONAL', $this->plugin->text_domain).'

'."\n"; echo '
/cache/PROTOCOL/HOST/REQUEST_URI.
'."\n"; - echo '

'.__('Super Globals work here; $GLOBALS[\'table_prefix\'] is a popular one.
Or, perhaps a PHP Constant defined in /wp-config.php; such as WPLANG or DB_HOST.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Important: your Version Salt is scanned for PHP syntax errors via phpCodeChecker.com. If errors are found, you\'ll receive a notice in the Dashboard.', plugin()->text_domain).'

'."\n"; - echo '

'.__('If you\'ve enabled a separate cache for each user (optional) that\'s perfectly OK. A Version Salt works with user caching too.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Super Globals work here; $GLOBALS[\'table_prefix\'] is a popular one.
Or, perhaps a PHP Constant defined in /wp-config.php; such as WPLANG or DB_HOST.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Important: your Version Salt is scanned for PHP syntax errors via phpCodeChecker.com. If errors are found, you\'ll receive a notice in the Dashboard.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('If you\'ve enabled a separate cache for each user (optional) that\'s perfectly OK. A Version Salt works with user caching too.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -542,17 +549,17 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Theme/Plugin Developers', plugin()->text_domain)."\n"; + echo ' '.__('Theme/Plugin Developers', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Developing a Theme or Plugin for WordPress?', plugin()->text_domain).'

'."\n"; - echo '

'.__('Tip: Quick Cache can be disabled temporarily. If you\'re a theme/plugin developer, you can set a flag within your PHP code to disable the cache engine at runtime. Perhaps on a specific page, or in a specific scenario. In your PHP script, set: $_SERVER[\'QUICK_CACHE_ALLOWED\'] = FALSE; or define(\'QUICK_CACHE_ALLOWED\', FALSE). Quick Cache is also compatible with: define(\'DONOTCACHEPAGE\', TRUE). It does\'t matter where or when you define one of these, because Quick Cache is the last thing to run before script execution ends.', plugin()->text_domain).'

'."\n"; + echo '

'.__('Developing a Theme or Plugin for WordPress?', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Tip: Quick Cache can be disabled temporarily. If you\'re a theme/plugin developer, you can set a flag within your PHP code to disable the cache engine at runtime. Perhaps on a specific page, or in a specific scenario. In your PHP script, set: $_SERVER[\'QUICK_CACHE_ALLOWED\'] = FALSE; or define(\'QUICK_CACHE_ALLOWED\', FALSE). Quick Cache is also compatible with: define(\'DONOTCACHEPAGE\', TRUE). It does\'t matter where or when you define one of these, because Quick Cache is the last thing to run before script execution ends.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; - echo '

'.__('Writing "Advanced Cache" Plugins Specifically for Quick Cache', plugin()->text_domain).'

'."\n"; - echo '

'.__('Theme/plugin developers can take advantage of the Quick Cache plugin architecture by creating PHP files inside this special directory: /wp-content/ac-plugins/. There is an example plugin file @ GitHub (please review it carefully and ask questions). If you develop a plugin for Quick Cache, please share it with the community by publishing it in the plugins respository at WordPress.org.', plugin()->text_domain).'

'."\n"; - echo '

'.__('Why does Quick Cache have it\'s own plugin architecture? WordPress loads the advanced-cache.php drop-in file (for caching purposes) very early-on; before any other plugins or a theme. For this reason, Quick Cache implements it\'s own watered-down version of functions like add_action(), do_action(), add_filter(), apply_filters().', plugin()->text_domain).'

'."\n"; + echo '

'.__('Writing "Advanced Cache" Plugins Specifically for Quick Cache', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Theme/plugin developers can take advantage of the Quick Cache plugin architecture by creating PHP files inside this special directory: /wp-content/ac-plugins/. There is an example plugin file @ GitHub (please review it carefully and ask questions). If you develop a plugin for Quick Cache, please share it with the community by publishing it in the plugins respository at WordPress.org.', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('Why does Quick Cache have it\'s own plugin architecture? WordPress loads the advanced-cache.php drop-in file (for caching purposes) very early-on; before any other plugins or a theme. For this reason, Quick Cache implements it\'s own watered-down version of functions like add_action(), do_action(), add_filter(), apply_filters().', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -560,31 +567,31 @@ public function options() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Import/Export Options', plugin()->text_domain)."\n"; + echo ' '.__('Import/Export Options', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('Import Options from Another Quick Cache Installation?', plugin()->text_domain).'

'."\n"; - echo '

'.sprintf(__('Upload your %1$s-options.json file and click "Save All Changes" below. The options provided by your import file will override any that exist currently.', plugin()->text_domain), __NAMESPACE__).'

'."\n"; + echo '

'.__('Import Options from Another Quick Cache Installation?', $this->plugin->text_domain).'

'."\n"; + echo '

'.sprintf(__('Upload your %1$s-options.json file and click "Save All Changes" below. The options provided by your import file will override any that exist currently.', $this->plugin->text_domain), __NAMESPACE__).'

'."\n"; echo '

'."\n"; echo '
'."\n"; - echo '

'.__('Export Existing Options from this Quick Cache Installation?', plugin()->text_domain).'

'."\n"; + echo '

'.__('Export Existing Options from this Quick Cache Installation?', $this->plugin->text_domain).'

'."\n"; echo ' '."\n"; - echo '

'.__('Download your existing options and import them all into another Quick Cache installation; saves time on future installs.', plugin()->text_domain).'

'."\n"; + ' '.sprintf(__('%1$s-options.json', $this->plugin->text_domain), __NAMESPACE__).' '."\n"; + echo '

'.__('Download your existing options and import them all into another Quick Cache installation; saves time on future installs.', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '
'."\n"; echo '
'."\n"; - echo ' '."\n"; - echo ' '."\n"; - echo ' '."\n"; - echo ' '."\n"; - echo ' '."\n"; - echo ' '."\n"; + echo ' '."\n"; + echo ' '."\n"; + echo ' '."\n"; + echo ' '."\n"; + echo ' '."\n"; + echo ' '."\n"; echo '
'."\n"; echo '
'."\n"; @@ -598,20 +605,20 @@ public function update_sync() echo '
'."\n"; - echo ' '."\n"; + echo ' '."\n"; - echo '
'."\n"; + echo '
'."\n"; echo ' '."\n"; echo ' '."\n"; echo '
'."\n"; echo ' '."\n"; - echo ' '.esc_attr(__('Plugin Updater', plugin()->text_domain)).''."\n"; + echo ' '.esc_attr(__('Plugin Updater', $this->plugin->text_domain)).''."\n"; echo '
'."\n"; @@ -626,18 +633,18 @@ public function update_sync() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Update Credentials', plugin()->text_domain)."\n"; + echo ' '.__('Update Credentials', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('WebSharks™ Authentication', plugin()->text_domain).'

'."\n"; - echo '

'.sprintf(__('From this page you can update to the latest version of Quick Cache Pro for WordPress. Quick Cache Pro is a premium product available for purchase @ websharks-inc.com. In order to connect with our update servers, we ask that you supply your account login details for websharks-inc.com. This will authenticate your copy of Quick Cache Pro; providing you with access to the latest version. You only need to enter these credentials once. Quick Cache Pro will save them in your WordPress database; making future upgrades even easier. ', plugin()->text_domain), str_replace('_', '-', __NAMESPACE__)).'

'."\n"; + echo '

'.__('WebSharks™ Authentication', $this->plugin->text_domain).'

'."\n"; + echo '

'.sprintf(__('From this page you can update to the latest version of Quick Cache Pro for WordPress. Quick Cache Pro is a premium product available for purchase @ websharks-inc.com. In order to connect with our update servers, we ask that you supply your account login details for websharks-inc.com. This will authenticate your copy of Quick Cache Pro; providing you with access to the latest version. You only need to enter these credentials once. Quick Cache Pro will save them in your WordPress database; making future upgrades even easier. ', $this->plugin->text_domain), str_replace('_', '-', __NAMESPACE__)).'

'."\n"; echo '
'."\n"; - echo '

'.__('WebSharks™ Username', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; - echo '

'.__('WebSharks™ Password', plugin()->text_domain).'

'."\n"; - echo '

'."\n"; + echo '

'.__('WebSharks™ Username', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; + echo '

'.__('WebSharks™ Password', $this->plugin->text_domain).'

'."\n"; + echo '

'."\n"; echo '
'."\n"; echo '
'."\n"; @@ -645,24 +652,24 @@ public function update_sync() echo '
'."\n"; echo '
'."\n"; - echo ' '.__('Update Notifier', plugin()->text_domain)."\n"; + echo ' '.__('Update Notifier', $this->plugin->text_domain)."\n"; echo '
'."\n"; echo '
'."\n"; echo ' '."\n"; - echo '

'.__('WebSharks™ Update Notifier', plugin()->text_domain).'

'."\n"; - echo '

'.__('When a new version of Quick Cache Pro becomes available, WebSharks™ can display a notification in your WordPress Dashboard prompting you to return to this page and perform an upgrade. Would you like this functionality enabled or disabled?', plugin()->text_domain).'

'."\n"; + echo '

'.__('WebSharks™ Update Notifier', $this->plugin->text_domain).'

'."\n"; + echo '

'.__('When a new version of Quick Cache Pro becomes available, WebSharks™ can display a notification in your WordPress Dashboard prompting you to return to this page and perform an upgrade. Would you like this functionality enabled or disabled?', $this->plugin->text_domain).'

'."\n"; echo '
'."\n"; echo '

'."\n"; echo '
'."\n"; echo '
'."\n"; echo '
'."\n"; - echo ' '."\n"; + echo ' '."\n"; echo '
'."\n"; echo '
'."\n"; diff --git a/quick-cache-pro/includes/share.php b/quick-cache-pro/includes/share.php index 997f3833..dc946daa 100644 --- a/quick-cache-pro/includes/share.php +++ b/quick-cache-pro/includes/share.php @@ -12,14 +12,1018 @@ * @package quick_cache\share * @since 14xxxx Reorganizing class members. */ - class share // Shared between {@link advanced_cache} and {@link plugin}. + abstract class share // Shared between {@link advanced_cache} and {@link plugin}. { + /* -------------------------------------------------------------------------------------- + * Class properties. + -------------------------------------------------------------------------------------- */ + + /** + * Identifies pro version of Quick Cache. + * + * @since 140422 First documented version. + * + * @var boolean `TRUE` for Quick Cache Pro. + */ + public $is_pro = TRUE; + + /** + * Version string in YYMMDD[+build] format. + * + * @since 140422 First documented version. + * + * @var string Current version of the software. + */ + public $version = '140605'; + + /** + * Text domain for translations; based on `__NAMESPACE__`. + * + * @since 140422 First documented version. + * + * @var string Defined by class constructor; for translations. + */ + public $text_domain = ''; + + /** + * An instance-based cache for class members. + * + * @since 14xxxx Reorganizing class members. + * + * @var array An instance-based cache for class members. + */ + public $cache = array(); + + /** + * A global static cache for class members. + * + * @since 14xxxx Reorganizing class members. + * + * @var array Global static cache for class members. + */ + public static $static = array(); + + /** + * Array of hooks added by plugins. + * + * @since 140422 First documented version. + * + * @var array An array of any hooks added by plugins. + */ + public $hooks = array(); + + /** + * Flag indicating the current user login cookie is expired or invalid. + * + * @since 140429 Improving user cache handlers. + * + * @var boolean `TRUE` if current user login cookie is expired or invalid. + * See also {@link user_token()} and {@link advanced_cache::maybe_start_ob_when_logged_in_postload()}. + */ + public $user_login_cookie_expired_or_invalid = FALSE; + + /* -------------------------------------------------------------------------------------- + * Cache path class constants. + -------------------------------------------------------------------------------------- */ + + /** + * Exclude scheme from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_SCHEME = 1; + + /** + * Exclude host (i.e. domain name) from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_HOST = 2; + + /** + * Exclude path from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_PATH = 4; + + /** + * Exclude path index (i.e. no default `index`) from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_PATH_INDEX = 8; + + /** + * Exclude query, user & version salt from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_QUV = 16; + + /** + * Exclude query string from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_QUERY = 32; + + /** + * Exclude user token from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_USER = 64; + + /** + * Exclude version salt from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_VSALT = 128; + + /** + * Exclude extension from cache path. + * + * @since 140422 First documented version. + * + * @var integer Part of a bitmask. + */ + const CACHE_PATH_NO_EXT = 256; + + /* -------------------------------------------------------------------------------------- + * Shared constructor. + -------------------------------------------------------------------------------------- */ + + /** + * Class constructor. + * + * @since 140422 First documented version. + */ public function __construct() { - // @TODO Bring shareable methods into this class. + if(strpos(__NAMESPACE__, '\\') !== FALSE) // Sanity check. + throw new \exception('Not a root namespace: `'.__NAMESPACE__.'`.'); + + $this->text_domain = str_replace('_', '-', __NAMESPACE__); + } + + /* -------------------------------------------------------------------------------------- + * Cache directory/path/URL utilities. + -------------------------------------------------------------------------------------- */ + + /** + * Absolute server path to the cache directory. + * + * @since 14xxxx Reorganizing class members. + * + * @param string $rel_path Optional; a relative path within the cache directory. + * + * @return string Absolute server path to the cache directory. + * + * @throws \exception If unable to determine the cache directory location. + */ + public function cache_dir($rel_path = '') + { + if(method_exists($this, 'wp_content_dir_to') && isset($this->cache_sub_dir)) + $cache_dir = $this->wp_content_dir_to($this->cache_sub_dir); + + else if(defined('QUICK_CACHE_DIR') && QUICK_CACHE_DIR) + $cache_dir = QUICK_CACHE_DIR; // Global constant. + + else throw new \exception(__('Unable to determine cache directory location.', $this->text_domain)); + + return $cache_dir.(($rel_path) ? '/'.ltrim((string)$rel_path) : ''); + } + + /** + * Converts a URL into a `cache/path`. + * + * @since 140422 First documented version. + * + * @param string $url The input URL to convert. + * @param string $with_user_token Optional user token (if applicable). + * @param string $with_version_salt Optional version salt (if applicable). + * @param integer $flags Optional flags; a bitmask provided by `CACHE_PATH_*` constants. + * + * @return string The resulting `cache/path` based on the input `$url`. + */ + public function url_to_cache_path($url, $with_user_token = '', $with_version_salt = '', $flags = 0) + { + $cache_path = ''; // Initialize. + $url = trim((string)$url); + $with_user_token = trim((string)$with_user_token); + $with_version_salt = trim((string)$with_version_salt); + + if($url && strpos($url, '://') === FALSE) + $url = '//'.ltrim($url, '/'); + + if(!$url || !($url = parse_url($url))) + return ''; // Invalid URL. + + if(!($flags & $this::CACHE_PATH_NO_SCHEME)) + { + if(!empty($url['scheme'])) + $cache_path .= $url['scheme'].'/'; + else $cache_path .= $this->is_ssl() ? 'https/' : 'http/'; + } + if(!($flags & $this::CACHE_PATH_NO_HOST)) + { + if(!empty($url['host'])) + $cache_path .= $url['host'].'/'; + else $cache_path .= $_SERVER['HTTP_HOST'].'/'; + } + if(!($flags & $this::CACHE_PATH_NO_PATH)) + { + if(!empty($url['path']) && strlen($url['path'] = trim($url['path'], '\\/'." \t\n\r\0\x0B"))) + $cache_path .= $url['path'].'/'; + else if(!($flags & $this::CACHE_PATH_NO_PATH_INDEX)) $cache_path .= 'index/'; + } + if($this->is_extension_loaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) + $cache_path = mb_strtolower($cache_path, 'UTF-8'); + $cache_path = str_replace('.', '-', strtolower($cache_path)); + + if(!($flags & $this::CACHE_PATH_NO_QUV)) + { + if(!($flags & $this::CACHE_PATH_NO_QUERY)) + if(isset($url['query']) && $url['query'] !== '') + $cache_path = rtrim($cache_path, '/').'.q/'.md5($url['query']).'/'; + + if(!($flags & $this::CACHE_PATH_NO_USER)) + if($with_user_token !== '') // Allow a `0` value if desirable. + $cache_path = rtrim($cache_path, '/').'.u/'.str_replace(array('/', '\\'), '-', $with_user_token).'/'; + + if(!($flags & $this::CACHE_PATH_NO_VSALT)) + if($with_version_salt !== '') // Allow a `0` value if desirable. + $cache_path = rtrim($cache_path, '/').'.v/'.str_replace(array('/', '\\'), '-', $with_version_salt).'/'; + } + $cache_path = trim(preg_replace('/\/+/', '/', $cache_path), '/'); + $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path); + + if(!($flags & $this::CACHE_PATH_NO_EXT)) + $cache_path .= '.html'; + + return $cache_path; // Do not filter. + } + + /* -------------------------------------------------------------------------------------- + * Token generation utilities. + -------------------------------------------------------------------------------------- */ + + /** + * Produces a token based on the current `$_SERVER['HTTP_HOST']`. + * + * @since 140422 First documented version. + * + * @param boolean $dashify Optional, defaults to a `FALSE` value. + * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. + * + * @return string Token based on the current `$_SERVER['HTTP_HOST']`. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function host_token($dashify = FALSE) + { + $dashify = (integer)$dashify; + + if(isset(static::$static[__FUNCTION__][$dashify])) + return static::$static[__FUNCTION__][$dashify]; + + $host = strtolower($_SERVER['HTTP_HOST']); + $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host), '-') : $host; + + return (static::$static[__FUNCTION__][$dashify] = $token_value); + } + + /** + * Produces a token based on the current site's base directory. + * + * @since 140605 First documented version. + * + * @param boolean $dashify Optional, defaults to a `FALSE` value. + * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. + * + * @return string Produces a token based on the current site's base directory; + * (i.e. in the case of a sub-directory multisite network). + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + * + * @see plugin::clear_cache() + * @see plugin::update_blog_paths() + */ + public function host_base_token($dashify = FALSE) + { + $dashify = (integer)$dashify; + + if(isset(static::$static[__FUNCTION__][$dashify])) + return static::$static[__FUNCTION__][$dashify]; + + $host_base_token = '/'; // Assume NOT multisite; or running it's own domain. + + if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) + { // Multisite w/ sub-directories; need a valid sub-directory token. + + if(defined('PATH_CURRENT_SITE')) $host_base_token = PATH_CURRENT_SITE; + else if(!empty($GLOBALS['base'])) $host_base_token = $GLOBALS['base']; + + $host_base_token = trim($host_base_token, '\\/'." \t\n\r\0\x0B"); + $host_base_token = (isset($host_base_token[0])) ? '/'.$host_base_token.'/' : '/'; + } + $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_base_token), '-') : $host_base_token; + + return (static::$static[__FUNCTION__][$dashify] = $token_value); + } + + /** + * Produces a token based on the current blog's sub-directory. + * + * @since 140422 First documented version. + * + * @param boolean $dashify Optional, defaults to a `FALSE` value. + * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. + * + * @return string Produces a token based on the current blog sub-directory + * (i.e. in the case of a sub-directory multisite network). + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + * + * @see plugin::clear_cache() + * @see plugin::update_blog_paths() + */ + public function host_dir_token($dashify = FALSE) + { + $dashify = (integer)$dashify; + + if(isset(static::$static[__FUNCTION__][$dashify])) + return static::$static[__FUNCTION__][$dashify]; + + $host_dir_token = '/'; // Assume NOT multisite; or on it's own domain. + if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) + { // Multisite w/ sub-directories; need a valid sub-directory token. + + $uri_minus_base = // Supports `/sub-dir/child-blog-sub-dir/` also. + preg_replace('/^'.preg_quote($this->host_base_token(), '/').'/', '', $_SERVER['REQUEST_URI']); + + list($host_dir_token) = explode('/', trim($uri_minus_base, '/')); + $host_dir_token = (isset($host_dir_token[0])) ? '/'.$host_dir_token.'/' : '/'; + + if($host_dir_token !== '/' // Perhaps NOT the main site? + && (!is_file(($cache_dir = $this->cache_dir()).'/qc-blog-paths') // NOT a read/valid blog path? + || !in_array($host_dir_token, unserialize(file_get_contents($cache_dir.'/qc-blog-paths')), TRUE)) + ) $host_dir_token = '/'; // Main site; e.g. this is NOT a real/valid child blog path. + } + $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_dir_token), '-') : $host_dir_token; + + return (static::$static[__FUNCTION__][$dashify] = $token_value); + } + + /** + * Produces tokens for the current site's base directory & current blog's sub-directory. + * + * @since 140422 First documented version. + * + * @param boolean $dashify Optional, defaults to a `FALSE` value. + * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`. + * + * @return string Tokens for the current site's base directory & current blog's sub-directory. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + * + * @see plugin::clear_cache() + * @see plugin::update_blog_paths() + */ + public function host_base_dir_tokens($dashify = FALSE) + { + $dashify = (integer)$dashify; + + if(isset(static::$static[__FUNCTION__][$dashify])) + return static::$static[__FUNCTION__][$dashify]; + + $tokens = preg_replace('/\/{2,}/', '/', $this->host_base_token($dashify).$this->host_dir_token($dashify)); + + return (static::$static[__FUNCTION__][$dashify] = $tokens); + } + + /** + * Produces a token based on the current user. + * + * @since 140422 First documented version. + * + * @return string Produces a token based on the current user; + * else an empty string if that's not possible to do. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + * + * @note This routine may trigger a flag which indicates that the current user was logged-in at some point, + * but now the login cookie can no longer be validated by WordPress; i.e. they are NOT actually logged in any longer. + * See {@link $user_login_cookie_expired_or_invalid} + */ + public function user_token() // When/if possible. + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + $wp_validate_auth_cookie_possible = $this->function_is_possible('wp_validate_auth_cookie'); + if($wp_validate_auth_cookie_possible && ($user_id = (integer)wp_validate_auth_cookie('', 'logged_in'))) + return (static::$static[__FUNCTION__] = $user_id); // A real user in this case. + + else if(!empty($_COOKIE['comment_author_email_'.COOKIEHASH]) && is_string($_COOKIE['comment_author_email_'.COOKIEHASH])) + return (static::$static[__FUNCTION__] = md5(strtolower(stripslashes($_COOKIE['comment_author_email_'.COOKIEHASH])))); + + else if(!empty($_COOKIE['wp-postpass_'.COOKIEHASH]) && is_string($_COOKIE['wp-postpass_'.COOKIEHASH])) + return (static::$static[__FUNCTION__] = md5(stripslashes($_COOKIE['wp-postpass_'.COOKIEHASH]))); + + else if(defined('SID') && SID) return (static::$static[__FUNCTION__] = preg_replace('/[^a-z0-9]/i', '', SID)); + + if($wp_validate_auth_cookie_possible // We were unable to validate the login cookie? + && !empty($_COOKIE['wordpress_logged_in_'.COOKIEHASH]) && is_string($_COOKIE['wordpress_logged_in_'.COOKIEHASH]) + ) $this->user_login_cookie_expired_or_invalid = TRUE; // Flag as `TRUE`. + + return (static::$static[__FUNCTION__] = ''); + } + + /* -------------------------------------------------------------------------------------- + * Conditional utilities. + -------------------------------------------------------------------------------------- */ + + /** + * Is the current request method `POST|PUT|DELETE`? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if a `POST|PUT|DELETE` request. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_post_put_del_request() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(!empty($_SERVER['REQUEST_METHOD'])) + if(in_array(strtoupper($_SERVER['REQUEST_METHOD']), array('POST', 'PUT', 'DELETE'), TRUE)) + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Does the current request include a query string? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if request includes a query string. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_get_request_w_query() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(!empty($_GET) || isset($_SERVER['QUERY_STRING'][0])) + if(!(isset($_GET['qcABC']) && count($_GET) === 1)) // Ignore this special case. + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Should the current user should be considered a logged-in user? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if current user should be considered a logged-in user. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_like_user_logged_in() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(defined('SID') && SID) // Session ID. + return (static::$static[__FUNCTION__] = TRUE); + + $logged_in_cookies[] = 'comment_author_'; // Comment (and/or reply) authors. + $logged_in_cookies[] = 'wp-postpass_'; // Password access to protected posts. + + $logged_in_cookies[] = (defined('AUTH_COOKIE')) ? AUTH_COOKIE : 'wordpress_'; + $logged_in_cookies[] = (defined('SECURE_AUTH_COOKIE')) ? SECURE_AUTH_COOKIE : 'wordpress_sec_'; + $logged_in_cookies[] = (defined('LOGGED_IN_COOKIE')) ? LOGGED_IN_COOKIE : 'wordpress_logged_in_'; + $logged_in_cookies = '/^(?:'.implode('|', array_map(function ($logged_in_cookie) + { + return preg_quote($logged_in_cookie, '/'); // Escape. + + }, $logged_in_cookies)).')/'; + $test_cookie = (defined('TEST_COOKIE')) ? TEST_COOKIE : 'wordpress_test_cookie'; + + foreach($_COOKIE as $_key => $_value) if($_key !== $test_cookie) + if(preg_match($logged_in_cookies, $_key) && $_value) + return (static::$static[__FUNCTION__] = TRUE); + unset($_key, $_value); // Housekeeping. + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Are we in a LOCALHOST environment? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if we are in a LOCALHOST environment. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_localhost() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(defined('LOCALHOST') && LOCALHOST) + return (static::$static[__FUNCTION__] = TRUE); + + if(!defined('LOCALHOST') && !empty($_SERVER['HTTP_HOST'])) + if(preg_match('/localhost|127\.0\.0\.1/i', $_SERVER['HTTP_HOST'])) + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Is the current request for the Auto-Cache Engine? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if the current request is for the Auto-Cache Engine. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_auto_cache_engine() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(!empty($_SERVER['HTTP_USER_AGENT'])) + if(stripos($_SERVER['HTTP_USER_AGENT'], __NAMESPACE__) !== FALSE) + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Is the current request for a feed? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if the current request is for a feed. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_feed() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) + return (static::$static[__FUNCTION__] = TRUE); + + if(isset($_REQUEST['feed'])) // Query var? + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Is the current request over SSL? + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if the current request is over SSL. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_ssl() + { + if(isset(static::$static[__FUNCTION__])) + return static::$static[__FUNCTION__]; + + if(!empty($_SERVER['SERVER_PORT'])) + if($_SERVER['SERVER_PORT'] === '443') + return (static::$static[__FUNCTION__] = TRUE); + + if(!empty($_SERVER['HTTPS'])) + if($_SERVER['HTTPS'] === '1' || strcasecmp($_SERVER['HTTPS'], 'on') === 0) + return (static::$static[__FUNCTION__] = TRUE); + + if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) + if(strcasecmp($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) + return (static::$static[__FUNCTION__] = TRUE); + + return (static::$static[__FUNCTION__] = FALSE); + } + + /** + * Is a document/string an HTML/XML doc; or no? + * + * @since 140422 First documented version. + * + * @param string $doc Input string/document to check. + * + * @return boolean `TRUE` if `$doc` is an HTML/XML doc type. + */ + public function is_html_xml_doc($doc) + { + if(($doc = (string)$doc)) + if(stripos($doc, '') !== FALSE || stripos($doc, 'function_is_possible('http_response_code') && ($http_response_code = http_response_code())) + { + $http_status = (integer)$http_response_code; + if(property_exists($this, 'http_status')) // Update {@link advanced_cache} property? + $this->{'http_status'} = $http_status; // Prefer over {@link status_header()} filter value. + } + $http_status = (string)$http_status; // Need a string type here. + if(isset($http_status[0]) && $http_status[0] !== '2' && $http_status !== '404') + return (static::$static[__FUNCTION__] = FALSE); // A non-2xx & non-404 status code. + /* + * PHP's `headers_list()` currently does NOT include `HTTP/` headers. + * This means the following routine will never catch a status sent by `status_header()`. + * However, I'm leaving this check in place in case a future version of PHP adds support for this. + * + * For now, we monitor `status_header()` via {@link maybe_filter_status_header_postload()} so that will suffice. + */ + foreach(headers_list() as $_header) + if(preg_match('/^(?:Retry\-After\:\s+(?P.+)|Status\:\s+(?P[0-9]+)|HTTP\/[0-9]+\.[0-9]+\s+(?P[0-9]+))/i', $_header, $_m)) + if(!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404') + || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404') + ) return (static::$static[__FUNCTION__] = FALSE); // NOT a 2xx or 404 status. + unset($_header); // Just a little housekeeping. + + return (static::$static[__FUNCTION__] = TRUE); // Assume that it is by default. + } + + /* -------------------------------------------------------------------------------------- + * Function/extension utilities. + -------------------------------------------------------------------------------------- */ + + /** + * Checks if a PHP extension is loaded up. + * + * @since 140422 First documented version. + * + * @param string $extension A PHP extension slug (i.e. extension name). + * + * @return boolean `TRUE` if the extension is loaded. + * + * @note The return value of this function is cached to reduce overhead on repeat calls. + */ + public function is_extension_loaded($extension) + { + if(isset(static::$static[__FUNCTION__][$extension])) + return static::$static[__FUNCTION__][$extension]; + return (static::$static[__FUNCTION__][$extension] = extension_loaded($extension)); + } + + /** + * Is a particular function possible in every way? + * + * @since 140422 First documented version. + * + * @param string $function A PHP function (or user function) to check. + * + * @return string `TRUE` if the function is possible. + * + * @note This checks (among other things) if the function exists and that it's callable. + * It also checks the currently configured `disable_functions` and `suhosin.executor.func.blacklist`. + */ + public function function_is_possible($function) + { + if(isset(static::$static[__FUNCTION__][$function])) + return static::$static[__FUNCTION__][$function]; + + if(isset(static::$static[__FUNCTION__]['___disabled_functions'])) + $disabled_functions =& static::$static[__FUNCTION__]['___disabled_functions']; + + else // We need to collect the disabled functions and cache them now. + { + static::$static[__FUNCTION__]['___disabled_functions'] = array(); // `$disabled_functions` =& reference. + $disabled_functions =& static::$static[__FUNCTION__]['___disabled_functions']; + + if(function_exists('ini_get')) // Only if {@link ini_get()} is possible itself. + { + if(($disable_functions = trim(ini_get('disable_functions')))) + $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($disable_functions), NULL, PREG_SPLIT_NO_EMPTY)); + + if(($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) + $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($blacklist_functions), NULL, PREG_SPLIT_NO_EMPTY)); + } + } + $possible = TRUE; // Assume it is.. (intialize). + + if(!function_exists($function) || !is_callable($function) + || ($disabled_functions && in_array(strtolower($function), $disabled_functions, TRUE)) + ) $possible = FALSE; // Not possible. + + return (static::$static[__FUNCTION__][$function] = $possible); } - } - $GLOBALS[__NAMESPACE__.'__share'] = new share(); + /* -------------------------------------------------------------------------------------- + * Misc. utility methods. + -------------------------------------------------------------------------------------- */ + + /** + * Escape single quotes. + * + * @since 140422 First documented version. + * + * @param string $string Input string to escape. + * @param integer $times Optional. Defaults to one escape char; e.g. `\'`. + * If you need to escape more than once, set this to something > `1`. + * + * @return string Escaped string; e.g. `Raam\'s the lead developer`. + */ + public function esc_sq($string, $times = 1) + { + return str_replace("'", str_repeat('\\', abs($times))."'", (string)$string); + } + + /** + * Recursive directory iterator based on a regex pattern. + * + * @since 140422 First documented version. + * + * @param string $dir An absolute server directory path. + * @param string $regex A regex pattern; compares to each full file path. + * + * @return \RegexIterator Navigable with {@link \foreach()}; where each item + * is a {@link \RecursiveDirectoryIterator}. + */ + public function dir_regex_iteration($dir, $regex) + { + $dir_iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS); + $iterator_iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST); + $regex_iterator = new \RegexIterator($iterator_iterator, $regex, \RegexIterator::MATCH, \RegexIterator::USE_KEY); + + return $regex_iterator; + } + + /* -------------------------------------------------------------------------------------- + * Hook/filter API for Quick Cache. + -------------------------------------------------------------------------------------- */ + + /** + * Assigns an ID to each callable attached to a hook/filter. + * + * @since 140422 First documented version. + * + * @param string|callable|mixed $function A string or a callable. + * + * @return string Hook ID for the given `$function`. + * + * @throws \exception If the hook/function is invalid (i.e. it's not possible to generate an ID). + */ + public function hook_id($function) + { + if(is_string($function)) + return $function; + + if(is_object($function)) // Closure. + $function = array($function, ''); + else $function = (array)$function; + + if(is_object($function[0])) + return spl_object_hash($function[0]).$function[1]; + + else if(is_string($function[0])) + return $function[0].'::'.$function[1]; + + throw new \exception(__('Invalid hook.', $this->text_domain)); + } + + /** + * Adds a new hook (works with both actions & filters). + * + * @since 140422 First documented version. + * + * @param string $hook The name of a hook to attach to. + * @param string|callable|mixed $function A string or a callable. + * @param integer $priority Hook priority; defaults to `10`. + * @param integer $accepted_args Max number of args that should be passed to the `$function`. + * + * @return boolean This always returns a `TRUE` value. + */ + public function add_hook($hook, $function, $priority = 10, $accepted_args = 1) + { + $this->hooks[$hook][$priority][$this->hook_id($function)] + = array('function' => $function, 'accepted_args' => (integer)$accepted_args); + return TRUE; // Always returns true. + } + + /** + * Adds a new action hook. + * + * @since 140422 First documented version. + * + * @return boolean This always returns a `TRUE` value. + * + * @see add_hook() + */ + public function add_action() // Simple `add_hook()` alias. + { + return call_user_func_array(array($this, 'add_hook'), func_get_args()); + } + + /** + * Adds a new filter. + * + * @since 140422 First documented version. + * + * @return boolean This always returns a `TRUE` value. + * + * @see add_hook() + */ + public function add_filter() // Simple `add_hook()` alias. + { + return call_user_func_array(array($this, 'add_hook'), func_get_args()); + } + + /** + * Removes a hook (works with both actions & filters). + * + * @since 140422 First documented version. + * + * @param string $hook The name of a hook to remove. + * @param string|callable|mixed $function A string or a callable. + * @param integer $priority Hook priority; defaults to `10`. + * + * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. + */ + public function remove_hook($hook, $function, $priority = 10) + { + if(!isset($this->hooks[$hook][$priority][$this->hook_id($function)])) + return FALSE; // Nothing to remove in this case. + + unset($this->hooks[$hook][$priority][$this->hook_id($function)]); + if(!$this->hooks[$hook][$priority]) unset($this->hooks[$hook][$priority]); + return TRUE; // Existed before it was removed in this case. + } + + /** + * Removes an action. + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. + * + * @see remove_hook() + */ + public function remove_action() // Simple `remove_hook()` alias. + { + return call_user_func_array(array($this, 'remove_hook'), func_get_args()); + } + + /** + * Removes a filter. + * + * @since 140422 First documented version. + * + * @return boolean `TRUE` if removed; else `FALSE` if not removed for any reason. + * + * @see remove_hook() + */ + public function remove_filter() // Simple `remove_hook()` alias. + { + return call_user_func_array(array($this, 'remove_hook'), func_get_args()); + } + + /** + * Runs any callables attached to an action. + * + * @since 140422 First documented version. + */ + public function do_action($hook) + { + if(empty($this->hooks[$hook])) + return; // No hooks. + + $hook_actions = $this->hooks[$hook]; + ksort($hook_actions); // Sort by priority. + + $args = func_get_args(); // We'll need these below. + foreach($hook_actions as $_hook_action) foreach($_hook_action as $_action) + { + if(!isset($_action['function'], $_action['accepted_args'])) + continue; // Not a valid filter in this case. + + call_user_func_array($_action['function'], array_slice($args, 1, $_action['accepted_args'])); + } + unset($_hook_action, $_action); // Housekeeping. + } + + /** + * Runs any callables attached to a filter. + * + * @since 140422 First documented version. + * + * @param string $hook The name of a filter hook. + * @param mixed $value The value to filter. + * + * @return mixed The filtered `$value`. + */ + public function apply_filters($hook, $value) + { + if(empty($this->hooks[$hook])) + return $value; // No hooks. + + $hook_filters = $this->hooks[$hook]; + ksort($hook_filters); // Sort by priority. + + $args = func_get_args(); // We'll need these below. + foreach($hook_filters as $_hook_filter) foreach($_hook_filter as $_filter) + { + if(!isset($_filter['function'], $_filter['accepted_args'])) + continue; // Not a valid filter in this case. + + $args[1] = $value; // Continously update the argument `$value`. + $value = call_user_func_array($_filter['function'], array_slice($args, 1, $_filter['accepted_args'])); + } + unset($_hook_filter, $_filter); // Housekeeping. + + return $value; // With applied filters. + } + + /* -------------------------------------------------------------------------------------- + * Misc. long property values. + -------------------------------------------------------------------------------------- */ + + /** + * Apache `.htaccess` rules that deny public access to the contents of a directory. + * + * @since 140422 First documented version. + * + * @var string `.htaccess` fules. + */ + public $htaccess_deny = "\n\tRequire all denied\n\n\n\tdeny from all\n"; + } } } \ No newline at end of file diff --git a/quick-cache-pro/includes/version-specific-upgrade.php b/quick-cache-pro/includes/version-specific-upgrade.php new file mode 100644 index 00000000..d7aeaea6 --- /dev/null +++ b/quick-cache-pro/includes/version-specific-upgrade.php @@ -0,0 +1,136 @@ +plugin = plugin(); + $this->prev_version = (string)$prev_version; + $this->run_handlers(); // Run upgrade(s). + } + + /** + * Runs upgrade handlers in the proper order. + */ + public function run_handlers() + { + $this->from_lt_v110523(); + $this->from_lt_v140104(); + $this->from_lt_v140605(); + $this->from_lt_v140612(); + } + + /* + * Upgrading from a version prior to our rewrite. + */ + public function from_lt_v110523() + { + if(version_compare($this->prev_version, '110523', '<')) + { + delete_option('ws_plugin__qcache_options'); // Ditch these. + delete_option('ws_plugin__qcache_notices'); // Ditch these. + delete_option('ws_plugin__qcache_configured'); // Ditch this too. + + wp_clear_scheduled_hook('ws_plugin__qcache_garbage_collector__schedule'); // Ditch old CRON job. + wp_clear_scheduled_hook('ws_plugin__qcache_auto_cache_engine__schedule'); // Ditch old CRON job. + + $this->plugin->enqueue_notice(__('Quick Cache: this version is a complete rewrite :-) Please review your Quick Cache options carefully!', $this->plugin->text_domain)); + } + } + + /* + * Upgrading from a version prior to v140104 where we introduced feed caching. + */ + public function from_lt_v140104() + { + if(version_compare($this->prev_version, '140104', '<')) // When this sort of update occurs, we issue a notice about this new feature. + $this->plugin->enqueue_notice(__('Quick Cache Feature Notice: This version of Quick Cache adds new options for Feed caching. Feed caching is now disabled by default. If you wish to enable feed caching, please visit the Quick Cache options panel.', $this->plugin->text_domain)); + } + + /* + * Upgrading from a version prior to v140605, where we introduced a branched cache structure. + * See + * We also also moved to a base directory layout. + */ + public function from_lt_v140605() + { + if(version_compare($this->prev_version, '140605', '<')) + { + if(!empty($this->plugin->options['cache_dir'])) + { + $wp_content_dir_relative = // We considered custom locations. + trim(str_replace(ABSPATH, '', WP_CONTENT_DIR), '\\/'." \t\n\r\0\x0B"); + + $this->plugin->options['base_dir'] = $this->plugin->options['cache_dir'] + = trim($this->plugin->options['cache_dir'], '\\/'." \t\n\r\0\x0B"); + + if(!$this->plugin->options['base_dir'] || $this->plugin->options['base_dir'] === $wp_content_dir_relative.'/cache') + $this->plugin->options['base_dir'] = $this->plugin->default_options['base_dir']; + + if($this->plugin->options['cache_dir']) // Wipe old files? + $this->plugin->wipe_cache(FALSE, ABSPATH.$this->plugin->options['cache_dir']); + unset($this->plugin->options['cache_dir']); + + update_option(__NAMESPACE__.'_options', $this->plugin->options); + if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->plugin->options); + } + $this->plugin->enqueue_notice(__('Quick Cache Feature Notice: This version of Quick Cache introduces a new Branched Cache Structure and several other new features.', $this->plugin->text_domain)); + } + } + + /** + * Upgrading from a version before we changed base directory from `ABSPATH` to `WP_CONTENT_DIR`. + * If so, we need to reset the cache location on sites + * that have `wp-content` in their base directory. + */ + public function from_lt_v140612() + { + if(version_compare($this->prev_version, '140612', '<')) + { + if(stripos($this->plugin->options['base_dir'], basename(WP_CONTENT_DIR)) !== FALSE) + { + $this->plugin->wipe_cache(FALSE, ABSPATH.$this->plugin->options['base_dir']); + $this->plugin->options['base_dir'] = $this->plugin->default_options['base_dir']; + + update_option(__NAMESPACE__.'_options', $this->plugin->options); + if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->plugin->options); + + $this->plugin->enqueue_notice( // Give site owners a quick heads up about this. + '

'.__('Quick Cache Notice: This version of Quick Cache changes the default base directory that it uses, from ABSPATH to WP_CONTENT_DIR. This is for improved compatibility with installations that choose to use a custom WP_CONTENT_DIR location.', $this->plugin->text_domain). + ' '.__('Quick Cache has detected that your previously configured cache directory may have been in conflict with this change. As a result, your Quick Cache configuration has been updated to the new default value; just to keep things running smoothly for you :-). If you would like to review this change, please see: Dashboard ⥱ Quick Cache ⥱ Directory & Expiration Time; where you may customize it further if necessary.', $this->plugin->text_domain).'

' + ); + } + } + } + } + } +} \ No newline at end of file diff --git a/quick-cache-pro/quick-cache-pro.inc.php b/quick-cache-pro/quick-cache-pro.inc.php index ec9765c9..ab91efa6 100644 --- a/quick-cache-pro/quick-cache-pro.inc.php +++ b/quick-cache-pro/quick-cache-pro.inc.php @@ -22,17 +22,8 @@ * @package quick_cache\plugin * @since 140422 First documented version. */ - class plugin + class plugin extends share { - /** - * Pro version flag. - * - * @since 140422 First documented version. - * - * @var boolean TRUE for pro version; FALSE for lite version. - */ - public $is_pro = TRUE; - /** * Stub `__FILE__` location. * @@ -44,24 +35,6 @@ class plugin */ public $file = ''; - /** - * Version string in YYMMDD[+build] format. - * - * @since 140422 First documented version. - * - * @var string Current version of the software. - */ - public $version = '140605'; - - /** - * Plugin text domain for translations. - * - * @since 140422 First documented version. - * - * @var string Plugin text domain; set by constructor. - */ - public $text_domain = ''; - /** * An array of all default option values. * @@ -81,34 +54,34 @@ class plugin public $options = array(); /** - * Update capability requirement. + * General capability requirement. * * @since 140422 First documented version. * * @var string WordPress capability required to - * update QC Pro to the latest release. + * administer QC in any environment; i.e. in multisite or otherwise. */ - public $update_cap = ''; + public $cap = ''; /** - * Network capability requirement. + * Update capability requirement. * * @since 140422 First documented version. * * @var string WordPress capability required to - * administer QC in a multisite network. + * update QC Pro to the latest release. */ - public $network_cap = ''; + public $update_cap = ''; /** - * General capability requirement. + * Network capability requirement. * * @since 140422 First documented version. * * @var string WordPress capability required to - * administer QC in any environment; i.e. in multisite or otherwise. + * administer QC in a multisite network. */ - public $cap = ''; + public $network_cap = ''; /** * Cache directory. @@ -137,15 +110,6 @@ class plugin */ public $htmlc_cache_sub_dir_private = 'htmlc/private'; - /** - * Easy reference to the {@link share} class instance. - * - * @since 14xxxx Reorganizing class members. - * - * @var share References {@link share} class. - */ - public $share; // Set by constructor. - /** * Quick Cache plugin constructor. * @@ -153,12 +117,9 @@ class plugin */ public function __construct() { - if(strpos(__NAMESPACE__, '\\') !== FALSE) // Sanity check. - throw new \exception('Not a root namespace: `'.__NAMESPACE__.'`.'); + parent::__construct(); // Shared constructor. - $this->file = preg_replace('/\.inc\.php$/', '.php', __FILE__); - $this->text_domain = str_replace('_', '-', __NAMESPACE__); - $this->share = $GLOBALS[__NAMESPACE__.'__share']; + $this->file = preg_replace('/\.inc\.php$/', '.php', __FILE__); add_action('after_setup_theme', array($this, 'setup')); register_activation_hook($this->file, array($this, 'activate')); @@ -176,72 +137,73 @@ public function setup() load_plugin_textdomain($this->text_domain); - $wp_content_dir_relative = // Considers custom `WP_CONTENT_DIR` locations. - trim(str_replace(ABSPATH, '', WP_CONTENT_DIR), '\\/'." \t\n\r\0\x0B"); - - $this->default_options = array( // Default options. - 'version' => $this->version, - - 'crons_setup' => '0', // `0` or timestamp. - - 'enable' => '0', // `0|1`. - 'debugging_enable' => '1', // `0|1|2` // 2 indicates greater debugging detail. - 'admin_bar_enable' => '1', // `0|1`. - 'cache_clear_s2clean_enable' => '0', // `0|1`. - 'cache_clear_eval_code' => '', // PHP code. - 'cache_purge_home_page_enable' => '1', // `0|1`. - 'cache_purge_posts_page_enable' => '1', // `0|1`. - 'cache_purge_author_page_enable' => '1', // `0|1`. - 'cache_purge_term_category_enable' => '1', // `0|1`. - 'cache_purge_term_post_tag_enable' => '1', // `0|1`. - 'cache_purge_term_other_enable' => '0', // `0|1`. - 'allow_browser_cache' => '0', // `0|1`. - - 'base_dir' => $wp_content_dir_relative.'/cache/quick-cache', - 'cache_max_age' => '7 days', // `strtotime()` compatible. - - 'when_logged_in' => '0', // `0|1|postload`. - 'get_requests' => '0', // `0|1`. - 'feeds_enable' => '0', // `0|1`. - 'cache_404_requests' => '0', // `0|1`. - - 'exclude_uris' => '', // Empty string or line-delimited patterns. - 'exclude_refs' => '', // Empty string or line-delimited patterns. - 'exclude_agents' => 'w3c_validator', // Empty string or line-delimited patterns. - - 'version_salt' => '', // Any string value. - - 'htmlc_enable' => '0', // Enable HTML compression? - 'htmlc_css_exclusions' => '', // Empty string or line-delimited patterns. - 'htmlc_js_exclusions' => '.php?', // Empty string or line-delimited patterns. - 'htmlc_cache_expiration_time' => '14 days', // `strtotime()` compatible. - - 'htmlc_compress_combine_head_body_css' => '1', // `0|1`. - 'htmlc_compress_combine_head_js' => '1', // `0|1`. - 'htmlc_compress_combine_footer_js' => '1', // `0|1`. - 'htmlc_compress_combine_remote_css_js' => '1', // `0|1`. - 'htmlc_compress_inline_js_code' => '1', // `0|1`. - 'htmlc_compress_css_code' => '1', // `0|1`. - 'htmlc_compress_js_code' => '1', // `0|1`. - 'htmlc_compress_html_code' => '1', // `0|1`. - - 'change_notifications_enable' => '1', // `0|1`. - 'uninstall_on_deactivation' => '0', // `0|1`. - - 'auto_cache_enable' => '0', // `0|1`. - 'auto_cache_sitemap_url' => 'sitemap.xml', // Relative to `site_url()`. - 'auto_cache_other_urls' => '', // A line-delimited list of any other URLs. - 'auto_cache_user_agent' => 'WordPress/'.get_bloginfo('version'), - - 'update_sync_username' => '', 'update_sync_password' => '', - 'update_sync_version_check' => '1', 'last_update_sync_version_check' => '0' + $this->default_options = array( + 'version' => $this->version, + + 'crons_setup' => '0', // `0` or timestamp. + + 'enable' => '0', // `0|1`. + 'debugging_enable' => '1', // `0|1|2` // 2 indicates greater debugging detail. + 'admin_bar_enable' => '1', // `0|1`. + 'cache_clear_s2clean_enable' => '0', // `0|1`. + 'cache_clear_eval_code' => '', // PHP code. + 'cache_purge_home_page_enable' => '1', // `0|1`. + 'cache_purge_posts_page_enable' => '1', // `0|1`. + 'cache_purge_author_page_enable' => '1', // `0|1`. + 'cache_purge_term_category_enable' => '1', // `0|1`. + 'cache_purge_term_post_tag_enable' => '1', // `0|1`. + 'cache_purge_term_other_enable' => '0', // `0|1`. + 'allow_browser_cache' => '0', // `0|1`. + + 'base_dir' => 'cache/quick-cache', // Relative to `WP_CONTENT_DIR`. + 'cache_max_age' => '7 days', // `strtotime()` compatible. + + 'when_logged_in' => '0', // `0|1|postload`. + 'get_requests' => '0', // `0|1`. + 'feeds_enable' => '0', // `0|1`. + 'cache_404_requests' => '0', // `0|1`. + + 'exclude_uris' => '', // Empty string or line-delimited patterns. + 'exclude_refs' => '', // Empty string or line-delimited patterns. + 'exclude_agents' => 'w3c_validator', // Empty string or line-delimited patterns. + + 'version_salt' => '', // Any string value. + + 'htmlc_enable' => '0', // Enable HTML compression? + 'htmlc_css_exclusions' => '', // Empty string or line-delimited patterns. + 'htmlc_js_exclusions' => '.php?', // Empty string or line-delimited patterns. + 'htmlc_cache_expiration_time' => '14 days', // `strtotime()` compatible. + + 'htmlc_compress_combine_head_body_css' => '1', // `0|1`. + 'htmlc_compress_combine_head_js' => '1', // `0|1`. + 'htmlc_compress_combine_footer_js' => '1', // `0|1`. + 'htmlc_compress_combine_remote_css_js' => '1', // `0|1`. + 'htmlc_compress_inline_js_code' => '1', // `0|1`. + 'htmlc_compress_css_code' => '1', // `0|1`. + 'htmlc_compress_js_code' => '1', // `0|1`. + 'htmlc_compress_html_code' => '1', // `0|1`. + + 'change_notifications_enable' => '1', // `0|1`. + 'uninstall_on_deactivation' => '0', // `0|1`. + + 'auto_cache_enable' => '0', // `0|1`. + 'auto_cache_sitemap_url' => 'sitemap.xml', // Relative to `site_url()`. + 'auto_cache_other_urls' => '', // A line-delimited list of any other URLs. + 'auto_cache_user_agent' => 'WordPress/'.get_bloginfo('version'), + + 'update_sync_username' => '', 'update_sync_password' => '', + 'update_sync_version_check' => '1', 'last_update_sync_version_check' => '0' ); // Default options are merged with those defined by the site owner. $options = (is_array($options = get_option(__NAMESPACE__.'_options'))) ? $options : array(); if(is_multisite() && is_array($site_options = get_site_option(__NAMESPACE__.'_options'))) $options = array_merge($options, $site_options); // Multisite network options. - if(!$options && is_array($old_options = get_option('ws_plugin__qcache_options')) && $old_options) + if(!$options && get_option('ws_plugin__qcache_configured') + && is_array($old_options = get_option('ws_plugin__qcache_options')) && $old_options + ) // Before the rewrite. Only if QC was previously configured w/ options. { + $this->options['version'] = '2.3.6'; // Old options. + if(!isset($options['enable']) && isset($old_options['enabled'])) $options['enable'] = (string)(integer)$old_options['enabled']; @@ -277,16 +239,15 @@ public function setup() if(!$this->options['base_dir']) // Security enhancement; NEVER allow this to be empty. $this->options['base_dir'] = $this->default_options['base_dir']; - $this->update_cap = apply_filters(__METHOD__.'__update_cap', 'update_plugins'); - $this->network_cap = apply_filters(__METHOD__.'__network_cap', 'manage_network_plugins'); $this->cap = apply_filters(__METHOD__.'__cap', 'activate_plugins'); + $this->network_cap = apply_filters(__METHOD__.'__network_cap', 'manage_network_plugins'); + $this->update_cap = apply_filters(__METHOD__.'__update_cap', 'update_plugins'); add_action('init', array($this, 'check_advanced_cache')); add_action('init', array($this, 'check_blog_paths')); add_action('wp_loaded', array($this, 'actions')); add_action('admin_init', array($this, 'check_version')); - add_action('admin_init', array($this, 'rewrite_notice')); add_action('admin_init', array($this, 'check_update_sync_version')); add_action('admin_bar_menu', array($this, 'admin_bar_menu')); @@ -357,12 +318,9 @@ public function setup() if((integer)$this->options['crons_setup'] < 1398051975) { wp_clear_scheduled_hook('_cron_'.__NAMESPACE__.'_auto_cache'); - wp_clear_scheduled_hook('_cron_'.__NAMESPACE__.'_cleanup'); - - wp_clear_scheduled_hook('ws_plugin__qcache_garbage_collector__schedule'); - wp_clear_scheduled_hook('ws_plugin__qcache_auto_cache_engine__schedule'); - wp_schedule_event(time() + 60, 'every15m', '_cron_'.__NAMESPACE__.'_auto_cache'); + + wp_clear_scheduled_hook('_cron_'.__NAMESPACE__.'_cleanup'); wp_schedule_event(time() + 60, 'daily', '_cron_'.__NAMESPACE__.'_cleanup'); $this->options['crons_setup'] = (string)time(); @@ -417,97 +375,28 @@ public function activate() */ public function check_version() { - /* - * The current version reflected by the configured option key: `version`. - * If they just upgraded, this represents the previous version. - */ $current_version = $prev_version = $this->options['version']; - - /* - * Check the current version; is it up-to-date? - */ if(version_compare($current_version, $this->version, '>=')) return; // Nothing to do; we've already upgraded them. - /* - * Update their current version to this version. - */ $current_version = $this->options['version'] = $this->version; - update_option(__NAMESPACE__.'_options', $this->options); + update_option(__NAMESPACE__.'_options', $this->options); // Updates version. if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->options); - /* ------- START: VERSION-SPECIFIC UPGRADE HANDLERS --------------------------- */ - - /* - * Upgrading from a version prior to v140104 where we introduced feed caching. - */ - if(version_compare($prev_version, '140104', '<')) // When this sort of update occurs, we issue a notice about this new feature. - $this->enqueue_notice(__('Quick Cache Feature Notice: This version of Quick Cache adds new options for Feed caching. Feed caching is now disabled by default. If you wish to enable feed caching, please visit the Quick Cache options panel.', $this->text_domain)); - - /* - * Upgrading from a version prior to v140605, where we introduced a branched cache structure, also also moved to a base directory layout. - * See - */ - if(version_compare($prev_version, '140605', '<')) // i.e. Upgrading from a version before the branched/base structures. - { - if(!empty($this->options['cache_dir'])) // From the previous release. - { - $wp_content_dir_relative = // Considers custom `WP_CONTENT_DIR` locations. - trim(str_replace(ABSPATH, '', WP_CONTENT_DIR), '\\/'." \t\n\r\0\x0B"); - - $this->options['base_dir'] = $this->options['cache_dir'] = trim($this->options['cache_dir'], '\\/'." \t\n\r\0\x0B"); - if(!$this->options['base_dir'] || $this->options['base_dir'] === $wp_content_dir_relative.'/cache') - $this->options['base_dir'] = $wp_content_dir_relative.'/cache/quick-cache'; - - if($this->options['cache_dir']) // Wipe old files? - $this->wipe_cache(FALSE, ABSPATH.$this->options['cache_dir']); - - unset($this->options['cache_dir']); - update_option(__NAMESPACE__.'_options', $this->options); - if(is_multisite()) update_site_option(__NAMESPACE__.'_options', $this->options); - } - $this->enqueue_notice(__('Quick Cache Feature Notice: This version of Quick Cache introduces a new Branched Cache Structure and several other new features.', $this->text_domain)); - } - /* ------- END: VERSION-SPECIFIC UPGRADE HANDLERS ----------------------------- */ + require_once dirname(__FILE__).'/includes/version-specific-upgrade.php'; + new version_specific_upgrade($prev_version); - /* - * If enabled, lets recompile Quick Cache. - */ - if($this->options['enable']) // Only if enabled. + if($this->options['enable']) // Recompile. { $this->add_wp_cache_to_wp_config(); $this->add_advanced_cache(); $this->update_blog_paths(); } - /* - * Wipe the cache on upgrade (always). - */ $this->wipe_cache(); // Always wipe the cache; no exceptions. - /* - * Common upgrade notice. This applies to all upgrades regardless of version. - * NOTE: the use of `TRUE` in the 3rd argument puts this notice first; even though it comes last down here. - */ $this->enqueue_notice(__('Quick Cache: detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)', $this->text_domain), '', TRUE); } - /** - * Display notice to site owners using a really old version of Quick Cache. - * - * @since 140422 First documented version. - * - * @attaches-to `admin_init` hook. - */ - public function rewrite_notice() - { - if(!get_option('ws_plugin__qcache_configured')) - return; // Nothing to do in this case. - - delete_option('ws_plugin__qcache_configured'); // One-time only. - - $this->enqueue_notice(__('Quick Cache: this version is a complete rewrite :-) Please review your Quick Cache options carefully!', $this->text_domain)); - } - /** * Plugin deactivation hook. * @@ -533,10 +422,6 @@ public function deactivate() delete_option(__NAMESPACE__.'_notices'); delete_option(__NAMESPACE__.'_errors'); - delete_option('ws_plugin__qcache_options'); - delete_option('ws_plugin__qcache_notices'); - delete_option('ws_plugin__qcache_configured'); - wp_clear_scheduled_hook('_cron_'.__NAMESPACE__.'_auto_cache'); wp_clear_scheduled_hook('_cron_'.__NAMESPACE__.'_cleanup'); } @@ -553,12 +438,11 @@ public function deactivate() */ public function url($file = '', $scheme = '') { - static $plugin_directory; // Static cache. - - if(!isset($plugin_directory)) // Not cached yet? - $plugin_directory = rtrim(plugin_dir_url($this->file), '/'); + if(!isset(static::$static[__FUNCTION__]['plugin_dir'])) + static::$static[__FUNCTION__]['plugin_dir'] = rtrim(plugin_dir_url($this->file), '/'); + $plugin_dir =& static::$static[__FUNCTION__]['plugin_dir']; - $url = $plugin_directory.(string)$file; + $url = $plugin_dir.(string)$file; if($scheme) // A specific URL scheme? $url = set_url_scheme($url, (string)$scheme); @@ -566,22 +450,6 @@ public function url($file = '', $scheme = '') return apply_filters(__METHOD__, $url, get_defined_vars()); } - /** - * Escape single quotes. - * - * @since 140422 First documented version. - * - * @param string $string Input string to escape. - * @param integer $times Optional. Defaults to one escape char; e.g. `\'`. - * If you need to escape more than once, set this to something > `1`. - * - * @return string Escaped string; e.g. `Raam\'s the lead developer`. - */ - public function esc_sq($string, $times = 1) - { - return str_replace("'", str_repeat('\\', abs($times))."'", (string)$string); - } - /** * Plugin action handler. * @@ -592,7 +460,6 @@ public function esc_sq($string, $times = 1) public function actions() { if(empty($_REQUEST[__NAMESPACE__])) return; - require_once dirname(__FILE__).'/includes/actions.php'; } @@ -795,6 +662,24 @@ public function add_menu_pages() $this->update_cap, __NAMESPACE__.'-update-sync', array($this, 'menu_page_update_sync')); } + /** + * Adds link(s) to Quick Cache row on the WP plugins page. + * + * @since 140422 First documented version. + * + * @attaches-to `plugin_action_links_'.plugin_basename($this->file)` filter. + * + * @param array $links An array of the existing links provided by WordPress. + * + * @return array Revised array of links. + */ + public function add_settings_link($links) + { + $links[] = ''.__('Settings', $this->text_domain).''; + + return apply_filters(__METHOD__, $links, get_defined_vars()); + } + /** * Loads the admin menu page options. * @@ -1073,7 +958,6 @@ public function auto_cache() require_once dirname(__FILE__).'/includes/auto-cache.php'; $auto_cache = new auto_cache(); - $auto_cache->run(); } /** @@ -1117,13 +1001,11 @@ public function wipe_cache($manually = FALSE, $also_wipe_dir = '') $counter += $this->wipe_htmlc_cache($manually); - $cache_dir = $this->abspath_to($this->cache_sub_dir); - // @TODO When set_time_limit() is disabled by PHP configuration, display a warning message to users upon plugin activation. @set_time_limit(1800); // In case of HUGE sites w/ a very large directory. Errors are ignored in case `set_time_limit()` is disabled. /** @var $_dir_file \RecursiveDirectoryIterator For IDEs. */ - if(is_dir($cache_dir)) foreach($this->dir_regex_iteration($cache_dir, '/.+/') as $_dir_file) + if(is_dir($cache_dir = $this->cache_dir())) foreach($this->dir_regex_iteration($cache_dir, '/.+/') as $_dir_file) { if(($_dir_file->isFile() || $_dir_file->isLink()) && strpos($_dir_file->getSubPathname(), '/') !== FALSE) // Don't delete files in the immediate directory; e.g. `qc-advanced-cache` or `.htaccess`, etc. @@ -1171,8 +1053,9 @@ public function wipe_htmlc_cache($manually = FALSE) { $counter = 0; // Initialize. - $cache_dir_public = $this->abspath_to($this->htmlc_cache_sub_dir_public); - $cache_dir_private = $this->abspath_to($this->htmlc_cache_sub_dir_private); + $cache_dir_public = $this->wp_content_dir_to($this->htmlc_cache_sub_dir_public); + $cache_dir_private = $this->wp_content_dir_to($this->htmlc_cache_sub_dir_private); + if(!is_dir($cache_dir_public) && !is_dir($cache_dir_private)) return $counter; // Nothing to do in this case. @@ -1217,7 +1100,7 @@ public function clear_cache($manually = FALSE) $counter += $this->clear_htmlc_cache($manually); - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. // @TODO When set_time_limit() is disabled by PHP configuration, display a warning message to users upon plugin activation. @@ -1268,8 +1151,9 @@ public function clear_htmlc_cache($manually = FALSE) if(($host_dir_token = $this->host_dir_token(TRUE)) === '/') $host_dir_token = ''; // Not necessary in this case. - $cache_dir_public = $this->abspath_to($this->htmlc_cache_sub_dir_public.$host_dir_token.'/'.$host_token); - $cache_dir_private = $this->abspath_to($this->htmlc_cache_sub_dir_private.$host_dir_token.'/'.$host_token); + $cache_dir_public = $this->wp_content_dir_to($this->htmlc_cache_sub_dir_public.$host_dir_token.'/'.$host_token); + $cache_dir_private = $this->wp_content_dir_to($this->htmlc_cache_sub_dir_private.$host_dir_token.'/'.$host_token); + if(!is_dir($cache_dir_public) && !is_dir($cache_dir_private)) return $counter; // Nothing to do in this case. @@ -1309,7 +1193,7 @@ public function purge_cache() { $counter = 0; // Initialize. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. $max_age = strtotime('-'.$this->options['cache_max_age']); if(!is_dir($cache_dir)) return $counter; // Nothing to do. @@ -1451,7 +1335,7 @@ public function auto_purge_post_cache($id, $force = FALSE) if($post_status === 'trash' && !$force) return $counter; // Nothing to do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. $counter += $this->auto_purge_home_page_cache(); // If enabled and necessary. @@ -1554,7 +1438,7 @@ public function auto_purge_home_page_cache() if(!$this->options['cache_purge_home_page_enable']) return $counter; // Nothing to do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. $cache_path_no_scheme_quv_ext = $this->url_to_cache_path(home_url('/'), '', '', $this::CACHE_PATH_NO_SCHEME | $this::CACHE_PATH_NO_PATH_INDEX | $this::CACHE_PATH_NO_QUV | $this::CACHE_PATH_NO_EXT); @@ -1610,7 +1494,7 @@ public function auto_purge_posts_page_cache() if(!$this->options['cache_purge_posts_page_enable']) return $counter; // Nothing to do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. $show_on_front = get_option('show_on_front'); @@ -1687,7 +1571,7 @@ public function auto_purge_author_page_cache($post_ID, $post_after, $post_before if(!$this->options['cache_purge_author_page_enable']) return $counter; // Nothing to do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. /* @@ -1805,7 +1689,7 @@ public function auto_purge_post_terms_cache($id, $force = FALSE) if($post_status === 'future' && !$force) return $counter; // Nothing to do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. /* @@ -1973,7 +1857,7 @@ public function auto_purge_user_cache($user_id) if(!$user_id) return $counter; // No can-do. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_dir($cache_dir)) return $counter; // Nothing to do. $regex = '/\.u\/'.preg_quote($user_id, '/').'[.\/]/'; // This user. @@ -2074,7 +1958,7 @@ public function auto_purge_user_cache_cur() /** * This constructs an absolute server directory path (no trailing slashes); - * which is always nested into {@link \ABSPATH} and the configured `base_dir` option value. + * which is always nested into {@link \WP_CONTENT_DIR} and the configured `base_dir` option value. * * @since 140605 Moving to a base directory structure. * @@ -2085,22 +1969,22 @@ public function auto_purge_user_cache_cur() * @throws \exception If `base_dir` is empty when this method is called upon; * i.e. if you attempt to call upon this method before {@link setup()} runs. */ - public function abspath_to($rel_dir_file) + public function wp_content_dir_to($rel_dir_file) { $rel_dir_file = trim((string)$rel_dir_file, '\\/'." \t\n\r\0\x0B"); if(empty($this->options['base_dir'])) // Security enhancement; NEVER allow this to be empty. throw new \exception(__('Doing it wrong! Missing `base_dir` option value. MUST call this method after `setup()`.', $this->text_domain)); - $abspath = ABSPATH.$this->options['base_dir']; - if(isset($rel_dir_file[0])) $abspath .= '/'.$rel_dir_file; + $wp_content_dir_to = WP_CONTENT_DIR.'/'.$this->options['base_dir']; + if(isset($rel_dir_file[0])) $wp_content_dir_to .= '/'.$rel_dir_file; - return apply_filters(__METHOD__, $abspath, get_defined_vars()); + return apply_filters(__METHOD__, $wp_content_dir_to, get_defined_vars()); } /** * This constructs a relative/base directory path (no leading/trailing slashes). - * Always relative to {@link \ABSPATH}. Depends on the configured `base_dir` option value. + * Always relative to {@link \WP_CONTENT_DIR}. Depends on the configured `base_dir` option value. * * @since 140605 Moving to a base directory structure. * @@ -2118,10 +2002,10 @@ public function basepath_to($rel_dir_file) if(empty($this->options['base_dir'])) // Security enhancement; NEVER allow this to be empty. throw new \exception(__('Doing it wrong! Missing `base_dir` option value. MUST call this method after `setup()`.', $this->text_domain)); - $basepath = $this->options['base_dir']; - if(isset($rel_dir_file[0])) $basepath .= '/'.$rel_dir_file; + $basepath_to = $this->options['base_dir']; + if(isset($rel_dir_file[0])) $basepath_to .= '/'.$rel_dir_file; - return apply_filters(__METHOD__, $basepath, get_defined_vars()); + return apply_filters(__METHOD__, $basepath_to, get_defined_vars()); } /** @@ -2251,7 +2135,7 @@ public function check_advanced_cache() if(!empty($_REQUEST[__NAMESPACE__])) return; // Skip on plugin actions. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_file($cache_dir.'/qc-advanced-cache')) $this->add_advanced_cache(); @@ -2282,7 +2166,7 @@ public function add_advanced_cache() if(!$this->remove_advanced_cache()) return FALSE; // Still exists. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php'; $advanced_cache_template = dirname(__FILE__).'/includes/advanced-cache.tpl.php'; @@ -2359,8 +2243,8 @@ public function add_advanced_cache() unset($_option, $_value, $_values, $_response); // Housekeeping. // Make it possible for the `advanced-cache.php` handler to find the plugin directory reliably. - $advanced_cache_contents = str_replace("'%%".__NAMESPACE__."_PLUGIN_FILE%%'", // e.g. `QUICK_CACHE_PLUGIN_FILE`. - "'".$this->esc_sq($this->file)."'", $advanced_cache_contents); + $advanced_cache_contents = str_ireplace("'%%".__NAMESPACE__."_PLUGIN_FILE%%'", // e.g. `QUICK_CACHE_PLUGIN_FILE`. + "'".$this->esc_sq($this->file)."'", $advanced_cache_contents); // Ignore; this is created by Quick Cache; and we don't need to obey in this case. #if(defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) @@ -2480,7 +2364,7 @@ public function check_blog_paths() if(!empty($_REQUEST[__NAMESPACE__])) return; // Skip on plugin actions. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Current cache directory. if(!is_file($cache_dir.'/qc-blog-paths')) $this->update_blog_paths(); @@ -2509,7 +2393,7 @@ public function update_blog_paths($enable_live_network_counts = NULL) if(!is_multisite()) return $value; // N/A. - $cache_dir = $this->abspath_to($this->cache_sub_dir); + $cache_dir = $this->cache_dir(); // Cache dir. if(!is_dir($cache_dir)) mkdir($cache_dir, 0775, TRUE); @@ -2530,392 +2414,6 @@ public function update_blog_paths($enable_live_network_counts = NULL) } return $value; // Pass through untouched (always). } - - /** - * Adds link(s) to Quick Cache row on the WP plugins page. - * - * @since 140422 First documented version. - * - * @attaches-to `plugin_action_links_'.plugin_basename($this->file)` filter. - * - * @param array $links An array of the existing links provided by WordPress. - * - * @return array Revised array of links. - */ - public function add_settings_link($links) - { - $links[] = ''.__('Settings', $this->text_domain).''; - - return apply_filters(__METHOD__, $links, get_defined_vars()); - } - - /* - * See also: `advanced-cache.tpl.php` duplicates. - * @TODO Find a way to centralize this section so it can be shared between both classes easily. - */ - - /** - * Exclude scheme from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_SCHEME = 1; - - /** - * Exclude host (i.e. domain name) from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_HOST = 2; - - /** - * Exclude path from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_PATH = 4; - - /** - * Exclude path index (i.e. no default `index`) from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_PATH_INDEX = 8; - - /** - * Exclude query, user & version salt from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_QUV = 16; - - /** - * Exclude query string from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_QUERY = 32; - - /** - * Exclude user token from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_USER = 64; - - /** - * Exclude version salt from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_VSALT = 128; - - /** - * Exclude extension from cache path. - * - * @since 140422 First documented version. - * - * @var integer Part of a bitmask. - */ - const CACHE_PATH_NO_EXT = 256; - - /** - * Converts a URL into a `cache/path`. - * - * @since 140422 First documented version. - * - * @param string $url The input URL to convert. - * @param string $with_user_token Optional user token (if applicable). - * @param string $with_version_salt Optional version salt (if applicable). - * @param integer $flags Optional flags; a bitmask provided by `CACHE_PATH_*` constants. - * - * @return string The resulting `cache/path` based on the input `$url`. - */ - public function url_to_cache_path($url, $with_user_token = '', $with_version_salt = '', $flags = 0) - { - $cache_path = ''; // Initialize. - $url = trim((string)$url); - $with_user_token = trim((string)$with_user_token); - $with_version_salt = trim((string)$with_version_salt); - - if($url && strpos($url, '://') === FALSE) - $url = '//'.ltrim($url, '/'); - - if(!$url || !($url = parse_url($url))) - return ''; // Invalid URL. - - if(!($flags & $this::CACHE_PATH_NO_SCHEME)) - { - if(!empty($url['scheme'])) - $cache_path .= $url['scheme'].'/'; - else $cache_path .= is_ssl() ? 'https/' : 'http/'; - } - if(!($flags & $this::CACHE_PATH_NO_HOST)) - { - if(!empty($url['host'])) - $cache_path .= $url['host'].'/'; - else $cache_path .= $_SERVER['HTTP_HOST'].'/'; - } - if(!($flags & $this::CACHE_PATH_NO_PATH)) - { - if(!empty($url['path']) && strlen($url['path'] = trim($url['path'], '\\/'." \t\n\r\0\x0B"))) - $cache_path .= $url['path'].'/'; - else if(!($flags & $this::CACHE_PATH_NO_PATH_INDEX)) $cache_path .= 'index/'; - } - if($this->is_extension_loaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) - $cache_path = mb_strtolower($cache_path, 'UTF-8'); - $cache_path = str_replace('.', '-', strtolower($cache_path)); - - if(!($flags & $this::CACHE_PATH_NO_QUV)) - { - if(!($flags & $this::CACHE_PATH_NO_QUERY)) - if(isset($url['query']) && $url['query'] !== '') - $cache_path = rtrim($cache_path, '/').'.q/'.md5($url['query']).'/'; - - if(!($flags & $this::CACHE_PATH_NO_USER)) - if($with_user_token !== '') // Allow a `0` value if desirable. - $cache_path = rtrim($cache_path, '/').'.u/'.str_replace(array('/', '\\'), '-', $with_user_token).'/'; - - if(!($flags & $this::CACHE_PATH_NO_VSALT)) - if($with_version_salt !== '') // Allow a `0` value if desirable. - $cache_path = rtrim($cache_path, '/').'.v/'.str_replace(array('/', '\\'), '-', $with_version_salt).'/'; - } - $cache_path = trim(preg_replace('/\/+/', '/', $cache_path), '/'); - $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path); - - if(!($flags & $this::CACHE_PATH_NO_EXT)) - $cache_path .= '.html'; - - return $cache_path; // Do not filter; exists in advanced-cache too. - } - - /** - * Produces a token based on the current `$_SERVER['HTTP_HOST']`. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Token based on the current `$_SERVER['HTTP_HOST']`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function host_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $host = strtolower($_SERVER['HTTP_HOST']); - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host), '-') : $host; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces a token based on the current site's base directory. - * - * @since 140605 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Produces a token based on the current site's base directory; - * (i.e. in the case of a sub-directory multisite network). - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see clear_cache() - * @see update_blog_paths() - */ - public function host_base_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $host_base_token = '/'; // Assume NOT multisite; or running it's own domain. - - if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) - { // Multisite w/ sub-directories; need a valid sub-directory token. - - if(defined('PATH_CURRENT_SITE')) $host_base_token = PATH_CURRENT_SITE; - else if(!empty($GLOBALS['base'])) $host_base_token = $GLOBALS['base']; - - $host_base_token = trim($host_base_token, '\\/'." \t\n\r\0\x0B"); - $host_base_token = (isset($host_base_token[0])) ? '/'.$host_base_token.'/' : '/'; - } - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_base_token), '-') : $host_base_token; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces a token based on the current blog's sub-directory. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the token is returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Produces a token based on the current blog sub-directory - * (i.e. in the case of a sub-directory multisite network). - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see clear_cache() - * @see update_blog_paths() - */ - public function host_dir_token($dashify = FALSE) - { - $dashify = (integer)$dashify; - static $tokens = array(); // Static cache. - if(isset($tokens[$dashify])) return $tokens[$dashify]; - - $cache_dir = $this->abspath_to($this->cache_sub_dir); - $host_dir_token = '/'; // Assume NOT multisite; or running it's own domain. - - if(is_multisite() && (!defined('SUBDOMAIN_INSTALL') || !SUBDOMAIN_INSTALL)) - { // Multisite w/ sub-directories; need a valid sub-directory token. - - $uri_minus_base = // Supports `/sub-dir/child-blog-sub-dir/` also. - preg_replace('/^'.preg_quote($this->host_base_token(), '/').'/', '', $_SERVER['REQUEST_URI']); - - list($host_dir_token) = explode('/', trim($uri_minus_base, '/')); - $host_dir_token = (isset($host_dir_token[0])) ? '/'.$host_dir_token.'/' : '/'; - - if($host_dir_token !== '/' // Perhaps NOT the main site? - && (!is_file($cache_dir.'/qc-blog-paths') // NOT a read/valid blog path? - || !in_array($host_dir_token, unserialize(file_get_contents($cache_dir.'/qc-blog-paths')), TRUE)) - ) $host_dir_token = '/'; // Main site; e.g. this is NOT a real/valid child blog path. - } - $token_value = ($dashify) ? trim(preg_replace('/[^a-z0-9\/]/i', '-', $host_dir_token), '-') : $host_dir_token; - - return ($tokens[$dashify] = $token_value); - } - - /** - * Produces tokens for the current site's base directory & current blog's sub-directory. - * - * @since 140422 First documented version. - * - * @param boolean $dashify Optional, defaults to a `FALSE` value. - * If `TRUE`, the tokens are returned with dashes in place of `[^a-z0-9\/]`. - * - * @return string Tokens for the current site's base directory & current blog's sub-directory. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - * - * @see clear_cache() - * @see update_blog_paths() - */ - public function host_base_dir_tokens($dashify = FALSE) - { - return preg_replace('/\/{2,}/', '/', $this->host_base_token($dashify).$this->host_dir_token($dashify)); - } - - /** - * Recursive directory iterator based on a regex pattern. - * - * @since 140422 First documented version. - * - * @param string $dir An absolute server directory path. - * @param string $regex A regex pattern; compares to each full file path. - * - * @return \RegexIterator Navigable with {@link \foreach()}; where each item - * is a {@link \RecursiveDirectoryIterator}. - */ - public function dir_regex_iteration($dir, $regex) - { - $dir_iterator = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_SELF | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS); - $iterator_iterator = new \RecursiveIteratorIterator($dir_iterator, \RecursiveIteratorIterator::CHILD_FIRST); - $regex_iterator = new \RegexIterator($iterator_iterator, $regex, \RegexIterator::MATCH, \RegexIterator::USE_KEY); - - return apply_filters(__METHOD__, $regex_iterator, get_defined_vars()); - } - - /** - * Checks if a PHP extension is loaded up. - * - * @since 140422 First documented version. - * - * @param string $extension A PHP extension slug (i.e. extension name). - * - * @return boolean `TRUE` if the extension is loaded; else `FALSE`. - * - * @note The return value of this function is cached to reduce overhead on repeat calls. - */ - public function is_extension_loaded($extension) - { - static $is = array(); // Static cache. - if(isset($is[$extension])) return $is[$extension]; - return ($is[$extension] = extension_loaded($extension)); - } - - /* - * ------------ end section to centralize in a future release. - */ - - /** - * Is a particular function possible in every way? - * - * @since 140422 First documented version. - * - * @param string $function A PHP function (or user function) to check. - * - * @return string `TRUE` if the function is possible; else `FALSE`. - * - * @note This checks (among other things) if the function exists and that it's callable. - * It also checks the currently configured `disable_functions` and `suhosin.executor.func.blacklist`. - */ - public function function_is_possible($function) - { - static $disabled_functions; // Static cache. - - if(!isset($disabled_functions) && function_exists('ini_get')) - { - $disabled_functions = array(); - - if(($disable_functions = trim(ini_get('disable_functions')))) - $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($disable_functions), NULL, PREG_SPLIT_NO_EMPTY)); - - if(($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) - $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($blacklist_functions), NULL, PREG_SPLIT_NO_EMPTY)); - } - $possible = TRUE; // Assume it is.. (intialize). - - if(!function_exists($function) || !is_callable($function) - || ($disabled_functions && in_array(strtolower($function), $disabled_functions, TRUE)) - ) $possible = FALSE; // Not possible. - - return apply_filters(__METHOD__, $possible, get_defined_vars()); - } - - /** - * Apache `.htaccess` rules that deny public access to the contents of a directory. - * - * @since 140422 First documented version. - * - * @var string `.htaccess` fules. - */ - public $htaccess_deny = "\n\tRequire all denied\n\n\n\tdeny from all\n"; } /**