diff --git a/changelog.txt b/changelog.txt index d5253d3..6c157a8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,33 @@ += v22.07.03 (2023-02-07) = +- Fixed: Tweaks::woocommerce_misc() -> Check if action_scheduler_migration_status is complete to prevent the list on the Scheduled Actions page from disappearing. +- Fixed: Tweaks::woocommerce_widget_remove() -> The classic widget is not disabled. +- Fixed: Plugin::get_precache_maxfile() -> Invalid constant, replace maxfile with precache_maxfile. +- Fixed: Filesystem::sanitize_precache_maxfile() -> Set the limit to 100 by default. +- Fixed: Becache::export() -> Invalid expiration time. Already in timestamp format not in seconds. +- Fixed: WP_Object_Cache::dc_save() -> Serialize twice when checking object size. +- Fixed: Configuration -> A notice is not shown when the constant is already defined. +- Added: Configuration -> Storage Options, Check file limits in real-time and Exclude Empty Object Data. +- Added: Configuration -> Runtime Options, Deactivate Concatenate WP-Admin Scripts and Deactivate WP Cron. +- Added: WP-CLI command -> run:optimizedb. +- Added: DOCKET_CACHE_MAXFILE_LIVECHECK constant to enable checking file limits in real-time. +- Added: DOCKET_CACHE_PRECACHE_MAXKEY, DOCKET_CACHE_PRECACHE_MAXGROUP constant to limit cache keys and groups. +- Added: DOCKET_CACHE_STALECACHE_IGNORE constant to enable excluding stale cache from being stored on disk. +- Added: DOCKET_CACHE_EMPTYCACHE constant to enable excluding empty caches from being stored on disk. +- Added: DOCKET_CACHE_AUTOUPDATE_TOGGLE constant, only to sync with WordPress auto_update_plugins option. +- Added: DOCKET_CACHE_GCRON_DISABLED constant to disable garbage collector cron event. +- Added: Filesystem::suspend_cache_write() -> Temporarily suspends new cache from being stored on disk. +- Changed: DOCKET_CACHE_AUTOUPDATE constant can only be defined manually to force an automatic update. +- Improved: Increase timeout limit if lower than 180 seconds. +- Improved: Constans::maybe_define() -> Keep track of constants that have been defined in the $GLOBAL['DOCKET_CACHE_RUNTIME'] list. +- Improved: WP_Object_Cache::maybe_expire() -> Set expiration to 1 day for key/group matches with the stale cache. +- Improved: Event::garbage_collector() -> Improve wc_cache filtering and other possible stale caches. +- Improved: WP_Object_Cache::dc_code() -> Use native var_export for data type objects and arrays if only have stdClass. +- Removed: Event::watchproc() -> No longer needed. +- Updated: DOCKET_CACHE_ADVCPOST_POSTTYPE -> Set the built-in Post Type as the default. +- Updated: Filesystem::get_max_execution_time() -> Accept value to set time limit. + +Thanks to Kevin Shenk of Avunu LLC for providing access to the staging server for testing purposes. + = v22.07.02 (2022-12-10) = - Fixed: Tweaks::cache_http_response() -> Default TTL. - Fixed: Tweaks::wpservehappy() -> missing array key. diff --git a/dist/docket-cache.zip b/dist/docket-cache.zip index 3519a7c..ad21303 100644 Binary files a/dist/docket-cache.zip and b/dist/docket-cache.zip differ diff --git a/docket-cache.php b/docket-cache.php index 2c2070b..9fb6c8a 100644 --- a/docket-cache.php +++ b/docket-cache.php @@ -12,8 +12,8 @@ * @wordpress-plugin * Plugin Name: Docket Cache * Plugin URI: https://docketcache.com/?utm_source=wp-plugins&utm_campaign=plugin-uri&utm_medium=wp-dash - * Version: 22.07.02 - * VerPrev: 21.07.01 + * Version: 22.07.03 + * VerPrev: 22.07.02 * Description: A persistent object cache stored as a plain PHP code, accelerates caching with OPcache backend. * GitHub Plugin URI: https://github.com/nawawi/docket-cache * Author: Nawawi Jamili diff --git a/includes/admin/config.php b/includes/admin/config.php index 6d47ad5..0035253 100644 --- a/includes/admin/config.php +++ b/includes/admin/config.php @@ -169,7 +169,7 @@ - tooltip('woowidgetoff'); ?> + tooltip('woowidgetoff'); ?> config_select_bool('woowidgetoff'); ?> @@ -283,6 +283,7 @@ + @@ -302,124 +303,156 @@ 'off' => __('Disable', 'docket-cache'), ] ); -?> + ?> tooltip('rtpostrevision'); ?> config_select_set( - 'rtpostrevision', - [ - 'default' => __('Default', 'docket-cache'), - '3' => __('Limit to 3 Revisions', 'docket-cache'), - '5' => __('Limit to 5 Revisions', 'docket-cache'), - 'on' => __('No Limit', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ] -); -?> + echo $this->config_select_set( + 'rtpostrevision', + [ + 'default' => __('Default', 'docket-cache'), + '3' => __('Limit to 3 Revisions', 'docket-cache'), + '5' => __('Limit to 5 Revisions', 'docket-cache'), + 'on' => __('No Limit', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ] + ); + ?> tooltip('rtpostemptytrash'); ?> config_select_set( - 'rtpostemptytrash', - [ - 'default' => __('Default', 'docket-cache'), - '7' => __('Empty In 7 Days', 'docket-cache'), - '14' => __('Empty In 14 Days', 'docket-cache'), - '30' => __('Empty In 30 Days', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ] -); -?> + echo $this->config_select_set( + 'rtpostemptytrash', + [ + 'default' => __('Default', 'docket-cache'), + '7' => __('Empty In 7 Days', 'docket-cache'), + '14' => __('Empty In 14 Days', 'docket-cache'), + '30' => __('Empty In 30 Days', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ] + ); + ?> tooltip('rtimageoverwrite'); ?> config_select_set( - 'rtimageoverwrite', - [ - 'default' => __('Default', 'docket-cache'), - 'on' => __('Enable', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ], - !empty($GLOBALS[$this->vcf()->px('rtimageoverwrite_false')]) && IMAGE_EDIT_OVERWRITE ? 'on' : $this->vcf()->dcvalue('rtimageoverwrite') -); -?> + echo $this->config_select_set( + 'rtimageoverwrite', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtimageoverwrite_false')]) && IMAGE_EDIT_OVERWRITE ? 'on' : $this->vcf()->dcvalue('rtimageoverwrite') + ); + ?> tooltip('rtwpcoreupdate'); ?> config_select_set( - 'rtwpcoreupdate', - [ - 'default' => __('Default', 'docket-cache'), - 'off' => __('Enable', 'docket-cache'), - 'on' => __('Disable', 'docket-cache'), - ], - !empty($GLOBALS[$this->vcf()->px('rtwpcoreupdate_false')]) && !(bool) WP_AUTO_UPDATE_CORE ? 'on' : $this->vcf()->dcvalue('rtwpcoreupdate') -); -?> + echo $this->config_select_set( + 'rtwpcoreupdate', + [ + 'default' => __('Default', 'docket-cache'), + 'off' => __('Enable', 'docket-cache'), + 'on' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtwpcoreupdate_false')]) && !(bool) WP_AUTO_UPDATE_CORE ? 'on' : $this->vcf()->dcvalue('rtwpcoreupdate') + ); + ?> tooltip('rtpluginthemeeditor'); ?> config_select_set( - 'rtpluginthemeeditor', - [ - 'default' => __('Default', 'docket-cache'), - 'on' => __('Enable', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ], - !empty($GLOBALS[$this->vcf()->px('rtpluginthemeeditor_false')]) && DISALLOW_FILE_EDIT ? 'on' : $this->vcf()->dcvalue('rtpluginthemeeditor') -); -?> + echo $this->config_select_set( + 'rtpluginthemeeditor', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtpluginthemeeditor_false')]) && DISALLOW_FILE_EDIT ? 'on' : $this->vcf()->dcvalue('rtpluginthemeeditor') + ); + ?> tooltip('rtpluginthemeinstall'); ?> config_select_set( - 'rtpluginthemeinstall', - [ - 'default' => __('Default', 'docket-cache'), - 'on' => __('Enable', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ], - !empty($GLOBALS[$this->vcf()->px('rtpluginthemeinstall_false')]) && DISALLOW_FILE_MODS ? 'on' : $this->vcf()->dcvalue('rtpluginthemeinstall') -); -?> + echo $this->config_select_set( + 'rtpluginthemeinstall', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtpluginthemeinstall_false')]) && DISALLOW_FILE_MODS ? 'on' : $this->vcf()->dcvalue('rtpluginthemeinstall') + ); + ?> + + + + tooltip('rtconcatenatescripts'); ?> + + config_select_set( + 'rtconcatenatescripts', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtconcatenatescripts_false')]) && !(bool) CONCATENATE_SCRIPTS ? 'on' : $this->vcf()->dcvalue('rtconcatenatescripts') + ); + ?> + + + + tooltip('rtdisablewpcron'); ?> + + config_select_set( + 'rtdisablewpcron', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + !empty($GLOBALS[$this->vcf()->px('rtdisablewpcron_false')]) && DISABLE_WP_CRON ? 'on' : $this->vcf()->dcvalue('rtdisablewpcron') + ); + ?> vcf()->px('rtwpdebug_false')]) && WP_DEBUG ? 'on' : $this->vcf()->dcvalue('rtwpdebug'); -?> + ?> >tooltip('rtwpdebug'); ?> config_select_set( - 'rtwpdebug', - [ - 'default' => __('Default', 'docket-cache'), - 'on' => __('Enable', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ], - $rtwpdebug_default - ); -?> + echo $this->config_select_set( + 'rtwpdebug', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + $rtwpdebug_default + ); + ?> @@ -436,35 +469,37 @@ ], !empty($GLOBALS[$this->vcf()->px('rtwpdebugdisplay_false')]) && WP_DEBUG_DISPLAY ? 'on' : $this->vcf()->dcvalue('rtwpdebugdisplay') ); - ?> + ?> vcf()->px('rtwpdebuglog_false')]) && WP_DEBUG_LOG ? 'on' : $this->vcf()->dcvalue('rtwpdebuglog'); - $error_log = \ini_get('error_log'); - ?> + $rtwpdebuglog_default = !empty($GLOBALS[$this->vcf()->px('rtwpdebuglog_false')]) && WP_DEBUG_LOG ? 'on' : $this->vcf()->dcvalue('rtwpdebuglog'); + $error_log = \ini_get('error_log'); + ?> tooltip('rtwpdebuglog'); ?> config_select_set( - 'rtwpdebuglog', - [ - 'default' => __('Default', 'docket-cache'), - 'on' => __('Enable', 'docket-cache'), - 'off' => __('Disable', 'docket-cache'), - ], - $rtwpdebuglog_default - ); + echo $this->config_select_set( + 'rtwpdebuglog', + [ + 'default' => __('Default', 'docket-cache'), + 'on' => __('Enable', 'docket-cache'), + 'off' => __('Disable', 'docket-cache'), + ], + $rtwpdebuglog_default + ); - if (\defined('WP_DEBUG') && WP_DEBUG && \defined('WP_DEBUG_LOG') && WP_DEBUG_LOG && @is_file($error_log) && is_readable($error_log)) { - $error_log = basename($error_log); - echo 'View Log'; - } - ?> + if (\defined('WP_DEBUG') && WP_DEBUG && \defined('WP_DEBUG_LOG') && WP_DEBUG_LOG && @is_file($error_log) && is_readable($error_log)) { + $error_log = basename($error_log); + echo 'View Log'; + } + ?> + + @@ -474,7 +509,7 @@ tooltip('maxfile'); ?> vcf()->dcvalue('maxfile')) { case '50000': $maxfile_default = '50K'; @@ -534,12 +569,33 @@ config_select_bool('chunkcachedir'); ?> + + tooltip('maxfile_livecheck'); ?> + + config_select_bool('maxfile_livecheck'); ?> + + - tooltip('flush_stalecache'); ?> + tooltip('flush_stalecache'); ?> config_select_bool('flush_stalecache'); ?> + + tooltip('stalecache_ignore'); ?> + + config_select_bool('stalecache_ignore'); ?> + + */ + ?> + + tooltip('emptycache_ignore'); ?> + + config_select_bool('emptycache_ignore'); ?> + + @@ -574,10 +630,10 @@ - - tooltip('autoupdate'); ?> + + tooltip('autoupdate_toggle'); ?> - config_select_bool('autoupdate'); ?> + config_select_bool('autoupdate_toggle'); ?> diff --git a/includes/admin/docket.css b/includes/admin/docket.css index 7ca5a96..574970a 100644 --- a/includes/admin/docket.css +++ b/includes/admin/docket.css @@ -135,6 +135,7 @@ body { #docket-cache .button { min-width: 150px; text-align: center; + margin-left: 0 !important; } #docket-cache .bt-fx { diff --git a/includes/admin/resource.php b/includes/admin/resource.php index 37d44e4..7f6bb6e 100644 --- a/includes/admin/resource.php +++ b/includes/admin/resource.php @@ -92,25 +92,28 @@

+

+ + tab_title(esc_html__('Resources', 'docket-cache')); ?> diff --git a/includes/cache.php b/includes/cache.php index 75b7862..b32362c 100644 --- a/includes/cache.php +++ b/includes/cache.php @@ -18,6 +18,7 @@ /** * Core class that implements an object cache. */ +#[AllowDynamicProperties] class WP_Object_Cache { /** @@ -90,6 +91,13 @@ class WP_Object_Cache */ private $multisite; + /** + * Holds the value of Network Id. + * + * @var bool + */ + private $network_id = 1; + /** * The cache path. * @@ -154,11 +162,39 @@ class WP_Object_Cache private $precache_hashkey = ''; /** - * Precache max entries. + * Precache max keys. + * + * @var int + */ + private $precache_maxkey = 20; + + /** + * Precache max groups. + * + * @var int + */ + private $precache_maxgroup = 20; + + /** + * Precache max cache file (url). * * @var int */ - private $precache_maxlist = 500; + private $precache_maxfile = 100; + + /** + * Maximum cache file. + * + * @var int + */ + private $maxfile = 50000; + + /** + * Check cache file limit in real-time. + * + * @var bool + */ + private $maxfile_livecheck = true; /** * The maximum time in seconds a script is allowed to run. @@ -175,25 +211,25 @@ class WP_Object_Cache private $wp_start_timestamp = 0; /** - * Stalecache status. + * Dev mode. * * @var bool */ - private $is_stalecache = false; + private $is_dev = false; /** - * List of stale cache to remove. + * Ignore stale cache. * - * @var array + * @var bool */ - private $stalecache_list = []; + private $ignore_stalecache = false; /** - * Dev mode. + * Ignore empty cache. * * @var bool */ - private $is_dev = false; + private $ignore_emptycache = false; /** * Sets up object properties. @@ -202,6 +238,7 @@ public function __construct() { $this->multisite = \function_exists('is_multisite') && is_multisite(); $this->blog_prefix = $this->switch_to_blog(get_current_blog_id()); + $this->network_id = (int) nwdcx_network_id(); $this->dc_init(); } @@ -213,7 +250,7 @@ public function __construct() * * @return bool whether the key exists in the cache for the given group */ - protected function _exists($key, $group) + protected function _exists($key, $group, $force = false) { // check key if (!$this->is_valid_key($key)) { @@ -229,15 +266,20 @@ protected function _exists($key, $group) return false; } - $is_exists = !empty($this->cache) && isset($this->cache[$group]) && (isset($this->cache[$group][$key]) || \array_key_exists($key, $this->cache[$group])); - if (!$is_exists && !$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key)) { + $is_exists = !$force && !empty($this->cache) && isset($this->cache[$group]) && (isset($this->cache[$group][$key]) || \array_key_exists($key, $this->cache[$group])); + + if (!$is_exists && !$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key) && !$this->is_stalecache_ignored($key, $group)) { $data = $this->dc_get($key, $group, false); if (false !== $data) { $is_exists = true; $this->cache[$group][$key] = $data; - if ($this->is_precache && !$this->is_bypass_precache($group, $key)) { - $this->precache[$group][$key] = 1; + if ($this->is_precache && !$this->fs()->suspend_cache_write() && !$this->is_bypass_precache($group, $key)) { + if (empty($this->precache[$group])) { + $this->precache[$group][$key] = 1; + } elseif (\count($this->precache[$group]) < $this->precache_maxkey && \count($this->precache) < $this->precache_maxgroup) { + $this->precache[$group][$key] = 1; + } } } } @@ -359,11 +401,6 @@ public function set($key, $data, $group = 'default', $expire = 0) $group = 'default'; } - // from invalidate cache - if ($this->is_stalecache) { - $this->dc_stalecache_filter($key, $group); - } - $cache_key = $this->dc_key($key, $group); if (\is_object($data)) { @@ -372,7 +409,12 @@ public function set($key, $data, $group = 'default', $expire = 0) $this->cache[$group][$cache_key] = $data; - if ((!$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key)) || $this->is_filtered_groups($group, $key)) { + // suspend new cache + if ($this->fs()->suspend_cache_write() && !is_file($this->get_file_path($cache_key, $group))) { + return true; + } + + if ((!$this->is_non_persistent_groups($group) && !$this->is_non_persistent_keys($key) && !$this->is_non_persistent_groupkey($group, $key) && !$this->is_stalecache_ignored($key, $group)) || $this->is_filtered_groups($group, $key)) { $expire = $this->maybe_expire($group, $expire, $key); $this->dc_save($cache_key, $this->cache[$group][$cache_key], $group, $expire, $key); } @@ -431,9 +473,8 @@ public function get($key, $group = 'default', $force = false, &$found = null) $cache_key = $this->dc_key($key, $group); - if ($this->_exists($cache_key, $group)) { + if ($this->_exists($cache_key, $group, $force)) { $found = true; - if (\is_object($this->cache[$group][$cache_key])) { return clone $this->cache[$group][$cache_key]; } @@ -680,7 +721,9 @@ public function stats() public function add_non_persistent_groups($groups) { $groups = (array) $groups; - $this->non_persistent_groups = array_unique(array_merge($this->non_persistent_groups, $groups)); + + $groups = array_fill_keys($groups, true); + $this->non_persistent_groups = array_merge($this->non_persistent_groups, $groups); } /** @@ -690,7 +733,20 @@ public function add_non_persistent_groups($groups) */ protected function is_non_persistent_groups($group) { - return !empty($this->non_persistent_groups) && \in_array($group, $this->non_persistent_groups); + return !empty($this->non_persistent_groups) && \array_key_exists($group, $this->non_persistent_groups); + } + + /** + * Sets the list of non persistent keys. + * + * @param array $keys list of keys that are to be ignored + */ + public function add_non_persistent_keys($keys) + { + $keys = (array) $keys; + + $keys = array_fill_keys($keys, true); + $this->non_persistent_keys = array_merge($this->non_persistent_keys, $keys); } /** @@ -700,7 +756,7 @@ protected function is_non_persistent_groups($group) */ protected function is_non_persistent_keys($key) { - return !empty($this->non_persistent_keys) && \in_array($key, $this->non_persistent_keys); + return !empty($this->non_persistent_keys) && \array_key_exists($key, $this->non_persistent_keys); } /** @@ -711,26 +767,50 @@ protected function is_non_persistent_keys($key) */ protected function is_non_persistent_groupkey($group, $key) { - return !empty($this->non_persistent_groupkey) && \in_array($group.':'.$key, $this->non_persistent_groupkey); + if (!empty($this->non_persistent_groupkey) && !empty($this->non_persistent_groupkey[$group])) { + $bypass_data = $this->non_persistent_groupkey[$group]; + + if (\is_array($bypass_data)) { + return false !== array_search($key, $bypass_data); + } + + if ($key === $bypass_data) { + return true; + } + } + + return false; } /** - * Check if key in non persistent index. + * Bypass preache. * * @param bool $group cache group * @param bool $key cache key */ protected function is_bypass_precache($group, $key) { - if (!empty($_POST) || ($this->fs()->is_docketcachegroup($group) || $this->fs()->is_transient($group) || $this->is_non_persistent_groups($group)) - // wc: woocommerce/includes/class-wc-cache-helper.php - || ('wc_cache_' === substr($key, 0, 9) || 'wc_session_id' === $group || @preg_match('@^wc_.*_cache_prefix@', $key)) - // stale cache *last_changed - || (false !== strpos($key, ':') && @preg_match('@(.*):([a-z0-9]{32}):([0-9\. ]+)$@', $key))) { + if ($this->fs()->is_docketcachegroup($group, $key) || $this->fs()->is_transient($group) || $this->is_non_persistent_groups($group) || $this->is_non_persistent_keys($key) || $this->has_stalecache($key, $group)) { return true; } - return !empty($this->bypass_precache) && \in_array($group.':'.$key, $this->bypass_precache); + if ('gbmedia-cpttables' === $group || 'doing_cron' === $key || preg_match('@^(\d+|[0-9a-f]{32})$@', $key)) { + return true; + } + + if (!empty($this->bypass_precache) && !empty($this->bypass_precache[$group])) { + $bypass_data = $this->bypass_precache[$group]; + + if (\is_array($bypass_data)) { + return false !== array_search($key, $bypass_data); + } + + if ($key === $bypass_data) { + return true; + } + } + + return false; } /** @@ -824,35 +904,72 @@ private function maybe_expire($group, $expire = 0, $key = '') if (\in_array($group, ['site-transient', 'transient'])) { if ('site-transient' === $group && \in_array($key, ['update_plugins', 'update_themes', 'update_core', '_woocommerce_helper_updates'])) { $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d - } elseif ('transient' === $group && 'health-check-site-status-result' === $key) { - $expire = 0; // to check with is_data_uptodate } else { - $expire = $maxttl < 604800 ? 604800 : $maxttl; // 7d + // $expire = $maxttl < 604800 ? 604800 : $maxttl; // 7d + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d } } elseif (\in_array($group, ['options', 'site-options'])) { $expire = $maxttl < 1209600 ? 1209600 : $maxttl; // 14d - } elseif (\in_array($group, ['terms', 'posts', 'post_meta', 'comments'])) { + } elseif (\in_array($group, ['terms', 'posts', 'post_meta', 'comments', 'comment_feed', 'sites', 'networks'])) { $expire = $maxttl < 1209600 ? 1209600 : $maxttl; // 14d + } - // wp stale cache - // prefix:md5hash:microtime - if (false !== strpos($key, ':') && @preg_match('@(.*):([a-z0-9]{32}):([0-9\. ]+)$@', $key)) { - $expire = $maxttl < 345600 ? $maxttl : 345600; // 4d - } + // wp stale cache + // prefix:md5hash:microtime + // wp_query|get_terms|get_comments|comment_feed|get_sites|get_network_ids|get_page_by_path|other? + elseif (false !== strpos($key, ':') && @preg_match('@^([a-zA-Z0-9\._-]+):([0-9a-f]{32}):([0-9\. ]+)$@', $key)) { + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d + } + + // wp stale cache + // cache timestamp + elseif ('last_changed' === $key) { + $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d } + // advcpost - // docketcache-post-timestamp + // docketcache-post-(found|media|timestamp) elseif (false !== strpos($group, 'docketcache-post-')) { - $expire = $maxttl < 345600 ? $maxttl : 345600; // 4d + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d + } + + // advcpost + // docketcache-post-media + elseif ('docketcache-post-media' === $group) { + $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d + } + + // advcpost + // cache timestamp + elseif ('docketcache-post' === $group && 'cache_incr' === $key) { + $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d + } + + // woocommerce stale cache + // cache prefix + elseif (false !== strpos($key, '_cache_prefix') && @preg_match('@^wc_(.*?)_cache_prefix$@', $key)) { + $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d } + // woocommerce stale cache // wc_cache_0.72953700 1651592702 elseif (false !== strpos($key, 'wc_cache_') && @preg_match('@^wc_cache_([0-9\. ]+)_@', $key)) { - $expire = $maxttl < 345600 ? $maxttl : 345600; // 4d + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d + } elseif (false !== strpos($group, 'wc_cache_') && @preg_match('@^wc_cache_([0-9\. ]+)_@', $group)) { + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d + } + + // common cache + elseif (preg_match('@[0-9a-f]{32}@', $key)) { + $expire = $maxttl < 86400 ? $maxttl : 86400; // 1d + } + + // else + else { + $expire = $maxttl; } } - // if 0 let's gc handle it by comparing file mtime. return $expire; } @@ -890,7 +1007,7 @@ private function get_file_path($key, $group) $index = $hash_group.'-'.$hash_key; - if ($this->cf()->is_dcfalse('CHUNKCACHEDIR')) { + if ($this->cf()->is_dcfalse('CHUNKCACHEDIR', true)) { return $this->cache_path.$index.'.php'; } @@ -904,7 +1021,7 @@ private function get_file_path($key, $group) */ private function skip_stats($group, $key = '') { - if ($this->is_non_persistent_groups($group)) { + if ($this->is_non_persistent_groups($group) || (!empty($keys) && $this->is_non_persistent_keys($key))) { return true; } @@ -914,7 +1031,7 @@ private function skip_stats($group, $key = '') /** * is_data_uptodate. */ - private function is_data_uptodate($key, $group, $data, $data_serialized = null) + private function is_data_uptodate($key, $group, $data) { $file = $this->get_file_path($key, $group); $data_p = $this->fs()->cache_get($file); @@ -923,24 +1040,47 @@ private function is_data_uptodate($key, $group, $data, $data_serialized = null) } $data_p = $data_p['data']; - $data_p_type = \gettype($data_p); - $data_type = \gettype($data); - $doserialize = 'array' === $data_type || 'object' === $data_type; - if ($data_p_type !== $data_type) { - return false; + if (\function_exists('nwdcx_arraysimilar') && nwdcx_arraysimilar($data_p, $data)) { + nwdcx_debuglog(__FUNCTION__.': '.$this->get_item_hash($file).' No data changes.'); + + return true; } - if (!$doserialize && ((false !== strpos($data_type, 'string') && 0 === strcmp($data_p, $data)) || $data_p === $data)) { + return false; + } + + /** + * has_stalecache. + */ + private function has_stalecache($key, $group = '') + { + if ('wc_' === substr($key, 0, 3) && '_cache_prefix' === substr($key, -13)) { return true; } - // @note 2122: use md5, serialize can be large. - if ($doserialize) { - $data_ps = !empty($data_serialized) ? $data_serialized : @serialize($data_p); - if (@md5($data_serialized) === @md5(@serialize($data))) { - return true; - } + if ('wc_cache_' === substr($key, 0, 9) || 'wc_cache_' === substr($group, 0, 9)) { + return true; + } + + if (false !== strpos($key, ':') && @preg_match('@^([a-zA-Z0-9\._-]+):([0-9a-f]{32}):([0-9\. ]+)$@', $key)) { + return true; + } + + if (false !== strpos($group, 'docketcache-post-') && preg_match('@^docketcache-post-\d+$@', $group)) { + return true; + } + + return false; + } + + /** + * is_stalecache_ignored. + */ + private function is_stalecache_ignored($key, $group = '') + { + if ($this->ignore_stalecache) { + return $this->has_stalecache($key, $group = ''); } return false; @@ -1090,15 +1230,21 @@ public function dc_remove_group($group) $group = implode(',', $group); } + $this->fs()->suspend_cache_write(true); + $max_execution_time = $this->fs()->get_max_execution_time(180); + $slowdown = 0; foreach ($this->fs()->scanfiles($this->cache_path, null, $pattern) as $object) { if ($object->isFile()) { $fx = $object->getPathName(); $fn = $object->getFileName(); $this->fs()->unlink($fx, true); - $this->dc_log('flush', $this->get_item_hash($fx), $group.':*'); ++$total; - unset($this->cache[$group]); + + array_map(function ($grp) use ($fx) { + unset($this->cache[$grp]); + $this->dc_log('flush', $this->get_item_hash($fx), $grp.':*'); + }, explode(',', $group)); } if ($slowdown > 10) { @@ -1108,11 +1254,13 @@ public function dc_remove_group($group) ++$slowdown; - if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) { + if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) { break; } } + $this->fs()->suspend_cache_write(false); + return $total; } @@ -1126,6 +1274,9 @@ public function dc_remove_group_match($group) return $total; } + $this->fs()->suspend_cache_write(true); + $max_execution_time = $this->fs()->get_max_execution_time(180); + $slowdown = 0; $pattern = '@^([a-z0-9]{12})\-([a-z0-9]{12})\.php$@'; foreach ($this->fs()->scanfiles($this->cache_path, null, $pattern) as $object) { @@ -1165,50 +1316,14 @@ public function dc_remove_group_match($group) ++$slowdown; - if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) { + if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) { break; } } - return $total; - } + $this->fs()->suspend_cache_write(false); - /** - * dc_stalecache_filter. - */ - private function dc_stalecache_filter($key, $group) - { - if ('wc_' === substr($key, 0, 3) && '_cache_prefix' === substr($key, -13)) { - // get previous usec - $usec = $this->get('wc_'.$group.'_cache_prefix', $group); - if ($usec) { - $val = 'wc_cache:'.$group.':'.$usec; - $this->stalecache_list[md5($val)] = $val; - } - } elseif ('last_changed' === $key) { - // get previous usec - $usec = $this->get('last_changed', $group); - if ($usec) { - $val = 'last_changed:'.$group.':'.$usec; - $this->stalecache_list[md5($val)] = $val; - } - } - // can't capture by last_changed. - // we compare key prefix and timestamp. - elseif (false !== strpos($key, ':') && @preg_match('@(.*):([a-z0-9]{32}):([0-9\. ]+)$@', $key, $mm)) { - $val = 'after:'.$group.':'.$mm[3].':'.$mm[1]; - $this->stalecache_list[md5($val)] = $val; - } - } - - /** - * advcpost_stalecache_se. - */ - public function add_stalecache($lists) - { - if ($this->is_stalecache && !empty($lists) && \is_array($lists)) { - $this->stalecache_list = array_merge($this->stalecache_list, $lists); - } + return $total; } /** @@ -1238,9 +1353,9 @@ private function dc_get($key, $group, $is_raw = false) } // incase gc not run - if (!$is_timeout && !empty($this->cache_maxttl) && !empty($data['timestamp']) && $this->fs()->valid_timestamp($data['timestamp'])) { + if (!$is_timeout && !empty($data['timestamp']) && $this->fs()->valid_timestamp($data['timestamp'])) { $maxttl = time() - $this->cache_maxttl; - if ($data['timestamp'] < $maxttl) { + if ($maxttl > $data['timestamp']) { $this->dc_log('exp', $logkey, $group.':'.$key); $this->fs()->unlink($file, true); // true = delete it instead of truncate } @@ -1280,7 +1395,18 @@ private function dc_code($file, $arr) $logkey = $this->get_item_hash($file); $logpref = __FUNCTION__.'():'; - $data = $this->fs()->export_var($arr, $error); + // use (object) instead of VarExporter. + if (\PHP_VERSION_ID >= 70433 && \in_array($arr['type'], ['object', 'array'])) { + $arr_data = var_export($arr, true); + if (!empty($arr_data) && false != strpos($arr_data, '(object) array(') && false === strpos($arr_data, '::__set_state')) { + $data = $arr_data; + } + } + + if (!isset($data)) { + $data = $this->fs()->export_var($arr, $error); + } + if (false === $data) { $this->dc_log('err', $logkey, $logpref.' Failed to export var -> '.$error); @@ -1319,13 +1445,11 @@ private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $ke $logpref = __FUNCTION__.'():'; // skip save to disk, return true; - if ('' === $data && $this->fs()->is_transient($group)) { - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $group.':'.$cache_key.' '.$logpref.' Data empty'); - } + /*if ('' === $data && $this->fs()->is_transient($group)) { + nwdcx_debuglog(__FUNCTION__.': '.$logkey.': Process aborted. No data availale.'); return true; - } + }*/ if (!$this->fs()->mkdir_p($this->cache_path)) { return false; @@ -1335,8 +1459,16 @@ private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $ke $file = $this->get_file_path($cache_key, $group); + // skip save to disk, return true; + if (('' === $data || (\is_array($data) && empty($data))) && ($this->fs()->is_transient($group) || $this->ignore_emptycache)) { + nwdcx_debuglog(__FUNCTION__.': '.$logkey.': Process aborted. No data availale.'); + $this->fs()->unlink($file, false); + + return true; + } + // chunk dir - if ($this->cf()->is_dctrue('CHUNKCACHEDIR') && !$this->fs()->mkdir_p(\dirname($file))) { + if ($this->cf()->is_dctrue('CHUNKCACHEDIR', true) && !$this->fs()->mkdir_p(\dirname($file))) { return false; } @@ -1348,6 +1480,7 @@ private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $ke $data = ''; } + // unserialize content if (!empty($data)) { if ('string' === $type) { $data = nwdcx_unserialize($data); @@ -1362,43 +1495,37 @@ private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $ke } // abort if object too large - $data_serialized = serialize($data); - $len = \strlen(serialize($data_serialized)); + $len = \strlen(serialize($data)); if ($len >= $this->cache_maxsize) { $this->dc_log('err', $logkey, $group.':'.$cache_key.' '.$logpref.' Object too large -> '.$len.'/'.$this->cache_maxsize); + nwdcx_debuglog(__FUNCTION__.': '.$logkey.': Process aborted. Object too large ('.$len.'/'.$this->cache_maxsize.')'); + return false; } // since timeout set to timestamp. - if (0 === $expire && !empty($key) && @is_file($file) && $this->is_data_uptodate($key, $group, $data, $data_serialized)) { - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $group.':'.$cache_key.' '.$logpref.' No changes'); - } - + /*clearstatcache(true, $file); + if (0 === $expire && !empty($key) && @is_file($file) && $this->is_data_uptodate($key, $group, $data)) { return false; - } + }*/ $meta = []; $meta['timestamp'] = time(); if ($this->multisite) { - // try to avoid error-prone - // in rare condition, get_current_network_id dependencies not load properly. - try { - $meta['network_id'] = get_current_network_id(); - } catch (\Throwable $e) { - $meta['network_id'] = 0; - } + $meta['network_id'] = $this->network_id; } $final_type = \gettype($data); if ('string' === $final_type && nwdcx_serialized($data)) { $final_type = 'string_serialize'; - } elseif ('array' === $final_type) { + } elseif ('array' === $final_type && (!\defined('DOCKET_CACHE_USE_CLASSMAP') || !DOCKET_CACHE_USE_CLASSMAP)) { // may lead to __PHP_Incomplete_Class // headers => Requests_Utility_CaseInsensitiveDictionary Object - if (!empty($data['headers']) && \is_object($data['headers']) && false !== strpos(var_export($data['headers'], 1), 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) { + // headers => Requests_Utility_CaseInsensitiveDictionary Object + // if (!empty($data['headers']) && \is_object($data['headers']) && false !== strpos(var_export($data['headers'], 1), 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) { + if (false !== strpos(var_export($data, 1), 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) { $data = @serialize($data); if (nwdcx_serialized($data)) { $final_type = 'array_serialize'; @@ -1415,11 +1542,21 @@ private function dc_save($cache_key, $data, $group = 'default', $expire = 0, $ke // and maxttl constants. $meta['timeout'] = $timeout; + // final data $meta['data'] = $data; + // only count new file. + clearstatcache(true, $file); + $has_cache_file = is_file($file); if (true === $this->dc_code($file, $meta)) { - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $group.':'.$cache_key.' '.$logpref.' Storing to disk'); + nwdcx_debuglog(__FUNCTION__.': '.$this->get_item_hash($file).': Storing to disk.'); + + if (!$has_cache_file && $this->maxfile_livecheck) { + $count_file = (int) $this->get('count_file', 'docketcache-gc'); + if ($this->maxfile > $count_file) { + ++$count_file; + $this->set('count_file', $count_file, 'docketcache-gc', 86400); // 1d + } } return true; @@ -1484,7 +1621,7 @@ private function dc_precache_load($hash) foreach ($keys as $cache_group => $arr) { foreach ($arr as $cache_key) { - if ($cnt_max >= $this->precache_maxlist) { + if ($cnt_max >= $this->precache_maxkey) { break 2; } @@ -1520,30 +1657,37 @@ private function dc_precache_load($hash) */ private function dc_precache_set($hash) { + $group = 'docketcache-precache'; + $file = $this->get_file_path($hash, $group); + if (empty($this->precache) || !\is_array($this->precache)) { + $this->fs()->unlink($file, true); + return; } - $group = 'docketcache-precache'; + $file_hash = $this->get_item_hash($file); $data = []; $slowdown = 0; $cnt_max = 0; - $logkey = $this->item_hash('docketcache-precache').'-'.$this->item_hash(__FUNCTION__); - $logpref = __FUNCTION__.'():'; + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process started.'); - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $logpref.' Precache Set: Start'); + // docketcache-precache-gc + $count_file = (int) $this->get('count_file', $group.'-gc'); + if ($count_file >= $this->precache_maxfile) { + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum file limit ('.$count_file.'/'.$this->precache_maxfile.')'); + + return; } foreach ($this->precache as $cache_group => $cache_keys) { - if ($cnt_max >= $this->precache_maxlist) { + if ($cnt_max >= $this->precache_maxkey) { break; } if ($cache_group !== $group) { - $cache_keys = array_keys($cache_keys); - $data[$cache_group] = $cache_keys; + $data[$cache_group] = array_keys($cache_keys); } ++$cnt_max; @@ -1556,36 +1700,51 @@ private function dc_precache_set($hash) ++$slowdown; if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) { - // bypass, maybe data too big - $data = []; - $this->delete($hash); + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum execution time.'); break; } } - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $logpref.' Precache Set: End -> '.\count($data)); - } - if (!empty($data)) { - if (!empty($this->precache_loaded) && md5(serialize($this->precache_loaded[$hash])) === md5(serialize($data))) { - if ($this->is_dev) { - $this->dc_log('debug', $logkey, $logpref.' '.$hash.' No changes'); - } + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Total items = '.\count($data, 1)); + + if (!empty($this->precache_loaded) && \function_exists('nwdcx_arraysimilar') && nwdcx_arraysimilar($this->precache_loaded[$hash], $data)) { + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. No data changes.'); return; } - $this->set($hash, $data, $group, 86400); // 1d + // docketcache-precache-gc + if ($this->precache_maxfile > $count_file) { + clearstatcache(true, $file); + + // only count new file. + $has_precache_file = is_file($file); + + if ($this->set($hash, $data, $group, 86400)) { // 1d + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. Storing cache to disk.'); + + if (!$has_precache_file) { + ++$count_file; + $this->set('count_file', $count_file, $group.'-gc', 86400); // 1d + } + + return; + } + } + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process aborted. Reached maximum file limit ('.$count_file.'/'.$this->precache_maxfile.')'); + + return; } + nwdcx_debuglog(__FUNCTION__.': '.$file_hash.': Process ended. No data available.'); unset($data, $hash); } /** * dc_precache. */ - private function dc_precache() + private function dc_precache_init() { if (!empty($_POST) || empty($_SERVER['REQUEST_URI']) || $this->cf()->is_dctrue('WPCLI')) { return; @@ -1640,7 +1799,8 @@ private function dc_precache() return; } - $this->precache_hashkey = $this->item_hash($req_host.$req_uri); + // $this->precache_hashkey = $this->item_hash($req_host.$req_uri); + $this->precache_hashkey = md5($req_host.$req_uri); $this->dc_precache_load($this->precache_hashkey); } @@ -1653,18 +1813,14 @@ private function dc_precache() */ public function dc_close() { - $this->fs()->close_buffer(); + // $this->fs()->close_buffer(); static $is_done = false; if (!$is_done) { - if ($this->is_precache && !empty($this->precache_hashkey) && $this->fs()->close_buffer()) { + if ($this->is_precache && !empty($this->precache_hashkey) && !$this->fs()->suspend_cache_write() /* && $this->fs()->close_buffer() */) { $this->dc_precache_set($this->precache_hashkey); } - if ($this->is_stalecache && !empty($this->stalecache_list)) { - $this->add('items', $this->stalecache_list, 'docketcache-stalecache', 3600); - } - $is_done = true; } } @@ -1695,11 +1851,11 @@ private function dc_init() } if ($this->cf()->is_dcarray('IGNORED_GROUPS', $dcvalue)) { - $this->non_persistent_groups = $dcvalue; + $this->add_non_persistent_groups($dcvalue); } if ($this->cf()->is_dcarray('IGNORED_KEYS', $dcvalue)) { - $this->non_persistent_keys = $dcvalue; + $this->add_non_persistent_keys($dcvalue); } if ($this->cf()->is_dcarray('FILTERED_GROUPS', $dcvalue)) { @@ -1775,7 +1931,6 @@ function ($option) { add_action( 'shutdown', function () { - $this->fs()->close_buffer(); $this->delete('alloptions', 'options'); }, \PHP_INT_MAX - 1 @@ -1792,21 +1947,16 @@ function () { add_action( $prefix.'_plugin', function ($plugin, $network) { - if ($this->multisite) { - add_action( - 'shutdown', - function () { - $this->fs()->close_buffer(); - $this->delete(get_current_network_id().':active_sitewide_plugins', 'site-options'); - }, - \PHP_INT_MAX - 1 - ); - } add_action( 'shutdown', function () { - $this->fs()->close_buffer(); + if ($this->multisite) { + $this->delete($this->network_id.':active_sitewide_plugins', 'site-options'); + $this->delete($this->network_id.':auto_update_plugins', 'site-options'); + } + $this->delete('uninstall_plugins', 'options'); + $this->delete('auto_update_plugins', 'options'); }, \PHP_INT_MAX - 1 ); @@ -1916,29 +2066,52 @@ function () { function () { if ($this->add_signature && !$this->is_user_logged_in()) { echo apply_filters('docketcache/filter/signature/htmlfooter', "\n\n"); - $this->fs()->close_buffer(); + // $this->fs()->close_buffer(); } }, \PHP_INT_MAX ); } - // stalecache - $this->is_stalecache = $this->cf()->is_dctrue('FLUSH_STALECACHE'); + // bypass stalecache + $this->ignore_stalecache = $this->cf()->is_dctrue('STALECACHE_IGNORE', true); + + // bypass emptyache + $this->ignore_emptycache = $this->cf()->is_dctrue('EMPTYCACHE_IGNORE', true); + + // maxfile check + // true = count file at dc_save, false = will handle by GC. + $this->maxfile_livecheck = $this->cf()->is_dctrue('MAXFILE_LIVECHECK', true); + + // maxfile + $this->maxfile = (int) $this->fs()->sanitize_maxfile($this->cf()->dcvalue('MAXFILE', true)); + $count_file = (int) $this->get('count_file', 'docketcache-gc'); + if ($count_file >= $this->maxfile) { + $this->fs()->suspend_cache_write(true); + } // load precache - $this->is_precache = $this->cf()->is_dctrue('PRECACHE'); + $this->is_precache = $this->cf()->is_dctrue('PRECACHE', true); if ($this->is_precache) { - $this->precache_maxlist = (int) $this->cf()->dcvalue('PRECACHE_MAXLIST'); - $this->dc_precache(); - } + if ($this->cf()->is_dcint('PRECACHE_MAXGROUP', $dcvalue)) { + if (!empty($dcvalue)) { + $this->precache_maxgroup = $dcvalue; + } + } - // maxfile - $maxfile = (int) $this->fs()->sanitize_maxfile($this->cf()->dcvalue('MAXFILE')); - $numfile = (int) $this->get('numfile', 'docketcache-gc'); - $numfile = $numfile > 0 ? $numfile : 0; - if ($numfile > $maxfile) { - wp_suspend_cache_addition(true); + if ($this->cf()->is_dcint('PRECACHE_MAXKEY', $dcvalue)) { + if (!empty($dcvalue)) { + $this->precache_maxkey = $dcvalue; + } + } + + if ($this->cf()->is_dcint('PRECACHE_MAXFILE', $dcvalue)) { + if (!empty($dcvalue)) { + $this->precache_maxfile = $this->fs()->sanitize_precache_maxfile($dcvalue); + } + } + + $this->dc_precache_init(); } } } @@ -2134,6 +2307,15 @@ function wp_cache_add_non_persistent_groups($groups) $wp_object_cache->add_non_persistent_groups($groups); } +/** + * @see WP_Object_Cache::add_non_persistent_keys() + */ +function wp_cache_add_non_persistent_keys($keys) +{ + global $wp_object_cache; + $wp_object_cache->add_non_persistent_keys($keys); +} + /** * @see WP_Object_Cache::switch_to_blog() */ @@ -2182,13 +2364,3 @@ function wp_cache_flush_group_match($group = 'default') return $wp_object_cache->dc_remove_group_match($group); } - -/** - * @see WP_Object_Cache::add_stalecache() - */ -function wp_cache_add_stalecache($lists) -{ - global $wp_object_cache; - - return $wp_object_cache->add_stalecache($lists); -} diff --git a/includes/compat.php b/includes/compat.php index d2460b0..17879e2 100644 --- a/includes/compat.php +++ b/includes/compat.php @@ -31,9 +31,42 @@ function nwdcx_arraymap($func, $arr) } } +if (!\function_exists('nwdcx_arraysimilar')) { + function nwdcx_arraysimilar($actual, $expected) + { + if (!\is_array($expected) || !\is_array($actual)) { + return $actual === $expected; + } + foreach ($expected as $key => $value) { + if (!isset($actual[$key]) || !isset($expected[$key])) { + return false; + } + + if (!nwdcx_arraysimilar($actual[$key], $expected[$key])) { + return false; + } + } + foreach ($actual as $key => $value) { + if (!isset($actual[$key]) || !isset($expected[$key])) { + return false; + } + if (!nwdcx_arraysimilar($actual[$key], $expected[$key])) { + return false; + } + } + + return true; + } +} + if (!\function_exists('nwdcx_serialized')) { function nwdcx_serialized($data) { + // short-circuit the checking. + if (!\is_string($data) || false === strpbrk($data, '{:;}')) { + return false; + } + if (!\function_exists('is_serialized')) { // 16072021: rare opcache issue with some hosting ABSPATH not defined. if (\defined('ABSPATH') && \defined('WPINC')) { @@ -56,23 +89,27 @@ function nwdcx_unserialize($data) return $data; } - $ok = true; - - // if the string has object format, check it if has stdClass, - // other than that set it as false and return the original data + // If the string has an object format, check if it has a stdClass, otherwise return the original data. + // The logic here is, if we "unserialize" it, we can't use the cache since the VarExporter can't detect + // the Class instance in objects which may lead to "class not found". if (false !== strpos($data, 'O:') && @preg_match_all('@O:\d+:"([^"]+)"@', $data, $mm)) { if (!empty($mm) && !empty($mm[1])) { foreach ($mm[1] as $v) { if ('stdClass' !== $v) { - $ok = false; - break; + return $data; } } unset($mm); } } - return !$ok ? $data : @unserialize(trim($data)); + // make query-monitor happy. + $nwdcx_suppresserrors = nwdcx_suppresserrors(true); + $data = @unserialize(trim($data)); + + nwdcx_suppresserrors($nwdcx_suppresserrors); + + return $data; } } @@ -154,7 +191,9 @@ function nwdcx_cleanuptransient() $collect = []; - $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` LIKE "_transient_%" OR `option_name` LIKE "_site_transient_%" ORDER BY `option_id` ASC LIMIT 1000', ARRAY_A); + // $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` LIKE "_transient_%" OR `option_name` LIKE "_site_transient_%" ORDER BY `option_id` ASC LIMIT 1000', ARRAY_A); + $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` RLIKE "^(_site)?(_transient)(_timeout)?_.*?" ORDER BY `option_id` ASC LIMIT 5000', ARRAY_A); + if (!empty($results) && \is_array($results)) { while ($row = @array_shift($results)) { $key = @preg_replace('@^(_site)?(_transient)(_timeout)?_@', '', $row['option_name']); @@ -180,7 +219,8 @@ function nwdcx_cleanuptransient() $collect = []; if (is_multisite() && isset($wpdb->sitemeta)) { - $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` LIKE "_site_transient_%" ORDER BY `meta_id` ASC LIMIT 1000', ARRAY_A); + // $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` LIKE "_site_transient_%" ORDER BY `meta_id` ASC LIMIT 1000', ARRAY_A); + $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` RLIKE "^(_site_transient)(_timeout)?_.*?" ORDER BY `meta_id` ASC LIMIT 5000', ARRAY_A); if (!empty($results) && \is_array($results)) { while ($row = @array_shift($results)) { $key = @preg_replace('@^(_site)?(_transient)(_timeout)?_@', '', $row['meta_key']); @@ -233,6 +273,31 @@ function nwdcx_throwable($name, $error) } } +if (!\function_exists('nwdcx_debuglog')) { + function nwdcx_debuglog($text) + { + if (\defined('DOCKET_CACHE_DEV') && DOCKET_CACHE_DEV) { + $logfile = WP_CONTENT_DIR.'/dcdev-debug.log'; + error_log('['.date('Y-m-d H:i:s').'] '.$text."\n", 3, $logfile); + } + } +} + +if (!\function_exists('nwdcx_cliverbose')) { + function nwdcx_cliverbose($text) + { + static $is_verbose = false; + + if (!$is_verbose) { + $is_verbose = 'cli' === \PHP_SAPI && !empty($_SERVER['argv']) && \in_array('--verbose', $_SERVER['argv']) && !\in_array('--quiet', $_SERVER['argv']); + } + + if ($is_verbose) { + fwrite(\STDOUT, $text); + } + } +} + if (!\function_exists('nwdcx_microtimetofloat')) { function nwdcx_microtimetofloat($second) { diff --git a/includes/object-cache.php b/includes/object-cache.php index 48a905f..96efc15 100644 --- a/includes/object-cache.php +++ b/includes/object-cache.php @@ -3,7 +3,7 @@ * @wordpress-plugin * Plugin Name: Docket Cache Drop-in * Plugin URI: https://wordpress.org/plugins/docket-cache/ - * Version: 22.07.02 + * Version: 22.07.03 * Description: A persistent object cache stored as a plain PHP code, accelerates caching with OPcache backend. * Author: Nawawi Jamili * Author URI: https://docketcache.com @@ -31,7 +31,7 @@ } /* - * Bypass if we doing action. + * Bypass if we doing action. It happen on redirection. */ if (!empty($_GET['_wpnonce']) && !empty($_GET['action']) && !empty($_GET['page']) && 'docket-cache' === $_GET['page'] && false === strpos($_GET['action'], 'cronbot') && false === strpos($_GET['action'], 'wpoptaload')) { return; @@ -39,6 +39,7 @@ /* * Bypass if match cache key in $_REQUEST. + * Just for development, it may cause uncertain results. */ if (\defined('DOCKET_CACHE_IGNORE_REQUEST') && \is_array(DOCKET_CACHE_IGNORE_REQUEST) && !empty($_REQUEST)) { if (array_intersect(DOCKET_CACHE_IGNORE_REQUEST, array_keys($_REQUEST))) { diff --git a/includes/src/Becache.php b/includes/src/Becache.php index 8408b7f..7396fa2 100644 --- a/includes/src/Becache.php +++ b/includes/src/Becache.php @@ -111,7 +111,7 @@ private function get_file_path($key, $group) $index = $hash_group.'-'.$hash_key; - if ($this->cf()->is_dcfalse('CHUNKCACHEDIR')) { + if ($this->cf()->is_dcfalse('CHUNKCACHEDIR', true)) { return $this->cache_path.$index.'.php'; } @@ -122,7 +122,18 @@ private function get_file_path($key, $group) private function dump_code($file, $arr) { - $data = $this->fs()->export_var($arr, $error); + // use (object) instead of VarExporter. + if (\PHP_VERSION_ID >= 70433 && \in_array($arr['type'], ['object', 'array'])) { + $arr_data = var_export($arr, true); + if (!empty($arr_data) && false != strpos($arr_data, '(object) array(') && false === strpos($arr_data, '::__set_state')) { + $data = $arr_data; + } + } + + if (!isset($data)) { + $data = $this->fs()->export_var($arr, $error); + } + if (false === $data) { return false; } @@ -143,55 +154,29 @@ private function dump_code($file, $arr) return $stat; } - private function maybe_expire($group, $expire = 0, $key = '') - { - if (empty($expire)) { - $expire = 0; - } - - $expire = $this->fs()->sanitize_timestamp($expire); - $maxttl = $this->cache_maxttl; - - if (0 === $expire && $maxttl < 2419200) { - if ($this->fs()->is_transient($group)) { - if ('site-transient' === $group && \in_array($key, ['update_plugins', 'update_themes', 'update_core', '_woocommerce_helper_updates'])) { - $expire = $maxttl < 2419200 ? 2419200 : $maxttl; // 28d - } elseif ('transient' === $group && 'health-check-site-status-result' === $key) { - $expire = 0; // to check with is_data_uptodate - } else { - $expire = $maxttl < 604800 ? 604800 : $maxttl; // 7d - } - } elseif (\in_array($group, ['terms', 'posts', 'post_meta', 'options', 'site-options', 'comments'])) { - $expire = $maxttl < 1209600 ? 1209600 : $maxttl; // 14d - } - // woocommerce stale cache - // wc_cache_0.72953700 1651592702 - elseif ('wc_cache_' === substr($key, 0, 9) && preg_match('@^wc_cache_([0-9\. ]+)_@', $key)) { - $expire = 86400; // 1d - } - } - - return $expire; - } - private function store_cache($key, $data, $group, $expire = 0) { if (!$this->fs()->mkdir_p($this->cache_path)) { return false; } - $expire = $this->maybe_expire($group, $expire, $key); - $cache_key = $this->cache_key($key, $group); $file = $this->get_file_path($cache_key, $group); // chunk dir - if ($this->cf()->is_dctrue('CHUNKCACHEDIR') && !$this->fs()->mkdir_p(\dirname($file))) { + if ($this->cf()->is_dctrue('CHUNKCACHEDIR', true) && !$this->fs()->mkdir_p(\dirname($file))) { return false; } - $timeout = ($expire > 0 ? time() + $expire : 0); + if ($this->fs()->is_transient($group)) { + // transient timeout already as timestamp in DB. + $timeout = $expire > 0 ? $expire : time() + 3600; + } elseif ('options' === $group) { + // initial set to 1 hour. + $timeout = time() + 3600; + } + $timeout = $timeout > $this->cache_maxttl ? time() + $this->cache_maxttl : $timeout; $type = \gettype($data); if ('NULL' === $type && null === $data) { $data = ''; @@ -227,13 +212,13 @@ private function store_cache($key, $data, $group, $expire = 0) } $final_type = \gettype($data); - if ('array' === $final_type) { - // http remote request - // headers => Requests_Utility_CaseInsensitiveDictionary Object - if (!empty($data['headers']) && \is_object($data['headers']) && false !== strpos(var_export($data['headers'], 1), 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) { + if ('string' === $final_type && nwdcx_serialized($data)) { + $final_type = 'string_serialize'; + } elseif ('array' === $final_type && (!\defined('DOCKET_CACHE_USE_CLASSMAP') || !DOCKET_CACHE_USE_CLASSMAP)) { + if (false !== strpos(var_export($data, 1), 'Requests_Utility_CaseInsensitiveDictionary::__set_state')) { $data = @serialize($data); if (nwdcx_serialized($data)) { - $final_type = 'string'; + $final_type = 'array_serialize'; } } } @@ -261,7 +246,8 @@ public function export_transient() $suppress = $wpdb->suppress_errors(true); $collect = []; - $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` LIKE "_transient_%" OR `option_name` LIKE "_site_transient_%" ORDER BY `option_id` ASC LIMIT '.$this->qlimit, ARRAY_A); + // $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` LIKE "_transient_%" OR `option_name` LIKE "_site_transient_%" ORDER BY `option_id` ASC LIMIT '.$this->qlimit, ARRAY_A); + $results = $wpdb->get_results('SELECT `option_id`,`option_name`,`option_value` FROM `'.$wpdb->options.'` WHERE `option_name` RLIKE "^(_site)?(_transient)(_timeout)?_.*?" ORDER BY `option_id` ASC LIMIT '.$this->qlimit, ARRAY_A); if (!empty($results) && \is_array($results)) { while ($row = @array_shift($results)) { if ($this->max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $this->max_execution_time) { @@ -286,6 +272,10 @@ public function export_transient() if (false !== strpos($row['option_name'], '_transient_timeout_')) { $collect[$key]['timeout'] = (int) $row['option_value']; + + if (time() > $collect[$key]['timeout']) { + unset($collect[$key]); + } } } @@ -304,7 +294,8 @@ public function export_transient() $collect = []; if ($this->multisite && isset($wpdb->sitemeta)) { - $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` LIKE "_site_transient_%" ORDER BY `meta_id` ASC LIMIT '.$this->qlimit, ARRAY_A); + // $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` LIKE "_site_transient_%" ORDER BY `meta_id` ASC LIMIT '.$this->qlimit, ARRAY_A); + $results = $wpdb->get_results('SELECT `meta_id`,`meta_key`,`meta_value` FROM `'.$wpdb->sitemeta.'` WHERE `meta_key` RLIKE "^(_site_transient)(_timeout)?_.*?" ORDER BY `meta_id` ASC LIMIT '.$this->qlimit, ARRAY_A); if (!empty($results) && \is_array($results)) { while ($row = @array_shift($results)) { if ($this->max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $this->max_execution_time) { @@ -317,15 +308,19 @@ public function export_transient() continue; } - $key = @preg_replace('@^(_site)?(_transient)(_timeout)?_@', '', $row['meta_key']); + $key = @preg_replace('@^(_site_transient)(_timeout)?_@', '', $row['meta_key']); if (!isset($collect[$key])) { - $collect[$key] = ['value' => '', 'group' => 'site-transient', 'expire' => 0]; + $collect[$key] = ['value' => '', 'group' => 'site-transient', 'timeout' => 0]; } $collect[$key]['value'] = $row['meta_value']; if (false !== strpos($row['meta_key'], '_site_transient_timeout_')) { $collect[$key]['timeout'] = (int) $row['meta_value']; + + if (time() > $collect[$key]['timeout']) { + unset($collect[$key]); + } } } @@ -361,7 +356,7 @@ public function export_alloptions() if (!empty($alloptions_db) && \is_array($alloptions_db)) { $wp_options = $this->fs()->keys_alloptions(); - $is_filter = $this->cf()->is_dctrue('WPOPTALOAD'); + $is_filter = $this->cf()->is_dctrue('WPOPTALOAD', true); foreach ($alloptions_db as $num => $options) { if ($this->max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $this->max_execution_time) { $alloptions = []; diff --git a/includes/src/Canopt.php b/includes/src/Canopt.php index 89bbad5..0d6cca3 100644 --- a/includes/src/Canopt.php +++ b/includes/src/Canopt.php @@ -93,7 +93,7 @@ public function keys($key = false) 'postmissedschedule' => esc_html__('Post Missed Schedule Tweaks', 'docket-cache'), 'wootweaks' => esc_html__('Misc WooCommerce Tweaks', 'docket-cache'), 'wooadminoff' => esc_html__('Deactivate WooCommerce Admin', 'docket-cache'), - 'woowidgetoff' => esc_html__('Deactivate WooCommerce Widget', 'docket-cache'), + 'woowidgetoff' => esc_html__('Deactivate WooCommerce Classic Widget', 'docket-cache'), 'woowpdashboardoff' => esc_html__('Deactivate WooCommerce WP Dashboard', 'docket-cache'), 'wooextensionpageoff' => esc_html__('Deactivate WooCommerce Extensions Page', 'docket-cache'), 'woocartfragsoff' => esc_html__('Deactivate WooCommerce Cart Fragments', 'docket-cache'), @@ -106,7 +106,8 @@ public function keys($key = false) 'stats' => esc_html__('Object Cache Data Stats', 'docket-cache'), 'gcaction' => esc_html__('Garbage Collector Action Button', 'docket-cache'), 'flushaction' => esc_html__('Additional Flush Cache Action Button', 'docket-cache'), - 'autoupdate' => esc_html__('Docket Cache Auto Update', 'docket-cache'), + /* 'autoupdate' => esc_html__('Docket Cache Auto Update', 'docket-cache'), */ + 'autoupdate_toggle' => esc_html__('Docket Cache Auto Update', 'docket-cache'), 'checkversion' => esc_html__('Critical Version Checking', 'docket-cache'), 'optwpquery' => esc_html__('Optimize WP Query', 'docket-cache'), 'pingback' => esc_html__('Deactivate XML-RPC / Pingbacks', 'docket-cache'), @@ -125,8 +126,11 @@ public function keys($key = false) 'opcshutdown' => esc_html__('Flush OPcache During Deactivation', 'docket-cache'), 'maxsize_disk' => esc_html__('Cache Disk Limit', 'docket-cache'), 'maxfile' => esc_html__('Cache Files Limit', 'docket-cache'), + 'maxfile_livecheck' => esc_html__('Real-time File Limit Checking', 'docket-cache'), 'chunkcachedir' => esc_html__('Chunk Cache Directory', 'docket-cache'), 'flush_stalecache' => esc_html__('Auto Remove Stale Cache', 'docket-cache'), + 'stalecache_ignore' => esc_html__('Exclude Stale Cache', 'docket-cache'), + 'emptycache_ignore' => esc_html__('Exclude Empty Object Data', 'docket-cache'), 'limithttprequest' => esc_html__('Limit WP-Admin HTTP requests', 'docket-cache'), 'httpheadersexpect' => esc_html__('HTTP Request Expect header tweaks', 'docket-cache'), 'rtpostautosave' => esc_html__('Auto Save Interval', 'docket-cache'), @@ -139,6 +143,8 @@ public function keys($key = false) 'rtwpdebugdisplay' => esc_html__('WP Debug Display', 'docket-cache'), 'rtwpdebuglog' => esc_html__('WP Debug Log', 'docket-cache'), 'rtwpcoreupdate' => esc_html__('Disallows WP Auto Update Core', 'docket-cache'), + 'rtconcatenatescripts' => esc_html__('Deactivate Concatenate WP-Admin Scripts', 'docket-cache'), + 'rtdisablewpcron' => esc_html__('Deactivate WP Cron', 'docket-cache'), ]; $data = apply_filters('docketcache/filter/optionkeys', $data); @@ -219,7 +225,7 @@ public function get($name) return false; } - public function save($name, $value) + public function save($name, $value, $do_action = true) { if (!$this->mkdir_p($this->path)) { return false; @@ -241,7 +247,10 @@ public function save($name, $value) } $ret = $this->put_config($config); - do_action('docketcache/action/saveoption', $name, $value, $ret); + + if ($do_action) { + do_action('docketcache/action/saveoption', $name, $value, $ret); + } return $ret; } @@ -284,9 +293,7 @@ public function clear_lock() if (!empty($files) && \is_array($files)) { foreach ($files as $file) { if (@is_file($file) && @is_writable($file)) { - if (\defined('DocketCache_CLI') && DocketCache_CLI) { - @fwrite(\STDOUT, basename($file).\PHP_EOL); - } + nwdcx_cliverbose(basename($file)."\n"); @unlink($file); } } diff --git a/includes/src/Command.php b/includes/src/Command.php index bff084e..60ea490 100644 --- a/includes/src/Command.php +++ b/includes/src/Command.php @@ -24,9 +24,32 @@ class Command extends WP_CLI_Command public function __construct(Plugin $pt) { + if (empty($_SERVER['HTTP_HOST'])) { + $_SERVER['HTTP_HOST'] = wp_parse_url(site_url(), \PHP_URL_HOST); + } + $this->pt = $pt; } + private function print_stdout($text, $nl = true) + { + if (!empty($_SERVER['argv']) && \in_array('--quiet', $_SERVER['argv'])) { + return; + } + fwrite(\STDOUT, $text.($nl ? "\n" : '')); + } + + private function clear_line() + { + $this->print_stdout("\r".str_repeat(' ', 100)."\r", false); + } + + private function halt_warning($warning) + { + WP_CLI::warning($warning); + WP_CLI::halt(2); + } + private function halt_error($error) { WP_CLI::error($error, false); @@ -41,7 +64,7 @@ private function halt_success($success) private function halt_status($text, $status = 0) { - WP_CLI::line($text); + $this->print_stdout($text); WP_CLI::halt($status); } @@ -68,7 +91,7 @@ private function dropino_runtime_status() { $info = (object) $this->pt->get_info(); if (2 === $info->status_code) { - WP_CLI::line($this->title('Cache Status').$this->status_color($info->status_code, $info->status_text)); + $this->print_stdout($this->title('Cache Status').$this->status_color($info->status_code, $info->status_text)); unset($info); WP_CLI::halt(1); } @@ -87,12 +110,14 @@ public function status() $info = (object) $this->pt->get_info(); $halt = $info->status_code ? 0 : 1; - WP_CLI::line($this->title('Cache Status').$this->status_color($info->status_code, $info->status_text)); - WP_CLI::line($this->title('Cache Path').$info->cache_path); + $line = str_repeat('-', 15).':'.str_repeat('-', \strlen($info->cache_path) + 2); + $this->print_stdout($line); + $this->print_stdout($this->title('Cache Status').$this->status_color($info->status_code, $info->status_text)); + $this->print_stdout($this->title('Cache Path').$info->cache_path); if ($this->pt->cf()->is_dctrue('STATS')) { - WP_CLI::line($this->title('Cache Size').$info->cache_size); + $this->print_stdout($this->title('Cache Size').$info->cache_size); } - + $this->print_stdout($line); unset($info); WP_CLI::halt($halt); @@ -190,13 +215,15 @@ public function dropino_update() */ public function flush_cache() { - WP_CLI::line(__('Flushing cache. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing cache. Please wait..', 'docket-cache'), false); sleep(1); $is_timeout = false; $total = $this->pt->flush_cache(true, $is_timeout); + $this->clear_line(); + $this->pt->cx()->undelay(); if ($is_timeout) { @@ -242,9 +269,13 @@ public function reset_lock() */ public function reset_cron() { - WP_CLI::line(__('Resetting cron event. Please wait..', 'docket-cache')); + $this->print_stdout(__('Resetting cron event. Please wait..', 'docket-cache'), false); + ( new Event($this->pt) )->reset(); sleep(1); + + $this->clear_line(); + WP_CLI::runcommand('cron event list'); $this->halt_success(__('Cron event has been reset.', 'docket-cache')); } @@ -263,7 +294,7 @@ public function reset_cron() public function runtime_remove() { if (WpConfig::is_bedrock()) { - WP_CLI::line(__('This command does not support Bedrock. Please manually remove the runtime code.', 'docket-cache')); + $this->print_stdout(__('This command does not support Bedrock. Please manually remove the runtime code.', 'docket-cache')); WP_CLI::halt(1); } @@ -287,7 +318,7 @@ public function runtime_remove() public function runtime_install() { if (WpConfig::is_bedrock()) { - WP_CLI::line(__('This command does not support Bedrock. Please manually install the runtime code.', 'docket-cache')); + $this->print_stdout(__('This command does not support Bedrock. Please manually install the runtime code.', 'docket-cache')); WP_CLI::halt(1); } @@ -310,13 +341,15 @@ public function runtime_install() */ public function flush_precache() { - if (!\function_exists('wp_cache_flush_group')) { - $this->halt_error(__('Precache could not be flushed.', 'docket-cache')); + if (!\function_exists('wp_cache_flush_group') || !method_exists('WP_Object_Cache', 'dc_remove_group')) { + $this->halt_error(__('Object Precache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache')); } - WP_CLI::line(__('Flushing precache. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing precache. Please wait..', 'docket-cache'), false); sleep(1); - $total = wp_cache_flush_group('docketcache-precache'); + + $total = wp_cache_flush_group(['docketcache-precache', 'docketcache-precache-gc']); + $this->clear_line(); /* translators: %d = count */ $this->halt_success(sprintf(__('The precache was flushed. Total cache flushed: %d', 'docket-cache'), $total)); @@ -335,14 +368,15 @@ public function flush_precache() */ public function flush_transient() { - if (!\function_exists('wp_cache_flush_group')) { - $this->halt_error(__('Transient could not be flushed.', 'docket-cache')); + if (!\function_exists('wp_cache_flush_group') || !method_exists('WP_Object_Cache', 'dc_remove_group')) { + $this->halt_error(__('Transient could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache')); } - WP_CLI::line(__('Flushing transient. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing transient. Please wait..', 'docket-cache'), false); sleep(1); $total = wp_cache_flush_group(['transient', 'site-transient']); + $this->clear_line(); /* translators: %d = couint */ $this->halt_success(sprintf(__('The transient was flushed. Total cache flushed: %d', 'docket-cache'), $total)); @@ -361,14 +395,16 @@ public function flush_transient() */ public function flush_advcpost() { - if (!\function_exists('wp_cache_flush_group_match')) { - $this->halt_error(__('Advanced Post Cache could not be flushed.', 'docket-cache')); + if (!\function_exists('wp_cache_flush_group_match') || !method_exists('WP_Object_Cache', 'dc_remove_group')) { + $this->halt_error(__('Advanced Post Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache')); } - WP_CLI::line(__('Flushing Advanced Post Cache. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing Advanced Post Cache. Please wait..', 'docket-cache'), false); sleep(1); $total = wp_cache_flush_group_match('docketcache-post'); + $this->clear_line(); + /* translators: %d = count */ $this->halt_success(sprintf(__('The Advanced Post Cache was flushed. Total cache flushed: %d', 'docket-cache'), $total)); } @@ -386,14 +422,16 @@ public function flush_advcpost() */ public function flush_menucache() { - if (!\function_exists('wp_cache_flush_group')) { - $this->halt_error(__('Menu Cache could not be flushed.', 'docket-cache')); + if (!\function_exists('wp_cache_flush_group') || !method_exists('WP_Object_Cache', 'dc_remove_group')) { + $this->halt_error(__('Menu Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache')); } - WP_CLI::line(__('Flushing Menu Cache. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing Menu Cache. Please wait..', 'docket-cache'), false); sleep(1); $total = wp_cache_flush_group('docketcache-menu'); + $this->clear_line(); + /* translators: %d = count */ $this->halt_success(sprintf(__('The Menu Cache was flushed. Total cache flushed: %d', 'docket-cache'), $total)); } @@ -411,14 +449,16 @@ public function flush_menucache() */ public function flush_mocache() { - if (!\function_exists('wp_cache_flush_group')) { - $this->halt_error(__('Translation Cache could not be flushed.', 'docket-cache')); + if (!\function_exists('wp_cache_flush_group') || !method_exists('WP_Object_Cache', 'dc_remove_group')) { + $this->halt_error(__('Translation Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache')); } - WP_CLI::line(__('Flushing Translation Cache. Please wait..', 'docket-cache')); + $this->print_stdout(__('Flushing Translation Cache. Please wait..', 'docket-cache'), false); sleep(1); $total = wp_cache_flush_group('docketcache-mo'); + $this->clear_line(); + /* translators: %d = count */ $this->halt_success(sprintf(__('The Translation Cache was flushed. Total cache flushed: %d', 'docket-cache'), $total)); } @@ -436,9 +476,13 @@ public function flush_mocache() */ public function run_cron() { - WP_CLI::line(__('Executing the cron event. Please wait..', 'docket-cache')); + $this->print_stdout(__('Executing the cron event. Please wait..', 'docket-cache'), false); sleep(1); + + $this->clear_line(); + WP_CLI::runcommand('cron event run --all'); + WP_CLI::runcommand('cron event list'); } /** @@ -454,16 +498,51 @@ public function run_cron() */ public function run_stats() { - WP_CLI::line(__('Executing the cache stats. Please wait..', 'docket-cache')); + $this->print_stdout(__('Executing the cache stats. Please wait..', 'docket-cache'), false); sleep(1); + $pad = 15; $stats = $this->pt->get_cache_stats(true); - WP_CLI::line($this->title(__('Object size', 'docket-cache'), $pad).$this->pt->normalize_size($stats->size)); - WP_CLI::line($this->title(__('File size', 'docket-cache'), $pad).$this->pt->normalize_size($stats->filesize)); - WP_CLI::line($this->title(__('Total file', 'docket-cache'), $pad).$stats->files); + + $this->clear_line(); + + $padr = 10; + if (\strlen($stats->files) > 10) { + $padr = \strlen($stats->files); + } + + $line = str_repeat('-', $pad).':'.str_repeat('-', $padr); + $this->print_stdout($line); + $this->print_stdout($this->title(__('Object size', 'docket-cache'), $pad).$this->pt->normalize_size($stats->size)); + $this->print_stdout($this->title(__('File size', 'docket-cache'), $pad).$this->pt->normalize_size($stats->filesize)); + $this->print_stdout($this->title(__('Total file', 'docket-cache'), $pad).$stats->files); + $this->print_stdout($line); $this->halt_success(__('Executing the cache stats completed.', 'docket-cache')); } + /** + * Runs the Docket Cache Optimizedb. + * + * Optimize DB. + * + * ## EXAMPLES + * + * wp cache run:optimizedb + * + * @subcommand run:stats + */ + public function run_optimizedb() + { + $this->print_stdout(__('Executing the optimizedb. Please wait..', 'docket-cache'), false); + sleep(1); + + ( new Event($this->pt) )->optimizedb(); + + $this->clear_line(); + + $this->halt_success(__('Executing the optimizedb completed.', 'docket-cache')); + } + /** * Runs the Docket Cache garbage collector (GC). * @@ -477,42 +556,45 @@ public function run_stats() */ public function run_gc() { - if (!has_filter('docketcache/filter/garbagecollector')) { - $this->halt_error(__('Garbage collector not available.', 'docket-cache')); - } - - WP_CLI::line(__('Executing the garbage collector. Please wait..', 'docket-cache')); + $this->print_stdout(__('Executing the garbage collector. Please wait..', 'docket-cache'), false); sleep(1); $pad = 35; - $collect = apply_filters('docketcache/filter/garbagecollector', true); + $collect = ( new Event($this->pt) )->garbage_collector(true); + + $this->clear_line(); + + if ($collect->is_locked) { + $this->halt_warning(__('Process locked. The garbage collector is in process. Try again in a few seconds.', 'docket-cache')); + } - WP_CLI::line(str_repeat('-', $pad).':'.str_repeat('-', 10)); - WP_CLI::line($this->title(__('Cache MaxTTL', 'docket-cache'), $pad).$collect->cache_maxttl); - WP_CLI::line($this->title(__('Cache File Limit', 'docket-cache'), $pad).$collect->cache_maxfile); - WP_CLI::line($this->title(__('Cache Disk Limit', 'docket-cache'), $pad).$this->pt->normalize_size($collect->cache_maxdisk)); - WP_CLI::line(str_repeat('-', $pad).':'.str_repeat('-', 10)); - WP_CLI::line($this->title(__('Cleanup Cache MaxTTL', 'docket-cache'), $pad).$collect->cleanup_maxttl); - WP_CLI::line($this->title(__('Cleanup Cache File Limit', 'docket-cache'), $pad).$collect->cleanup_maxfile); - WP_CLI::line($this->title(__('Cleanup Cache Disk Limit', 'docket-cache'), $pad).$collect->cleanup_maxdisk); + $line = str_repeat('-', $pad).':'.str_repeat('-', 10); + $this->print_stdout($line); + $this->print_stdout($this->title(__('Cache MaxTTL', 'docket-cache'), $pad).$collect->cache_maxttl); + $this->print_stdout($this->title(__('Cache File Limit', 'docket-cache'), $pad).$collect->cache_maxfile); + $this->print_stdout($this->title(__('Cache Disk Limit', 'docket-cache'), $pad).$this->pt->normalize_size($collect->cache_maxdisk)); + $this->print_stdout($line); + $this->print_stdout($this->title(__('Cleanup Cache MaxTTL', 'docket-cache'), $pad).$collect->cleanup_maxttl); + $this->print_stdout($this->title(__('Cleanup Cache File Limit', 'docket-cache'), $pad).$collect->cleanup_maxfile); + $this->print_stdout($this->title(__('Cleanup Cache Disk Limit', 'docket-cache'), $pad).$collect->cleanup_maxdisk); if ($collect->cleanup_expire > 0) { - WP_CLI::line($this->title(__('Cleanup Cache Expire', 'docket-cache'), $pad).$collect->cleanup_expire); + $this->print_stdout($this->title(__('Cleanup Cache Expire', 'docket-cache'), $pad).$collect->cleanup_expire); } if ($this->pt->get_precache_maxfile() > 0 && $collect->cleanup_precache_maxfile > 0) { - WP_CLI::line($this->title(__('Cleanup Precache Limit', 'docket-cache'), $pad).$collect->cleanup_precache_maxfile); + $this->print_stdout($this->title(__('Cleanup Precache Limit', 'docket-cache'), $pad).$collect->cleanup_precache_maxfile); } if ($this->pt->cf()->is_dctrue('FLUSH_STALECACHE') && $collect->cleanup_stalecache > 0) { - WP_CLI::line($this->title(__('Cleanup Stale Cache', 'docket-cache'), $pad).$collect->cleanup_stalecache); + $this->print_stdout($this->title(__('Cleanup Stale Cache', 'docket-cache'), $pad).$collect->cleanup_stalecache); } - WP_CLI::line(str_repeat('-', $pad).':'.str_repeat('-', 10)); - WP_CLI::line($this->title(__('Total Cache Cleanup', 'docket-cache'), $pad).$collect->cache_cleanup); - WP_CLI::line($this->title(__('Total Cache Ignored', 'docket-cache'), $pad).$collect->cache_ignore); - WP_CLI::line($this->title(__('Total Cache File', 'docket-cache'), $pad).$collect->cache_file); - WP_CLI::line(str_repeat('-', $pad).':'.str_repeat('-', 10)); + $this->print_stdout($line); + $this->print_stdout($this->title(__('Total Cache Cleanup', 'docket-cache'), $pad).$collect->cache_cleanup); + $this->print_stdout($this->title(__('Total Cache Ignored', 'docket-cache'), $pad).$collect->cache_ignore); + $this->print_stdout($this->title(__('Total Cache File', 'docket-cache'), $pad).$collect->cache_file); + $this->print_stdout($line); $this->halt_success(__('Executing the garbage collector completed.', 'docket-cache')); } diff --git a/includes/src/Constans.php b/includes/src/Constans.php index 164a2af..8710cc9 100644 --- a/includes/src/Constans.php +++ b/includes/src/Constans.php @@ -149,6 +149,12 @@ public function maybe_define($name, $value, $user_config = true) return @\define($name, $value); } + // mark defined constants + if (empty($GLOBALS['DOCKET_CACHE_RUNTIME'])) { + $GLOBALS['DOCKET_CACHE_RUNTIME'] = []; + } + $GLOBAL['DOCKET_CACHE_RUNTIME'][$this->px($name.'_FALSE')] = 1; + return false; } @@ -165,7 +171,7 @@ public function register_default() // cache dir $this->maybe_define($this->px('PATH'), DOCKET_CACHE_CONTENT_PATH.'/cache/docket-cache/', false); - // cache file max size: 3MB, 1MB = 1048576 bytes (binary) = 1000000 bytes (decimal) + // object max size: 3MB, 1MB = 1048576 bytes (binary) = 1000000 bytes (decimal) // Only numbers between 1000000 and 10485760 are accepted $this->maybe_define($this->px('MAXSIZE'), 3145728); @@ -176,6 +182,9 @@ public function register_default() // cache file max accelerated files: Only numbers between 200 and 200000 are accepted $this->maybe_define($this->px('MAXFILE'), 50000); + // check cache file limit in real-time + $this->maybe_define($this->px('MAXFILE_LIVECHECK'), false); + // cache maxttl: cache lifespan. Only seconds between 86400 and 2419200 are accepted $this->maybe_define($this->px('MAXTTL'), 345600); // 4d @@ -203,19 +212,25 @@ public function register_default() // flush cache when deactivate/uninstall $this->maybe_define($this->px('FLUSH_SHUTDOWN'), true); - // flush wc_cache / advanced post cache stale cache + // flush wc_cache / advanced post cache / wp stale cache $this->maybe_define($this->px('FLUSH_STALECACHE'), false); // split a cache file into smaller directory $this->maybe_define($this->px('CHUNKCACHEDIR'), false); + // ignore stale cache + $this->maybe_define($this->px('STALECACHE_IGNORE'), false); + + // ignore empty cache + $this->maybe_define($this->px('EMPTYCACHE_IGNORE'), false); + // optimize db $this->maybe_define($this->px('CRONOPTMZDB'), 'never'); // option autoload $this->maybe_define($this->px('WPOPTALOAD'), false); - // global cache group + // global cache group for multisite $this->maybe_define( $this->px('GLOBAL_GROUPS'), [ @@ -254,6 +269,10 @@ public function register_default() // @note: dnh_dismissed_notices -> https://github.com/julien731/WP-Dismissible-Notices-Handler $this->maybe_define($this->px('IGNORED_KEYS'), ['dnh_dismissed_notices']); + // @private + // cache ignored group => key, group => [key1, key2] + $this->maybe_define($this->px('IGNORED_GROUPKEY'), []); + // @private // this option private for right now $this->maybe_define( @@ -266,30 +285,36 @@ public function register_default() ] ); - // @private - // cache ignored group:key - $this->maybe_define($this->px('IGNORED_GROUPKEY'), []); - // precache $this->maybe_define($this->px('PRECACHE'), false); - // precache maxfile: < 1, false, null = unlimited - $this->maybe_define($this->px('PRECACHE_MAXFILE'), 1000); + // precache maxfile + $this->maybe_define($this->px('PRECACHE_MAXFILE'), 100); + + // precache max key + $this->maybe_define($this->px('PRECACHE_MAXKEY'), 20); - // precache maxlist - $this->maybe_define($this->px('PRECACHE_MAXLIST'), 1000); + // precache max group + $this->maybe_define($this->px('PRECACHE_MAXGROUP'), 20); // @private // cache ignored precache $this->maybe_define( $this->px('IGNORED_PRECACHE'), [ - 'freemius:fs_accounts', - 'options:uninstall_plugins', - 'options:active_plugins', - 'options:cron', - 'options:litespeed_messages', - 'options:litespeed.admin_display.messages', + 'freemius' => 'fs_accounts', + 'options' => [ + 'uninstall_plugins', + 'auto_update_plugins', + 'active_plugins', + 'cron', + 'litespeed_messages', + 'litespeed.admin_display.messages', + ], + 'site-options' => [ + '1:auto_update_plugins', + '1:active_sitewide_plugins', + ], ] ); @@ -324,7 +349,25 @@ public function register_default() $this->maybe_define($this->px('ADVCPOST'), false); // advanced post cache allow post type - $this->maybe_define($this->px('ADVCPOST_POSTTYPE'), ['post', 'page', 'attachment']); + $this->maybe_define( + $this->px('ADVCPOST_POSTTYPE'), + [ + 'post', + 'page', + 'attachment', + 'revision', + 'nav_menu_item', + 'custom_css', + 'customize_changeset', + 'oembed_cache', + 'user_request', + 'wp_block', + 'wp_template', + 'wp_template_part', + 'wp_global_styles', + 'wp_navigation', + ] + ); // advanced post cache allow all post type $this->maybe_define($this->px('ADVCPOST_POSTTYPE_ALL'), false); @@ -375,8 +418,11 @@ public function register_default() // check version $this->maybe_define($this->px('CHECKVERSION'), false); - // auto update - $this->maybe_define($this->px('AUTOUPDATE'), false); + // / @private: auto update + // 28012023: DOCKET_CACHE_AUTOUPDATE only to force WP auto_update_plugin filter. + // DOCKET_CACHE_AUTOUPDATE_TOGGLE will sync with WP auto_update_plugins option. + // $this->maybe_define($this->px('AUTOUPDATE'), false); + $this->maybe_define($this->px('AUTOUPDATE_TOGGLE'), false); // flush opcache when deactivate $this->maybe_define($this->px('OPCSHUTDOWN'), false); @@ -468,6 +514,12 @@ public function register_default() // @private: deactivate wp auto update core. $this->maybe_define($this->px('RTWPCOREUPDATE'), \defined('WP_AUTO_UPDATE_CORE') && WP_AUTO_UPDATE_CORE ? 'off' : 'on'); + // @private: deactivate concatenate wp-admin scripts. + $this->maybe_define($this->px('RTCONCATENATESCRIPTS'), \defined('CONCATENATE_SCRIPTS') && !(bool) CONCATENATE_SCRIPTS ? 'on' : 'off'); + + // @private: deactivate wp cron. + $this->maybe_define($this->px('RTDISABLEWPCRON'), \defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ? 'on' : 'off'); + // @private // capture fatal error rarely incase non-throwable // set true for debugging only diff --git a/includes/src/Crawler.php b/includes/src/Crawler.php index 3ed5d9c..4120e69 100644 --- a/includes/src/Crawler.php +++ b/includes/src/Crawler.php @@ -14,7 +14,7 @@ final class Crawler { - private static $version = '22.07.02'; + private static $version = '22.07.03'; public static $send_cookie = false; private static function default_args($param = []) diff --git a/includes/src/Event.php b/includes/src/Event.php index cba3c9a..d610f6e 100644 --- a/includes/src/Event.php +++ b/includes/src/Event.php @@ -75,23 +75,25 @@ function ($schedules) { add_action( 'plugins_loaded', function () { - // 19092020: standardize. rename hooks - foreach (['docket_cache_gc', 'docket_cache_optimizedb', 'docket_cache_monitor'] as $hx) { + // 19092020: standardize. rename hooks. + // 19012023: remove docketcache_watchproc. + foreach (['docket_cache_gc', 'docket_cache_optimizedb', 'docket_cache_monitor', 'docketcache_watchproc'] as $hx) { if (false !== wp_get_scheduled_event($hx)) { wp_clear_scheduled_hook($hx); } } - // gc: always enable - add_action('docketcache_gc', [$this, 'garbage_collector']); - if (!wp_next_scheduled('docketcache_gc')) { - wp_schedule_event(time(), 'docketcache_gc_schedule', 'docketcache_gc'); - } - - // monitor: always enable - add_action('docketcache_watchproc', [$this, 'watchproc']); - if (!wp_next_scheduled('docketcache_watchproc')) { - wp_schedule_event(time(), 'hourly', 'docketcache_watchproc'); + // garbage collector + // 27012023: added disable constant + if ($this->pt->cf()->is_dcfalse('GCRON_DISABLED')) { + add_action('docketcache_gc', [$this, 'garbage_collector']); + if (!wp_next_scheduled('docketcache_gc')) { + wp_schedule_event(time(), 'docketcache_gc_schedule', 'docketcache_gc'); + } + } else { + if (wp_get_schedule('docketcache_gc')) { + wp_clear_scheduled_hook('docketcache_gc'); + } } // optimize db @@ -127,7 +129,7 @@ function () { } // check version - if ($this->pt->cf()->is_dctrue('CHECKVERSION')) { + if ($this->pt->cf()->is_dctrue('CHECKVERSION', true)) { // 06102020: reset old schedule $check = wp_get_scheduled_event('docketcache_checkversion'); if (\is_object($check) && 'docketcache_checkversion_schedule' !== $check->schedule) { @@ -145,6 +147,11 @@ function () { wp_clear_scheduled_hook('docketcache_checkversion'); } } + + // expired transient in DB + if (has_action('delete_expired_transients') && wp_using_ext_object_cache()) { + add_action('delete_expired_transients', [$this, 'delete_expired_transients_db']); + } } ); } @@ -160,7 +167,7 @@ public function unregister() } /** - * reset,. + * reset. */ public function reset() { @@ -168,27 +175,6 @@ public function reset() $this->register(); } - /** - * monitor. - */ - public function watchproc() - { - if ($this->pt->co()->lockproc('watchproc', time() + 3600)) { - return false; - } - - if (!$this->is_optimizedb) { - $this->delete_expired_transients_db(); - } - - // $this->clear_unknown_cron(); - - $this->pt->get_cache_stats(true); - $this->pt->co()->lockreset('watchproc'); - - return true; - } - /** * garbage_collector. */ @@ -196,29 +182,29 @@ public function garbage_collector($force = false) { static $is_done = false; - $maxfileo = (int) $this->pt->get_cache_maxfile(); - $maxfile = $maxfileo; + $maxfile_default = (int) $this->pt->get_cache_maxfile(); + $maxfile = $maxfile_default; - if ($maxfileo > 10000) { - $maxfile = $maxfileo - 1000; + if ($maxfile_default > 10000) { + $maxfile = $maxfile_default - 1000; } - $maxfileo_pre = (int) $this->pt->get_precache_maxfile(); - $maxfile_pre = $maxfileo_pre; + $maxfile_precache_default = (int) $this->pt->get_precache_maxfile(); + $maxfile_precache = $maxfile_precache_default; - if ($maxfileo_pre > 10000) { - $maxfile_pre = $maxfileo_pre - 1000; + if ($maxfile_precache_default > 10000) { + $maxfile_precache = $maxfile_precache_default - 1000; } - $maxttl0 = (int) $this->pt->get_cache_maxttl(); - $maxttl = $maxttl0; + $maxttl_default = (int) $this->pt->get_cache_maxttl(); + $maxttl = $maxttl_default; if (!empty($maxttl)) { $maxttl = time() - $maxttl; } $chkmaxdisk = false; - $maxsizedisk0 = (int) $this->pt->get_cache_maxsize_disk(); - $maxsizedisk = $maxsizedisk0; + $maxsizedisk_default = (int) $this->pt->get_cache_maxsize_disk(); + $maxsizedisk = $maxsizedisk_default; if (!empty($maxsizedisk)) { $maxsizedisk = $maxsizedisk - 1048576; @@ -228,9 +214,10 @@ public function garbage_collector($force = false) } $collect = (object) [ - 'cache_maxttl' => $maxttl0, - 'cache_maxfile' => $maxfileo, - 'cache_maxdisk' => $maxsizedisk0, + 'is_locked' => false, + 'cache_maxttl' => $maxttl_default, + 'cache_maxfile' => $maxfile_default, + 'cache_maxdisk' => $maxsizedisk_default, 'cleanup_maxfile' => 0, 'cleanup_precache_maxfile' => 0, 'cleanup_maxttl' => 0, @@ -245,29 +232,63 @@ public function garbage_collector($force = false) clearstatcache(); if (!$this->pt->is_docketcachedir($this->pt->cache_path) || @is_file(DOCKET_CACHE_CONTENT_PATH.'/.object-cache-flush.txt')) { + $collect->is_locked = true; + return $collect; } - if ($is_done || $this->pt->co()->lockproc('garbage_collector', time() + $this->max_execution_time + 10)) { + // try to set max execution time to 3 minutes if not 0 or lower than 180 seconds. + $max_execution_time = $this->pt->get_max_execution_time(180); + + // lock process. + $lock_expiry = $max_execution_time > 0 ? $max_execution_time : 180; + $lock_expiry = time() + $lock_expiry; + if ($is_done || $this->pt->co()->lockproc('garbage_collector', $lock_expiry)) { + $collect->is_locked = true; + return $collect; } - $stalecache_list = []; - if ($this->pt->cf()->is_dctrue('FLUSH_STALECACHE')) { - $stalecache_list = wp_cache_get('items', 'docketcache-stalecache'); - wp_cache_delete('items', 'docketcache-stalecache'); + // Stalecache + $is_flush_stalecache = $this->pt->cf()->is_dctrue('FLUSH_STALECACHE', true); + $is_ignore_stalecache = $this->pt->cf()->is_dctrue('STALECACHE_IGNORE', true); + + $wp_cache_last_changed = []; + $wp_cache_last_changed_match = [ + 'posts' => 'wp_query', + 'terms' => 'get_terms', + 'comment' => 'get_comments', + 'comment_feed' => 'comment_feed', + 'sites' => 'get_sites', + 'networks' => 'get_network_ids', + ]; + foreach ($wp_cache_last_changed_match as $grp => $kk) { + $wp_cache_last_changed[$grp] = wp_cache_get_last_changed($grp); } + $wp_cache_last_changed['advpost'] = wp_cache_get('cache_incr', 'docketcache-post'); + $wc_has_cache_helper = method_exists('WC_Cache_Helper', 'get_cache_prefix'); + $wc_session_cache_group = \defined('WC_SESSION_CACHE_GROUP') ? WC_SESSION_CACHE_GROUP : 'wc_session_id'; + $delay = $force ? 650 : 5000; - wp_suspend_cache_addition(true); + if ('cli' === \PHP_SAPI) { + $delay = 100; + } + + // hold cache write + $this->pt->suspend_cache_write(true); - $fsizetotal = 0; - $fcnt = 0; - $pcnt = 0; + $filesize_total = 0; + $file_cache_count = 0; + $file_precache_count = 0; + $bytes_total = 0; $slowdown = 0; + $gcisrun_lock = $this->pt->cache_path.'/.gc-is-run.txt'; + $this->pt->touch($gcisrun_lock); + foreach ($this->pt->scanfiles($this->pt->cache_path) as $object) { - if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) { + if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) { break; } @@ -296,9 +317,7 @@ public function garbage_collector($force = false) continue; } - if ($this->pt->cf()->is_dctrue('DEV') && 'cli' === \PHP_SAPI) { - echo 'run-gc: '.$fx."\n"; - } + nwdcx_cliverbose('run-gc: '.$fx."\n"); if ($fm >= $ft && (0 === $fs || 'dump_' === substr($fn, 0, 5))) { $this->pt->unlink($fx, true); @@ -309,11 +328,24 @@ public function garbage_collector($force = false) continue; } + // 03022023: timeout 0 was set to maxtll, see WP_Object_Cache::maybe_expire + // cleanup first to reduce memory usage + if ($maxttl > 0 && $maxttl > $ft) { + $this->pt->unlink($fx, true); + + if ($force && @is_file($fx)) { + ++$collect->cleanup_failed; + } + + ++$collect->cleanup_maxttl; + continue; + } + // 032e9f2c5b60- = docketcache-precache- - if ($maxfile_pre > 0 && '032e9f2c5b60-' === substr($fn, 0, 13)) { - ++$pcnt; + if ($maxfile_precache > 0 && '032e9f2c5b60-' === substr($fn, 0, 13)) { + ++$file_precache_count; - if ($pcnt > $maxfile_pre) { + if ($file_precache_count > $maxfile_precache) { $this->pt->unlink($fx, true); if ($force && @is_file($fx)) { @@ -325,10 +357,7 @@ public function garbage_collector($force = false) } } - if ($fcnt >= $maxfile) { - // trigger WP_Object_Cache - wp_cache_set('numfile', $fcnt, 'docketcache-gc', 60); - + if ($file_cache_count >= $maxfile) { $this->pt->unlink($fx, true); if ($force && @is_file($fx)) { @@ -339,8 +368,7 @@ public function garbage_collector($force = false) continue; } - $fsizetotal += $fs; - if ($chkmaxdisk && $fsizetotal > $maxsizedisk) { + if ($chkmaxdisk && $filesize_total > $maxsizedisk) { $this->pt->unlink($fx, true); if ($force && @is_file($fx)) { @@ -382,131 +410,190 @@ public function garbage_collector($force = false) continue; } } - } - // no timeout data or 0 - if (false === $is_timeout && $maxttl > 0 && $maxttl > $ft) { - $this->pt->unlink($fx, true); + if ($is_flush_stalecache) { + // wp stale cache + if (!empty($wp_cache_last_changed_match[$data['group']]) && preg_match('@^(wp_query|get_terms|get_comments|comment_feed|get_sites|get_network_ids|get_page_by_path):([0-9a-f]{32}):([0-9\. ]{21})([0-9\. ]+)?$@', $data['key'], $mm)) { + if ('get_page_by_path' === $mm[1]) { + $mm[1] = 'wp_query'; + } - if ($force && @is_file($fx)) { - ++$collect->cleanup_failed; - } + $km = $wp_cache_last_changed_match[$data['group']]; - ++$collect->cleanup_maxttl; - continue; - } + if (($km === $mm[1] && $wp_cache_last_changed[$data['group']] !== $mm[3]) || $is_ignore_stalecache) { + if (@unlink($fx)) { + clearstatcache(true, $fx); - // stalecache - if ((!empty($stalecache_list) && \is_array($stalecache_list)) && !empty($data) && !empty($data['key']) && !empty($data['group']) && 'docketcache-stalecache' !== $data['group']) { - $collect->cleanup_stalecache += $this->flush_stalecache($fx, $data, $stalecache_list); - if ($collect->cleanup_stalecache > 0) { - continue; - } - } - unset($data); + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); - ++$fcnt; - ++$collect->cache_file; - } // foreach1 + ++$collect->cleanup_stalecache; + continue; + } + } + } - $collect->cache_cleanup = $collect->cleanup_maxttl + $collect->cleanup_expire + $collect->cleanup_maxfile + $collect->cleanup_maxdisk + $collect->cleanup_precache_maxfile + $collect->cleanup_stalecache; + // advpost stale cache + if (false !== strpos($data['group'], 'docketcache-post-') && preg_match('@^docketcache-post-(\d+)$@', $data['group'], $mm)) { + if ((int) $wp_cache_last_changed['advpost'] !== (int) $mm[1] || $is_ignore_stalecache) { + if (@unlink($fx)) { + clearstatcache(true, $fx); - wp_suspend_cache_addition(false); + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); - $this->pt->co()->lockreset('garbage_collector'); - $this->pt->cx()->delay_expire(); + ++$collect->cleanup_stalecache; + continue; + } + } + } - $is_done = true; + // wc stale cache + if (false !== strpos($data['key'], 'wc_cache_') && preg_match('@^(wc_cache_[0-9\. ]+_)@', $data['key'], $mm)) { + if (!$wc_has_cache_helper || $is_ignore_stalecache) { + if (@unlink($fx)) { + clearstatcache(true, $fx); - // reset - wp_cache_delete('numfile', 'docketcache-gc'); + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); - return $collect; - } + ++$collect->cleanup_stalecache; + } + continue; + } - /** - * flush_stalecache. - */ - public function flush_stalecache($file, $data, $stalecache_list) - { - $total = 0; + $current_prefix = $mm[1]; + static $cache_prefix_cached = []; - if (!is_file($file) || empty($data) || empty($data['key']) || empty($data['group']) || empty($stalecache_list) || !\is_array($stalecache_list)) { - return $total; - } + // wc product + if ('products' === $data['group'] && preg_match('@.*?_type_(\d+)$@', $data['key'], $nn)) { + $grp = 'product_'.$nn[1]; - $slowdown = 0; - foreach ($stalecache_list as $id => $key) { - $do_flush = false; + if (!empty($cache_prefix_cached[$grp])) { + $cache_prefix = $cache_prefix_cached; + } else { + $cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp); + $cache_prefix_cached[$grp] = $cache_prefix; + } - if (false !== strpos($data['key'], 'wc_cache_') && 'wc_cache:' === substr($key, 0, 9) && preg_match('@^wc_cache_([0-9\. ]+)_.*@', $data['key'], $mm)) { - list($prefix, $group, $usec) = explode(':', $key); - if ($usec === $mm[1]) { - $do_flush = true; - } else { - $usec1 = nwdcx_microtimetofloat($usec); - $usec2 = nwdcx_microtimetofloat($mm[1]); - if ($usec1 > $usec2) { - $do_flush = true; - } - } - } - // group = from cache file, key = list key - elseif (false !== strpos($data['group'], 'docketcache-post-') && false !== strpos($key, 'docketcache-post-')) { - if ($key === $data['group']) { - $do_flush = true; - } else { - $usec1 = str_replace('docketcache-post-', '', $key); - $usec2 = str_replace('docketcache-post-', '', $data['group']); - if ($usec1 > $usec2) { - $do_flush = true; - } - } - } elseif (false !== strpos($key, 'last_changed:') && @preg_match('@(.*):([a-z0-9]{32}):([0-9\. ]+)$@', $data['key'], $mm)) { - list($prefix, $group, $usec) = explode(':', $key); - if ($group === $data['group']) { - $usec1 = nwdcx_microtimetofloat($usec); - $usec2 = nwdcx_microtimetofloat($mm[3]); - if ($usec1 > $usec2) { - $do_flush = true; + if ($cache_prefix !== $current_prefix) { + if (@unlink($fx)) { + clearstatcache(true, $fx); + + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); + + ++$collect->cleanup_stalecache; + continue; + } + } + } + + if (\in_array($data['group'], + [ + 'products', 'coupons', 'orders', 'webhooks', 'taxes', 'shipping_zones', + 'woocommerce-attributes', 'store_api_rate_limit', $wc_session_cache_group, + ])) { + $grp = $data['group']; + + if (!empty($cache_prefix_cached[$grp])) { + $cache_prefix = $cache_prefix_cached; + } else { + $cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp); + $cache_prefix_cached[$grp] = $cache_prefix; + } + + if ($cache_prefix !== $current_prefix) { + if (@unlink($fx)) { + clearstatcache(true, $fx); + + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); + + ++$collect->cleanup_stalecache; + continue; + } + } + } + + if ('wc_rate_limit' === $data['group'] && 'rate_limit' === substr($data['key'], 0, 10)) { + $grp = $data['group']; + + if (!empty($cache_prefix_cached[$grp])) { + $cache_prefix = $cache_prefix_cached; + } else { + $cache_prefix = \WC_Cache_Helper::get_cache_prefix($grp); + $cache_prefix_cached[$grp] = $cache_prefix; + } + + if ($cache_prefix !== $current_prefix) { + if (@unlink($fx)) { + clearstatcache(true, $fx); + + nwdcx_cliverbose('run-gc:stale-cache: '.$fx."\n"); + + ++$collect->cleanup_stalecache; + continue; + } + } + } } } - } elseif (false !== strpos($key, 'after:') && @preg_match('@(.*):([a-z0-9]{32}):([0-9\. ]+)$@', $data['key'], $mm)) { - list($prefix, $group, $usec, $abc) = explode(':', $key); - if ($group === $data['group'] && $abc === $mm[1]) { - $usec1 = nwdcx_microtimetofloat($usec); - $usec2 = nwdcx_microtimetofloat($mm[3]); - if ($usec1 > $usec2) { - $do_flush = true; - } + $bytes_total += \strlen(serialize($data)); + } // data + + // no timeout data or 0 + // 03022023: timeout 0 was set to maxtll, see WP_Object_Cache::maybe_expire + /*if (false === $is_timeout && $maxttl > 0 && $maxttl > $ft) { + $this->pt->unlink($fx, true); + + if ($force && @is_file($fx)) { + ++$collect->cleanup_failed; } - } - if ($do_flush) { - $nwdcx_suppresserrors = nwdcx_suppresserrors(true); - // use native unlink since it is a junk file. - if (@unlink($file)) { - unset($stalecache_list[$id]); + ++$collect->cleanup_maxttl; + continue; + }*/ - if ($this->pt->cf()->is_dctrue('DEV') && 'cli' === \PHP_SAPI) { - echo 'run-gc:stale-cache: '.$file."\n"; - } + unset($data); - ++$total; - } - nwdcx_suppresserrors($nwdcx_suppresserrors); - break; // found and break foreach - } + $filesize_total += $fs; + ++$file_cache_count; + } // foreach1 - if ($slowdown > 10) { - $slowdown = 0; - usleep(5000); - } + @unlink($gcisrun_lock); - ++$slowdown; + $collect->cache_file = $file_cache_count; + + $collect->cache_cleanup = $collect->cleanup_maxttl + $collect->cleanup_expire + $collect->cleanup_maxfile + $collect->cleanup_maxdisk + $collect->cleanup_precache_maxfile + $collect->cleanup_stalecache; + + // release + $this->pt->suspend_cache_write(false); + + if (\function_exists('nwdcx_cleanuptransient')) { + nwdcx_cliverbose("run-gc: cleanup expired transients in DB\n"); + nwdcx_cleanuptransient(); } - return $total; + // reset gc + $count_file = $collect->cache_file; + $count_file = $count_file < 0 ? 0 : $count_file; + wp_cache_set('count_file', $count_file, 'docketcache-gc', 86400); + + // reset precache + $count_file = $file_precache_count - $collect->cleanup_precache_maxfile; + $count_file = $count_file < 0 ? 0 : $count_file; + wp_cache_set('count_file', $count_file, 'docketcache-precache-gc', 86400); + + // stats + $this->pt->co()->save_part([ + 'timestamp' => time(), + 'size' => $bytes_total, + 'filesize' => $filesize_total, + 'files' => $collect->cache_file, + ], 'cachestats'); + + // done + $this->pt->co()->lockreset('garbage_collector'); + $this->pt->cx()->delay_expire(); + $is_done = true; + + return $collect; } /** @@ -525,21 +612,20 @@ public function optimizedb() $suppress = $wpdb->suppress_errors(true); @set_time_limit(300); + $max_execution_time = $this->pt->get_max_execution_time(); $this->delete_expired_transients_db(); if (is_main_site() && is_main_network()) { $dbname = $wpdb->dbname; $tables = $wpdb->get_results('SHOW TABLES FROM '.$dbname, ARRAY_A); if (!empty($tables) && \is_array($tables)) { - $max_execution_time = $this->max_execution_time; - if ($max_execution_time < 300) { - $max_execution_time = 300; - } foreach ($tables as $table) { $tbl = $table['Tables_in_'.$dbname]; - $wpdb->query('OPTIMIZE TABLE `'.$tbl.'`'); + $sql = 'OPTIMIZE TABLE `'.$tbl.'`'; + $ret = $wpdb->query($sql); - if ($this->max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $this->max_execution_time) { + nwdcx_cliverbose(str_replace('`', '', $sql)."\n"); + if ($max_execution_time > 0 && (microtime(true) - $this->wp_start_timestamp) > $max_execution_time) { break; } } @@ -549,6 +635,8 @@ public function optimizedb() $wpdb->suppress_errors($suppress); + $this->pt->co()->lockreset('optimizedb'); + return true; } @@ -557,10 +645,6 @@ public function optimizedb() */ public function delete_expired_transients_db() { - if (!wp_using_ext_object_cache()) { - return false; - } - if (!nwdcx_wpdb($wpdb)) { return false; } @@ -575,33 +659,8 @@ public function delete_expired_transients_db() } /** - * clear_unknown_cron. + * checkversion. */ - public function clear_unknown_cron() - { - // let's wp handles it. - return; - - if (!wp_using_ext_object_cache()) { - return; - } - - if (!\function_exists('_get_cron_array')) { - return; - } - $crons = _get_cron_array(); - if (!empty($crons) && \is_array($crons)) { - foreach ($crons as $time => $cron) { - foreach ($cron as $hook => $dings) { - if (!has_action($hook)) { - wp_clear_scheduled_hook($hook); - } - } - } - } - unset($crons); - } - public function checkversion() { if (!is_main_site()) { @@ -688,6 +747,7 @@ public function checkversion() } $this->pt->co()->save_part($output, $part); + $this->pt->co()->lockreset($part); return true; } diff --git a/includes/src/Filesystem.php b/includes/src/Filesystem.php index ffc30cd..16de391 100644 --- a/includes/src/Filesystem.php +++ b/includes/src/Filesystem.php @@ -125,9 +125,9 @@ public function is_docketcachefile($file) /** * is_docketcachegroup. */ - public function is_docketcachegroup($group) + public function is_docketcachegroup($group, $key = '') { - return 'docketcache' === substr($group, 0, 11); + return 'docketcache' === substr($group, 0, 11) || !empty($key) && 'docketcache' === substr($key, 0, 11); } /** @@ -157,9 +157,16 @@ public function is_dirempty($dir) /** * get_max_execution_time. */ - public function get_max_execution_time() + public function get_max_execution_time($second = 0) { $max_execution_time = (int) \ini_get('max_execution_time'); + + $second = (int) $second; + if ($second > 0 && $max_execution_time > 0 && $second > $max_execution_time) { + set_time_limit($second); + $max_execution_time = (int) \ini_get('max_execution_time'); + } + if ($max_execution_time > 10) { --$max_execution_time; } @@ -418,9 +425,12 @@ public function shutdown_cleanup($file, $seq = 10) add_action( 'shutdown', function () use ($file) { + $nwdcx_suppresserrors = nwdcx_suppresserrors(true); + clearstatcache(true, $file); if (@is_file($file)) { @unlink($file); } + nwdcx_suppresserrors($nwdcx_suppresserrors); }, $seq ); @@ -431,6 +441,8 @@ function () use ($file) { */ public function unlink($file, $is_delete = false, $is_block = false) { + clearstatcache(true, $file); + // skip if not exist if (!@is_file($file)) { return true; @@ -457,16 +469,18 @@ public function unlink($file, $is_delete = false, $is_block = false) $ok = true; } - clearstatcache(); - // cleanup if ftruncate() failed if (false === $ok) { + clearstatcache(true, $file); if (@is_file($file) && !@unlink($file)) { // try cleanup at shutdown $this->shutdown_cleanup($file); } } + // reset all + clearstatcache(true); + // always true return true; } @@ -492,7 +506,6 @@ public function put($file, $data, $flag = 'cb', $is_block = false) } } @fclose($handle); - clearstatcache(); if (false === $ok) { $this->unlink($file, true); @@ -500,6 +513,8 @@ public function put($file, $data, $flag = 'cb', $is_block = false) return -1; } + clearstatcache(true); + $this->opcache_flush($file); $this->chmod($file); @@ -520,10 +535,13 @@ public function dump($file, $data, $is_validate = false) // truncate reason $this->opcache_flush($file); + // make query-monitor happy. + $nwdcx_suppresserrors = nwdcx_suppresserrors(true); + $ok = $this->put($tmpfile, $data, 'cb', true); if (true === $ok) { try { - clearstatcache(); + clearstatcache(true, $tmpfile); if (@is_file($tmpfile) && @rename($tmpfile, $file)) { if (isset($nwdcx_suppresserrors)) { nwdcx_suppresserrors($nwdcx_suppresserrors); @@ -549,10 +567,15 @@ public function dump($file, $data, $is_validate = false) } // cleanup if not bool true + clearstatcache(true, $tmpfile); if (@is_file($tmpfile)) { @unlink($tmpfile); } + nwdcx_suppresserrors($nwdcx_suppresserrors); + + clearstatcache(true); + // maybe -1, >= 1, false: return from put() return $ok; } @@ -777,7 +800,10 @@ public function opcache_filecache_reset() if (!$is_done && !empty($fcdata)) { $dir = $fcdata['file_cache']; $cnt = 0; - $max_execution_time = $this->get_max_execution_time(); + + $this->suspend_cache_write(true); + + $max_execution_time = $this->get_max_execution_time(180); $slowdown = 0; foreach ($this->opcache_filecache_scanfiles($dir) as $object) { try { @@ -804,8 +830,12 @@ public function opcache_filecache_reset() } } + clearstatcache(true); + $is_done = true; + $this->suspend_cache_write(false); + return $cnt; } @@ -979,12 +1009,15 @@ public function cachedir_flush($dir, $cleanup = false, &$is_timeout = false) return true; } - wp_suspend_cache_addition(true); + $this->suspend_cache_write(true); + + $gcisrun_lock = $dir.'/.gc-is-run.txt'; - $max_execution_time = $this->get_max_execution_time(); + $max_execution_time = $this->get_max_execution_time(180); $flush_lock = DOCKET_CACHE_CONTENT_PATH.'/.object-cache-flush.txt'; - if ($this->put($flush_lock, time())) { - $this->touch($flush_lock, time() + $max_execution_time); + $flush_lock_expiry = time() + $max_execution_time + 10; + if ($this->put($flush_lock, $flush_lock_expiry)) { + $this->touch($flush_lock, $flush_lock_expiry); } $slowdown = 0; @@ -1006,6 +1039,7 @@ public function cachedir_flush($dir, $cleanup = false, &$is_timeout = false) } ++$slowdown; + if ($max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $max_execution_time) { $is_timeout = true; break; @@ -1020,11 +1054,13 @@ public function cachedir_flush($dir, $cleanup = false, &$is_timeout = false) $this->unlink($dir.'/index.html', true); } + $this->unlink($gcisrun_lock, true); + if (@is_file($flush_lock)) { @unlink($flush_lock); } - wp_suspend_cache_addition(false); + $this->suspend_cache_write(false); $is_done = true; return $cnt; @@ -1042,14 +1078,16 @@ public function cache_size($dir) $filestotal = 0; clearstatcache(); - if (!$is_done && $this->is_docketcachedir($dir) && !@is_file(DOCKET_CACHE_CONTENT_PATH.'/.object-cache-flush.txt')) { + $gcisrun_lock = $dir.'/.gc-is-run.txt'; + + if (!$is_done && $this->is_docketcachedir($dir) && !@is_file(DOCKET_CACHE_CONTENT_PATH.'/.object-cache-flush.txt') && !@is_file($gcisrun_lock)) { // hardmax $maxfile = 999000; // 1000000 - 1000; $cnt = 0; $slowdown = 0; ignore_user_abort(true); - $max_execution_time = $this->get_max_execution_time(); + $max_execution_time = $this->get_max_execution_time(180); $pattern = '@^([a-z0-9]{12})\-([a-z0-9]{12})\.php$@'; foreach ($this->scanfiles($dir, null, $pattern) as $object) { @@ -1094,12 +1132,16 @@ public function cache_size($dir) if ($max_execution_time > 0 && \defined('WP_START_TIMESTAMP') && (microtime(true) - WP_START_TIMESTAMP) > $max_execution_time) { break; } + + if (@is_file($gcisrun_lock)) { + break; + } } } $is_done = true; - wp_cache_set('numfile', $filestotal, 'docketcache-gc', 60); + wp_cache_set('count_file', $filestotal, 'docketcache-gc', 86400); return [ 'timestamp' => time(), @@ -1192,6 +1234,20 @@ function () { ); } + /** + * suspend_cache_write. + */ + public function suspend_cache_write($suspend = null) + { + static $_suspend = false; + + if (\is_bool($suspend)) { + $_suspend = $suspend; + } + + return $_suspend; + } + /** * cache_get. */ @@ -1260,6 +1316,16 @@ public function code_stub($data = '') { $is_debug = \defined('WP_DEBUG') && WP_DEBUG; $is_data = !empty($data); + + $class_map = [ + 'Requests_Utility_CaseInsensitiveDictionary' => 'Requests/Utility/CaseInsensitiveDictionary.php', + 'Requests_Response' => ' Requests/Response.php', + 'Requests_Response_Headers' => 'Requests/Response/Headers.php', + 'Requests_Cookie_Jar' => 'Requests/Cookie/Jar.php', + 'WP_HTTP_Requests_Response' => 'class-wp-http-requests-response.php', + 'WP_Post' => 'class-wp-post.php', + ]; + $ucode = ''; if ($is_data && false !== strpos($data, 'Registry::p(')) { if (@preg_match_all('@Registry::p\(\'([a-zA-Z_]+)\'\)@', $data, $mm)) { @@ -1267,13 +1333,26 @@ public function code_stub($data = '') $cls = $mm[1]; foreach ($cls as $clsname) { if ('stdClass' !== $clsname) { - if ($is_debug) { - $reflector = new \ReflectionClass($clsname); - $clsfname = $reflector->getFileName(); - if (false !== $clsfname) { - $ucode .= '/* f: '.str_replace(ABSPATH, '', $clsfname).' */'.\PHP_EOL; + if (\defined('DOCKET_CACHE_USE_CLASSMAP') && DOCKET_CACHE_USE_CLASSMAP) { + $clspath = ''; + if (\defined('DOCKET_CACHE_USE_REFLECTIONCLASS') && DOCKET_CACHE_USE_REFLECTIONCLASS) { + $reflector = new \ReflectionClass($clsname); + $clsfname = $reflector->getFileName(); + if (false !== $clsfname) { + $clspath = str_replace(ABSPATH, '', $clsfname); + } + } + + if (empty($clspath) && !empty($class_map[$clsname])) { + $clspath = WPINC.'/'.$class_map[$clsname]; + } + + if (!empty($clspath)) { + $clsfname = $clspath; + $ucode .= "if ( !@class_exists('".$clsname."', false) && @file_exists(ABSPATH.'".$clsfname."') ) { @include_once(ABSPATH.'".$clsfname."'); }".\PHP_EOL; } } + $ucode .= "if ( !@class_exists('".$clsname."', false) ) { return false; }".\PHP_EOL; } } @@ -1284,8 +1363,10 @@ public function code_stub($data = '') } $code = 'sanitize_maxfile($maxfile); + return $this->sanitize_maxfile($maxfile, $default); } /** @@ -1460,6 +1542,7 @@ public function valid_timestamp($timestamp) return $timestamp > 0; } + // put here because use in Becache. public function keys_alloptions() { // reference: wp-admin/includes/schema.php diff --git a/includes/src/MoCache.php b/includes/src/MoCache.php index 0b9edb6..b07bfbe 100644 --- a/includes/src/MoCache.php +++ b/includes/src/MoCache.php @@ -12,6 +12,7 @@ \defined('ABSPATH') || exit; +#[AllowDynamicProperties] final class MoCache { private $domain = null; diff --git a/includes/src/Plugin.php b/includes/src/Plugin.php index 6a8a8b6..49efeb2 100644 --- a/includes/src/Plugin.php +++ b/includes/src/Plugin.php @@ -546,7 +546,7 @@ public function get_opcache_status($is_raw = false) */ public function get_cache_maxfile() { - $maxfile = $this->cf()->dcvalue('MAXFILE'); + $maxfile = $this->cf()->dcvalue('MAXFILE', true); return $this->sanitize_maxfile($maxfile); } @@ -580,7 +580,7 @@ public function get_precache_maxfile() return 0; } - $maxfile = $this->cf()->dcvalue('PRECACHE_MAXFILE'); + $maxfile = $this->cf()->dcvalue('PRECACHE_MAXFILE', true); return $this->sanitize_precache_maxfile($maxfile); } @@ -680,7 +680,11 @@ public function flush_cache($cleanup = false, &$is_timeout = false) $this->co()->clear_part('cachestats'); $this->cx()->delay(); - delete_expired_transients(true); + if (\function_exists('nwdcx_cleanuptransient')) { + nwdcx_cleanuptransient(); + } else { + delete_expired_transients(true); + } $cnt = $this->cachedir_flush($this->cache_path, $cleanup, $is_timeout); if (false === $cnt) { @@ -689,6 +693,8 @@ public function flush_cache($cleanup = false, &$is_timeout = false) return $cnt; } + $this->co()->clear_lock(); + return $cnt; } @@ -971,6 +977,8 @@ private function deactivate_cleanup($is_uninstall = false) if ($this->cf()->is_dctrue('OPCSHUTDOWN', true)) { $this->opcache_cleanup(); } + + $this->co()->clear_lock(); } /** @@ -1073,7 +1081,7 @@ private function plugin_upgrade() add_action( 'shutdown', function () { - $this->close_buffer(); + // $this->close_buffer(); if ($this->cf()->is_dcfalse('OBJECTCACHEOFF', true)) { $this->cx()->install(true); @@ -1089,6 +1097,18 @@ function () { ); } + private function toggle_auto_update($toggle = false) + { + $auto_updates = (array) get_site_option('auto_update_plugins', []); + if (true === $toggle) { + $auto_updates[] = $this->hook; + + return update_site_option('auto_update_plugins', array_unique($auto_updates)); + } + + return update_site_option('auto_update_plugins', array_diff($auto_updates, [$this->hook])); + } + /** * register_plugin_hooks. */ @@ -1184,15 +1204,16 @@ function () { @header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0'); @header('Content-Type: text/plain; charset=UTF-8'); if (@is_file($file) && @is_readable($file)) { - @readfile($file); - $this->close_exit(); + if (@readfile($file) > 0) { + $this->close_exit(); + } } - $this->close_exit(__('No data available', 'docket-cache')); + $this->close_exit(__('The log is empty. No data is available.', 'docket-cache')); } } - if (\defined('WP_DEBUG') && WP_DEBUG && \defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { + if ($this->cf()->is_true('WP_DEBUG') && $this->cf()->is_true('WP_DEBUG_LOG')) { $req = $_SERVER['REQUEST_URI']; if ((false !== strpos($req, '?page=docket-cache&idx=config&wplog=0') || false !== strpos($req, '?page=docket-cache-config&idx=config&wplog=0')) && preg_match('@config\&wplog=\d+(\&dd=\d+)?$@', $req)) { @@ -1209,11 +1230,12 @@ function () { $this->close_exit($log); } - @readfile($file); - $this->close_exit(); + if (@readfile($file) > 0) { + $this->close_exit(); + } } - $this->close_exit(__('No data available', 'docket-cache')); + $this->close_exit(__('The log is empty. No data is available.', 'docket-cache')); } } } @@ -1235,8 +1257,8 @@ function () { if (empty($ok)) { $wpdb->query('SET SESSION SQL_BIG_SELECTS=1'); } else { - // already big select, lock 24h - $locktime = time() + 86400; + // already big select, lock 28d + $locktime = time() + 2419200; $this->co()->setlock('sqlbigselect', $locktime); } @@ -1246,11 +1268,67 @@ function () { \PHP_INT_MIN ); + add_action( + 'plugins_loaded', + function () { + $dc_option = $this->co()->get('DOCKET_CACHE_AUTOUPDATE'); + if (!empty($dc_option)) { + $cache_hash_group = substr(md5('options'), 0, 12); + $cache_hash_key = substr(md5('auto_update_plugins'), 0, 12); + if (is_multisite()) { + $cache_hash_group = substr(md5('site-options'), 0, 12); + $cache_hash_key = substr(md5(get_current_network_id().':auto_update_plugins'), 0, 12); + } + + $file_cache = $this->cache_path.$cache_hash_group.'-'.$cache_hash_key.'.php'; + if (is_file($file_cache)) { + @unlink($file_cache); + } + + clearstatcache(); + + if ('enable' === $dc_option) { + $this->co()->save('autoupdate_toggle', 'enable'); + } elseif ('disable' === $dc_option) { + $this->co()->save('autoupdate_toggle', 'disable'); + } + + $this->co()->save('AUTOUPDATE', false); + } + }, + \PHP_INT_MAX + ); + + add_action( + 'update_site_option', + function ($option, $auto_updates, $old_auto_updates, $network_id) { + if ('auto_update_plugins' === $option) { + if (\in_array($this->hook, (array) $auto_updates, true) && !\in_array($this->hook, (array) $old_auto_updates, true)) { + $this->co()->save('autoupdate_toggle', 'enable', false); + + return; + } + + if (\in_array($this->hook, (array) $old_auto_updates, true) && !\in_array($this->hook, (array) $auto_updates, true)) { + $this->co()->save('autoupdate_toggle', 'disable', false); + + return; + } + + return; + } + }, + \PHP_INT_MAX, + 4 + ); + add_filter( 'auto_update_plugin', function ($update, $item) { if ('docket-cache' === $item->slug) { - return $this->cf()->is_dctrue('AUTOUPDATE'); + if (\defined('DOCKET_CACHE_AUTOUPDATE') && \is_bool(DOCKET_CACHE_AUTOUPDATE)) { + return DOCKET_CACHE_AUTOUPDATE; + } } return $update; @@ -1624,14 +1702,10 @@ function ($hook) { function () { add_action( 'shutdown', - function () { - $this->close_buffer(); - $user = wp_get_current_user(); - if (\is_object($user) && isset($user->ID)) { - wp_cache_delete($user->ID, 'user_meta'); - $this->delete_cron_siteid($user->ID); - $this->delete_current_select_siteid($user->ID); - } + function ($user_id) { + wp_cache_delete($user_id, 'user_meta'); + $this->delete_cron_siteid($user_id); + $this->delete_current_select_siteid($user_id); }, \PHP_INT_MAX ); @@ -1765,7 +1839,7 @@ function ($plugin_meta, $plugin_file) { 2 ); - add_filter( + /*add_filter( 'plugin_auto_update_setting_html', function ($html, $plugin_file, $plugin_data) { if ($plugin_file === $this->hook) { @@ -1776,7 +1850,8 @@ function ($html, $plugin_file, $plugin_data) { }, 10, 3 - ); + );*/ + // reference: Canopt::save() add_action( 'docketcache/action/saveoption', @@ -1794,10 +1869,10 @@ function ($name, $value, $status = true) { add_action( 'shutdown', function () { - $this->close_buffer(); + // $this->close_buffer(); wp_cache_delete('alloptions', 'options'); - if (\function_exists('wp_cache_flush_group')) { + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { wp_cache_flush_group('options'); wp_cache_flush_group('docketcache-precache'); } @@ -1815,7 +1890,7 @@ function () { 'shutdown', function () use ($action) { if (!$action) { - $this->close_buffer(); + // $this->close_buffer(); apply_filters('docketcache/filter/active/cronbot', $action); } @@ -1828,10 +1903,20 @@ function () use ($action) { $error_log = \ini_get('error_log'); if ('off' === $value && @is_file($error_log) && @is_writable($error_log)) { @unlink($error_log); + clearstatcache(); } break; case 'menucache': - wp_cache_flush_group('docketcache-menu'); + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { + wp_cache_flush_group('docketcache-menu'); + } + break; + case 'autoupdate_toggle': + if ('enable' === $value) { + $this->toggle_auto_update(true); + } else { + $this->toggle_auto_update(false); + } break; } @@ -1853,8 +1938,8 @@ function () { // lock opcache reset $this->co()->setlock('preload_lock_opcache_reset', time() + 20); - // warmup: see after_delay - if ($this->cf()->is_dcfalse('PRELOAD')) { + // warmup: see Dropino::after_delay + if ($this->cf()->is_dcfalse('PRELOAD', true)) { add_action( 'shutdown', function () { @@ -1960,6 +2045,11 @@ function () { add_action( 'docketcache/action/countcachesize', function () { + // gc is running + if ($this->co()->locked('garbage_collector')) { + return; + } + if ($this->co()->lockproc('doing_countcachesize', time() + $this->get_max_execution_time())) { return; } @@ -2100,7 +2190,7 @@ function () use ($tweaks) { if ($this->co()->lockproc('post_missed_schedule', time() + 180)) { return false; } - $this->close_buffer(); + // $this->close_buffer(); $tweaks->post_missed_schedule(); $this->co()->lockreset('post_missed_schedule'); }, @@ -2183,25 +2273,13 @@ private function register_cli() \WP_CLI::add_command('cache run:gc', [$cli, 'run_gc']); \WP_CLI::add_command('cache run:cron', [$cli, 'run_cron']); \WP_CLI::add_command('cache run:stats', [$cli, 'run_stats']); + \WP_CLI::add_command('cache run:optimizedb', [$cli, 'run_optimizedb']); \WP_CLI::add_command('cache reset:lock', [$cli, 'reset_lock']); \WP_CLI::add_command('cache reset:cron', [$cli, 'reset_cron']); - - if ($this->cf()->is_dctrue('ADVCPOST')) { - \WP_CLI::add_command('cache flush:advcpost', [$cli, 'flush_advcpost']); - } - - if ($this->cf()->is_dctrue('PRECACHE')) { - \WP_CLI::add_command('cache flush:precache', [$cli, 'flush_precache']); - } - - if ($this->cf()->is_dctrue('MENUCACHE')) { - \WP_CLI::add_command('cache flush:menucache', [$cli, 'flush_menucache']); - } - - if ($this->cf()->is_dctrue('MOCACHE')) { - \WP_CLI::add_command('cache flush:mocache', [$cli, 'flush_mocache']); - } - + \WP_CLI::add_command('cache flush:advcpost', [$cli, 'flush_advcpost']); + \WP_CLI::add_command('cache flush:precache', [$cli, 'flush_precache']); + \WP_CLI::add_command('cache flush:menucache', [$cli, 'flush_menucache']); + \WP_CLI::add_command('cache flush:mocache', [$cli, 'flush_mocache']); \WP_CLI::add_command('cache flush:transient', [$cli, 'flush_transient']); \WP_CLI::add_command('cache flush', [$cli, 'flush_cache']); \WP_CLI::add_command('cache runtime:install', [$cli, 'runtime_install']); diff --git a/includes/src/PostCache.php b/includes/src/PostCache.php index 0e8a468..ee1be9e 100644 --- a/includes/src/PostCache.php +++ b/includes/src/PostCache.php @@ -12,6 +12,7 @@ \defined('ABSPATH') || exit; +#[AllowDynamicProperties] final class PostCache { public $prefix = 'docketcache-post'; @@ -24,15 +25,32 @@ final class PostCache public $cached_posts = []; public $found_posts = false; public $cache_func = 'wp_cache_add'; - public $cache_func_expiry = 0; // let WP_Object_Cache::maybe_expire handles it - public $stalecache_list = []; - public $allow_posttype = ['post', 'page', 'attachment']; - public $blacklist_posttype = ['scheduled-action']; + public $cache_func_expiry = 86400; // 1d + public $allow_posttype = []; + public $blacklist_posttype = []; public $allow_posttype_all = false; public function __construct() { $this->group_prefix = $this->prefix.'-'; + $this->allow_posttype = [ + 'post', + 'page', + 'attachment', + 'revision', + 'nav_menu_item', + 'custom_css', + 'customize_changeset', + 'oembed_cache', + 'user_request', + 'wp_block', + 'wp_template', + 'wp_template_part', + 'wp_global_styles', + 'wp_navigation', + ]; + + $this->blacklist_posttype = ['scheduled-action']; } public function register() @@ -103,14 +121,14 @@ function ($counts = false, $post_id = 0) { $stats = get_comment_count(0); $stats['moderated'] = $stats['awaiting_moderation']; unset($stats['awaiting_moderation']); - $stats_object = (object) $stats; + $stats_object = $stats; wp_cache_set($cache_key, $stats_object, $this->prefix, 1800); // 1800 = 30min } - return $stats_object; + return (object) $stats_object; }, - 10, + \PHP_INT_MAX, 2 ); @@ -193,10 +211,6 @@ function ($post_id) { } } ); - - if (nwdcx_construe('FLUSH_STALECACHE')) { - add_action('shutdown', [$this, 'stalecache_set'], \PHP_INT_MAX); - } } public function setup_for_blog($new_blog_id = false, $previous_blog_id = false) @@ -224,11 +238,6 @@ public function invalidate_cache() return; } - // 03052022: flush - if (nwdcx_construe('FLUSH_STALECACHE')) { - $this->stalecache_list[md5($this->cache_group)] = $this->cache_group; - } - $this->cache_incr = wp_cache_incr('cache_incr', 1, $this->prefix); if (10 < \strlen($this->cache_incr)) { @@ -262,11 +271,12 @@ public function posts_request($sql, $query) return $sql; } - if (!$this->allow_post_type($query->get('post_type'))) { + $post_type = $query->get('post_type'); + if (!$this->allow_post_type($post_type)) { return $sql; } - $this->cache_key = 'query-'.md5($sql); + $this->cache_key = 'query-'.$post_type.'-'.md5($sql); $this->all_post_ids = wp_cache_get($this->cache_key, $this->cache_group); if ('NA' !== $this->found_posts) { @@ -393,14 +403,4 @@ public function found_posts($found_posts, $query) return $found_posts; } - - // send cache list to WP_Object_Cache and flush it at wp_cache_close right after "shutdown" hook. - public function stalecache_set() - { - if (!empty($this->stalecache_list) && \function_exists('wp_cache_add_stalecache')) { - $key_last = array_key_last($this->stalecache_list); - $list = [$key_last => $this->stalecache_list[$key_last]]; - wp_cache_add_stalecache($list); - } - } } diff --git a/includes/src/ReqAction.php b/includes/src/ReqAction.php index 11cdf19..a957052 100644 --- a/includes/src/ReqAction.php +++ b/includes/src/ReqAction.php @@ -173,7 +173,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value case 'docket-flush-menucache': $result = 0; $ok = true; - if (\function_exists('wp_cache_flush_group')) { + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { $result = wp_cache_flush_group('docketcache-menu'); $this->pt->co()->lookup_set('menucacheflushed', $result); $response = 'docket-menucache-flushed'; @@ -187,7 +187,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value case 'docket-flush-mocache': $result = 0; $ok = true; - if (\function_exists('wp_cache_flush_group')) { + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { $result = wp_cache_flush_group('docketcache-mo'); $this->pt->co()->lookup_set('mocacheflushed', $result); $response = 'docket-mocache-flushed'; @@ -201,7 +201,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value case 'docket-flush-ocprecache': $result = 0; $ok = true; - if (\function_exists('wp_cache_flush_group')) { + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { $result = wp_cache_flush_group('docketcache-precache'); $this->pt->co()->lookup_set('ocprecacheflushed', $result); $response = 'docket-ocprecache-flushed'; @@ -215,7 +215,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value case 'docket-flush-advcpost': $result = 0; $ok = true; - if (\function_exists('wp_cache_flush_group_match')) { + if (\function_exists('wp_cache_flush_group_match') && method_exists('WP_Object_Cache', 'dc_remove_group')) { $result = wp_cache_flush_group_match('docketcache-post'); $this->pt->co()->lookup_set('advcpostflushed', $result); $response = 'docket-advcpost-flushed'; @@ -229,7 +229,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value case 'docket-flush-transient': $result = 0; $ok = true; - if (\function_exists('wp_cache_flush_group')) { + if (\function_exists('wp_cache_flush_group') && method_exists('WP_Object_Cache', 'dc_remove_group')) { $result = wp_cache_flush_group(['transient', 'site-transient']); $this->pt->co()->lookup_set('transientflushed', $result); $response = 'docket-transient-flushed'; @@ -313,8 +313,13 @@ private function run_action($action, $param, &$option_name = '', &$option_value $response = 'docket-gcrun-failed'; $result = apply_filters('docketcache/filter/garbagecollector', true); if (!empty($result) && \is_object($result)) { - $this->pt->co()->lookup_set('gcrun', (array) $result); - $response = 'docket-gcrun'; + if ($result->is_locked) { + $response = 'docket-gcrun-warn'; + } else { + $this->pt->co()->lookup_set('gcrun', (array) $result); + $response = 'docket-gcrun'; + } + $ok = true; } @@ -399,26 +404,38 @@ private function run_action($action, $param, &$option_name = '', &$option_value } } - $ok = $this->pt->co()->save($nx, $nv); - if (isset($nvo)) { - $nv = $nvo; - } + if (WpConfig::has($nx)) { + $response = 'docket-option-wpf-warn'; + $this->pt->co()->save($nx, 'default'); + } else { + $ok = $this->pt->co()->save($nx, $nv); + if (isset($nvo)) { + $nv = $nvo; + } - $response = $ok ? 'docket-option-save' : 'docket-option-failed'; + $response = $ok ? 'docket-option-save' : 'docket-option-failed'; + } } + $option_value = $nv; } else { - $okmsg = 'default' === $nk ? 'docket-option-default' : 'docket-option-'.$nk; - $ok = $this->pt->co()->save($nx, $nk); - $response = $ok ? $okmsg : 'docket-option-failed'; + if (WpConfig::has($nx)) { + $response = 'docket-option-wpf-warn'; + $this->pt->co()->save($nx, 'default'); + } else { + $okmsg = 'default' === $nk ? 'docket-option-default' : 'docket-option-'.$nk; + $ok = $this->pt->co()->save($nx, $nk); + $response = $ok ? $okmsg : 'docket-option-failed'; + } } if ($ok) { - if ('wooaddtochartcrawling' === $nx && 'enable' == $nk) { + if ('wooaddtochartcrawling' === $nx && 'enable' == $nk && 'docket-option-wpf-warn' !== $response) { $robotsfile = wp_normalize_path(ABSPATH).'robots.txt'; if (@is_file($robotsfile)) { $response = 'docket-option-rbt-warn'; } + clearstatcache(); } } @@ -430,6 +447,7 @@ private function run_action($action, $param, &$option_name = '', &$option_value 'value' => $nv, 'name' => $nk, 'action' => $action, + 'response' => $response, ] ); } @@ -776,6 +794,11 @@ private function screen_notice() break; case 'docket-gcrun-failed': $this->pt->notice = esc_html__('Failed to run the garbage collector.', 'docket-cache'); + $this->pt->co()->lookup_delete('gcrun'); + break; + case 'docket-gcrun-warn': + $this->pt->notice = esc_html__('Process locked. The garbage collector is in process. Try again in a few seconds.', 'docket-cache'); + $this->pt->co()->lookup_delete('gcrun'); break; case 'docket-runtimeok': $this->pt->notice = esc_html__('Updating wp-config.php file successful.', 'docket-cache'); @@ -834,7 +857,7 @@ private function screen_notice() unset($total, $clmsg); break; case 'docket-menucache-flushed-failed': - $this->pt->notice = esc_html__('Menu cache could not be flushed.', 'docket-cache'); + $this->pt->notice = esc_html__('Menu cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache'); break; case 'docket-mocache-flushed': $this->pt->notice = esc_html__('Translation cache was flushed.', 'docket-cache'); @@ -852,7 +875,7 @@ private function screen_notice() unset($total, $clmsg); break; case 'docket-mocache-flushed-failed': - $this->pt->notice = esc_html__('Translation cache could not be flushed.', 'docket-cache'); + $this->pt->notice = esc_html__('Translation cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache'); break; case 'docket-ocprecache-flushed': $this->pt->notice = esc_html__('Object Precache was flushed.', 'docket-cache'); @@ -870,7 +893,7 @@ private function screen_notice() unset($total, $clmsg); break; case 'docket-ocprecache-flushed-failed': - $this->pt->notice = esc_html__('Object Precache could not be flushed.', 'docket-cache'); + $this->pt->notice = esc_html__('Object Precache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache'); break; case 'docket-advcpost-flushed': $this->pt->notice = esc_html__('Advanced Post Cache was flushed.', 'docket-cache'); @@ -888,7 +911,7 @@ private function screen_notice() unset($total, $clmsg); break; case 'docket-advcpost-flushed-failed': - $this->pt->notice = esc_html__('Advanced Post Cache could not be flushed.', 'docket-cache'); + $this->pt->notice = esc_html__('Advanced Post Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache'); break; case 'docket-transient-flushed': $this->pt->notice = esc_html__('Transient cache was flushed.', 'docket-cache'); @@ -906,7 +929,7 @@ private function screen_notice() unset($total, $clmsg); break; case 'docket-transient-flushed-failed': - $this->pt->notice = esc_html__('Transient cache could not be flushed.', 'docket-cache'); + $this->pt->notice = esc_html__('Transient cache could not be flushed. This action require Docket Cache object-cache.php Drop-in.', 'docket-cache'); break; } } diff --git a/includes/src/Resc.php b/includes/src/Resc.php index 1facf07..1fa2902 100644 --- a/includes/src/Resc.php +++ b/includes/src/Resc.php @@ -203,7 +203,7 @@ public static function runtimenotice($action, $is_adr = false) $message .= '

'; if (WpConfig::is_writable() && !$is_bedrock) { - $message .= '
'.$text4.'
'.esc_html__('Install', 'docket-cache').''; + $message .= '
'.$text4.'
'.esc_html__('Install', 'docket-cache').''; if ($is_remove && $is_adr) { $message .= ''.esc_html__('Un-Install', 'docket-cache').''; } diff --git a/includes/src/Tweaks.php b/includes/src/Tweaks.php index 37e99e7..49039e9 100644 --- a/includes/src/Tweaks.php +++ b/includes/src/Tweaks.php @@ -250,7 +250,9 @@ private function has_woocommerce() public function woocommerce_misc() { // wc: action_scheduler_migration_dependencies_met - add_filter('action_scheduler_migration_dependencies_met', '__return_false', \PHP_INT_MAX); + if ('complete' === get_option('action_scheduler_migration_status')) { + add_filter('action_scheduler_migration_dependencies_met', '__return_false', \PHP_INT_MAX); + } // wc: disable background image regeneration add_filter('woocommerce_background_image_regeneration', '__return_false', \PHP_INT_MAX); @@ -349,6 +351,13 @@ function () { }, \PHP_INT_MAX ); + + add_action('plugins_loaded', function () { + if (!$this->has_woocommerce()) { + return; + } + remove_action('widgets_init', 'wc_register_widgets'); + }, \PHP_INT_MAX); } public function woocommerce_cart_fragments_remove() @@ -404,7 +413,7 @@ public function woocommerce_crawling_addtochart_links() $append = ''; if (!@preg_match('@^Disallow:\s+/\*add\-to\-cart=\*@is', $output)) { - $append .= "Disallow: /*add-to-cart=*\n"; + $append .= 'Disallow: /*'."add-to-cart=*\n"; } if (!@preg_match('@^Disallow:\s+/cart/@is', $output)) { @@ -769,6 +778,39 @@ public function wpservehappy() }, \PHP_INT_MAX); } + // wp < 5.8 + public function http_headers_expect() + { + // https://github.com/WordPress/Requests/pull/454 + if (version_compare($GLOBALS['wp_version'], '5.8', '>')) { + return false; + } + + add_filter('http_request_args', function ($args) { + if (!isset($args['headers']['expect'])) { + $args['headers']['expect'] = ''; + + if (\is_array($args['body'])) { + $bytesize = 0; + $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($args['body'])); + + foreach ($iterator as $datum) { + $bytesize += \strlen((string) $datum); + + if ($bytesize >= 1048576) { + $args['headers']['expect'] = '100-Continue'; + break; + } + } + } elseif (!empty($args['body']) && \strlen((string) $args['body']) > 1048576) { + $args['headers']['expect'] = '100-Continue'; + } + } + + return $args; + }, \PHP_INT_MAX); + } + public function limit_http_request() { add_action( @@ -781,6 +823,10 @@ function ($preempt, $parsed_args, $url) { return false; } + if (/* 'GET' !== $parsed_args['method'] || */ $this->http_filter_bypass_url($url)) { + return false; + } + if (empty($GLOBALS['pagenow'])) { return false; } @@ -801,54 +847,38 @@ function ($preempt, $parsed_args, $url) { return false; } - $hostme = parse_url(home_url(), \PHP_URL_HOST); - $hostname = parse_url($url, \PHP_URL_HOST); - - if ('127.0.0.1' === $hostname || 'localhost' === $hostname || $hostme === $hostname) { + /*$site_host = parse_url(site_url(), \PHP_URL_HOST); + if ('.local' === substr($site_host, -\strlen('.local')) || '.test' === substr($site_host, -\strlen('.test'))) { return false; - } - - if ('.local' === substr($hostme, -\strlen('.local')) || '.test' === substr($hostme, -\strlen('.test'))) { - return false; - } - - if ('wordpress.org' === $hostname || 'api.wordpress.org' === $hostname || 'docketcache.com' === $hostname) { - return false; - } - - if ('.wordpress.org' === substr($hostname, -\strlen('.wordpress.org'))) { - return false; - } + }*/ - if ('.docketcache.com' === substr($hostname, -\strlen('.docketcache.com'))) { - return false; - } + $url_host = parse_url($url, \PHP_URL_HOST); - $ok = true; + $is_block = true; $wkey = nwdcx_constfx('LIMITHTTPREQUEST_WHITELIST'); if (\defined($wkey)) { $whitelist = \constant($wkey); if (!empty($whitelist) && \is_array($whitelist)) { - while ($hosta = @array_shift($whitelist)) { - $hostb = nwdcx_noscheme($hosta); - if ($hostname === $hostb) { - $ok = false; + foreach ($whitelist as $host) { + $host = nwdcx_noscheme($host); + if ($url_host === $host) { + $is_block = false; break; } - if ('.' === $hostb[0] && $hostb === substr($hostname, -\strlen($hostb))) { - $ok = false; + if ('.' === $host[0] && $host === substr($url_host, -\strlen($host))) { + $is_block = false; break; } } } } - /*if ( $ok ) { - error_log('docket-cache: Tweaks::limit_http_request(): Drop -> '.$hostname); - }*/ + if ($is_block) { + nwdcx_debuglog('Tweaks::limit_http_request(): Blocked -> '.$url_host); + } - return $ok; + return $is_block; }, \PHP_INT_MIN, 3 @@ -858,57 +888,22 @@ function ($preempt, $parsed_args, $url) { ); } - // wp < 5.8 - public function http_headers_expect() - { - // https://github.com/WordPress/Requests/pull/454 - if (version_compare($GLOBALS['wp_version'], '5.8', '<')) { - return false; - } - - add_filter('http_request_args', function ($args) { - if (!isset($args['headers']['expect'])) { - $args['headers']['expect'] = ''; - - if (\is_array($args['body'])) { - $bytesize = 0; - $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($args['body'])); - - foreach ($iterator as $datum) { - $bytesize += \strlen((string) $datum); - - if ($bytesize >= 1048576) { - $args['headers']['expect'] = '100-Continue'; - break; - } - } - } elseif (!empty($args['body']) && \strlen((string) $args['body']) > 1048576) { - $args['headers']['expect'] = '100-Continue'; - } - } - - return $args; - }, \PHP_INT_MAX); - } - public function cache_http_response() { add_action('init', function () { - add_filter('http_response', function ($response, $args, $url) { - if (200 !== $response['response']['code']) { + add_filter('http_response', function ($response, $parsed_args, $url) { + if (/* 'GET' !== $parsed_args['method'] || */ $this->http_filter_bypass_url($url)) { return $response; } - $site_host = wp_parse_url(site_url(), \PHP_URL_HOST); - $hostname = wp_parse_url($url, \PHP_URL_HOST); - if ('wordpress.org' === $hostname || '.wordpress.org' === substr($hostname, -\strlen('.wordpress.org')) - || 'docketcache.com' === $hostname || '.docketcache.com' === substr($hostname, -\strlen('.docketcache.com')) - || false !== strpos($hostname, $site_host)) { + $cache_key = 'docketcache-httpresponse_'.md5($url); + + if (200 !== $response['response']['code']) { + delete_transient($cache_key); + return $response; } - $cache_key = 'docketcache-httpresponse_'.md5($url); - $cache_ttl = (int) nwdcx_constval('CACHEHTTPRESPONSE_TTL'); if (empty($cache_ttl)) { $cache_ttl = 300; @@ -941,9 +936,15 @@ public function cache_http_response() }, \PHP_INT_MIN, 3); add_filter('pre_http_request', function ($preempt, $parsed_args, $url) { + if (/* 'GET' !== $parsed_args['method'] || */ $this->http_filter_bypass_url($url)) { + return $preempt; + } + $cache_key = 'docketcache-httpresponse_'.md5($url); $data = get_transient($cache_key); if (!empty($data) && \is_array($data)) { + nwdcx_debuglog('Tweaks::cache_http_response(): Cached -> '.$url); + return $data; } @@ -951,4 +952,34 @@ public function cache_http_response() }, \PHP_INT_MIN, 3); }, \PHP_INT_MAX); } + + private function http_filter_bypass_url($url) + { + $hosts = [ + 'wordpress.org', + 'docketcache.com', + 'paypal.com', + 'braintree-api.com', + 'stripe.com', + 'cloudflare.com', + 'woocommerce.com', + ]; + + $hosts = apply_filters('docketcache/filter/cache_http_response_bypass_url', $hosts); + + $site_host = wp_parse_url(site_url(), \PHP_URL_HOST); + $url_host = wp_parse_url($url, \PHP_URL_HOST); + + if ('127.0.0.1' === $url_host || 'localhost' === $url_host || $site_host === $url_host) { + return true; + } + + foreach ($hosts as $host) { + if ($host === $url_host || '.'.$host === substr($url_host, -\strlen('.'.$host))) { + return true; + } + } + + return false; + } } diff --git a/includes/src/View.php b/includes/src/View.php index efab105..98d2bf6 100644 --- a/includes/src/View.php +++ b/includes/src/View.php @@ -574,7 +574,7 @@ private function tooltip($id) 'cronbot' => esc_html__('The Cronbot is an external service that pings your website every hour to keep WordPress Cron running actively.', 'docket-cache'), 'log' => esc_html__('The cache log intends to provide information on how the cache works. For performance and security concerns, disable it if no longer needed.', 'docket-cache'), 'opcviewer' => esc_html__('OPcache Viewer allows you to view OPcache status and usage.', 'docket-cache'), - 'advcpost' => esc_html__('Cache WP Queries for a post which results in faster data retrieval and reduced database workload. By default only for Post Type post, page and attachment.', 'docket-cache'), + 'advcpost' => esc_html__('Cache WP Queries for a post which results in faster data retrieval and reduced database workload. By default only for built-in Post Types.', 'docket-cache'), 'advpost_posttype_all' => esc_html__('Allow Advanced Post Caching to cache any Post Type.', 'docket-cache'), 'menucache' => esc_html__('Cache the WordPress dynamic navigation menu.', 'docket-cache'), 'precache' => esc_html__('Increase cache performance by early loading cached objects based on the current URL.', 'docket-cache'), @@ -587,7 +587,7 @@ private function tooltip($id) 'misc_tweaks' => esc_html__('Miscellaneous WordPress Tweaks. Including performance, security dan user experience.', 'docket-cache'), 'wootweaks' => esc_html__('Miscellaneous WooCommerce Tweaks. Including performance, security dan user experience.', 'docket-cache'), 'wooadminoff' => esc_html__('WooCommerce Admin or Analytics page is a new JavaScript-driven interface for managing stores. Enable this option to turn off any feature-related.', 'docket-cache'), - 'woowidgetoff' => esc_html__('Deactivate WooCommerce Widget feature.', 'docket-cache'), + 'woowidgetoff' => esc_html__('Deactivate WooCommerce Classic Widget feature.', 'docket-cache'), 'woowpdashboardoff' => esc_html__('Remove the WooCommerce meta box in the WordPress Dashboard.', 'docket-cache'), 'woocartfragsoff' => esc_html__('Remove the WooCommerce Cart Fragments.', 'docket-cache'), 'wooextensionpageoff' => esc_html__('Remove WooCommerce Extensions page that includes My Subscriptions page.', 'docket-cache'), @@ -608,14 +608,17 @@ private function tooltip($id) 'stats' => esc_html__('Display Object Cache stats at Overview page.', 'docket-cache'), 'gcaction' => esc_html__('Enable the Garbage Collector action button on the Overview page.', 'docket-cache'), 'flushaction' => esc_html__('Enable the additional Flush Cache action button on the Configuration page.', 'docket-cache'), - 'autoupdate' => esc_html__('Enable automatic plugin updates for Docket Cache.', 'docket-cache'), + 'autoupdate_toggle' => esc_html__('Enable automatic plugin updates for Docket Cache.', 'docket-cache'), 'checkversion' => esc_html__('Allows Docket Cache to check any critical future version that requires removing cache files after doing the updates, purposely to avoid error-prone.', 'docket-cache'), 'flush_shutdown' => esc_html__('Flush Object Cache when deactivate / uninstall.', 'docket-cache'), 'opcshutdown' => esc_html__('Flush OPcache when deactivate / uninstall.', 'docket-cache'), 'maxsize_disk' => esc_html__('Maximum size of the cache storage on disk. The garbage collector will remove the cache file to free up storage space.', 'docket-cache'), 'maxfile' => esc_html__('The maximum cache file can be stored on a disk. The cache file will free up by the garbage collector when triggered by WP Cron.', 'docket-cache'), - 'chunkcachedir' => esc_html__('Enable this option to chunk cache files into a smaller directory to avoid an excessive number of cache files in a single directory. Only enable this option if you have difficulty when manually clearing the cache or experience a slowdown when the cache becomes too large.', 'docket-cache'), - 'flush_stalecache' => esc_html__('Enable this option to immediately remove the stale cache abandoned by WordPress, WooCommerce and others after doing cache invalidation. By default, it will be removed by GC within 4 days. This option may cause exessive usage of I/O and CPU. Only enable this option if you require to keep storage space in check.', 'docket-cache'), + 'maxfile_livecheck' => esc_html__('Enable this option to allow Docket Cache to monitor the cache file limit in real-time.', 'docket-cache'), + 'chunkcachedir' => esc_html__('Enable this option to chunk cache files into smaller directories to avoid an excessive number of cache files in one directory. Only enable it if you have difficulty clearing the cache manually or experience slowdowns when the cache becomes too large.', 'docket-cache'), + 'flush_stalecache' => esc_html__('Enable this option to allow GC immediately remove the stale cache abandoned by WordPress, WooCommerce and others after doing cache invalidation.', 'docket-cache'), + 'stalecache_ignore' => esc_html__('Enable this option to exclude stale cache created by WordPress, WooCommerce, and others from being stored on disk. Only enable it if you have an issue with inode limits.', 'docket-cache'), + 'emptycache_ignore' => esc_html__('Enable this option to exclude empty caches from being stored on disk. Only enable it if you have an issue with inode limits.', 'docket-cache'), 'limithttprequest' => esc_html__('Limit HTTP requests in WP Admin.', 'docket-cache'), 'httpheadersexpect' => esc_html__('By default, cURL sends the "Expect" header all the time which severely impacts performance. Enable this option, only send it if the body is larger than 1 MB.', 'docket-cache'), 'rtpostautosave' => esc_html__('WordPress by default automatically saves a draft every 1 minute when editing or create a new post. Changing this behaviour can reduce the usage of server resource.', 'docket-cache'), @@ -628,6 +631,8 @@ private function tooltip($id) 'rtwpdebugdisplay' => esc_html__('Enable this option to print debug info.', 'docket-cache'), 'rtwpdebuglog' => esc_html__('Enable this option to log debug info.', 'docket-cache'), 'rtwpcoreupdate' => esc_html__('This option will disable all core updates.', 'docket-cache'), + 'rtconcatenatescripts' => esc_html__('Enable this option to disable compression and concatenation of WP-Admin Scripts and CSS.', 'docket-cache'), + 'rtdisablewpcron' => esc_html__('Enable this option to disable the WP pseudo-cron. Only enable it if your site is already set up with real Cron.', 'docket-cache'), ]; $info = apply_filters('docketcache/filter/view/tooltips', $info); diff --git a/includes/src/WpConfig.php b/includes/src/WpConfig.php index 127ab8a..b51438f 100644 --- a/includes/src/WpConfig.php +++ b/includes/src/WpConfig.php @@ -32,16 +32,18 @@ private static function normalize_eol($content) private static function keys() { return [ - 'rtpostautosave' => 'AUTOSAVE_INTERVAL', - 'rtpostrevision' => 'WP_POST_REVISIONS', - 'rtpostemptytrash' => 'EMPTY_TRASH_DAYS', - 'rtpluginthemeeditor' => 'DISALLOW_FILE_EDIT', - 'rtpluginthemeinstall' => 'DISALLOW_FILE_MODS', - 'rtimageoverwrite' => 'IMAGE_EDIT_OVERWRITE', - 'rtwpdebug' => 'WP_DEBUG', - 'rtwpdebugdisplay' => 'WP_DEBUG_DISPLAY', - 'rtwpdebuglog' => 'WP_DEBUG_LOG', - 'rtwpcoreupdate' => 'WP_AUTO_UPDATE_CORE', + 'rtpostautosave' => 'AUTOSAVE_INTERVAL', + 'rtpostrevision' => 'WP_POST_REVISIONS', + 'rtpostemptytrash' => 'EMPTY_TRASH_DAYS', + 'rtpluginthemeeditor' => 'DISALLOW_FILE_EDIT', + 'rtpluginthemeinstall' => 'DISALLOW_FILE_MODS', + 'rtimageoverwrite' => 'IMAGE_EDIT_OVERWRITE', + 'rtwpdebug' => 'WP_DEBUG', + 'rtwpdebugdisplay' => 'WP_DEBUG_DISPLAY', + 'rtwpdebuglog' => 'WP_DEBUG_LOG', + 'rtwpcoreupdate' => 'WP_AUTO_UPDATE_CORE', + 'rtconcatenatescripts' => 'CONCATENATE_SCRIPTS', + 'rtdisablewpcron' => 'DISABLE_WP_CRON', ]; } @@ -256,7 +258,7 @@ private static function put_backup() public static function has($name) { - if (!empty($GLOBALS[nwdcx_constfx($name.'_false')])) { + if (!empty($GLOBALS['DOCKET_CACHE_RUNTIME'][nwdcx_constfx($name.'_false')])) { return true; } @@ -316,12 +318,20 @@ public static function write_runtime() 'configpath' => self::canopt()->path, ]; - $cons = ''; + $cons = "\$GLOBALS['DOCKET_CACHE_RUNTIME'] = [];".\PHP_EOL; $keys = self::keys(); foreach ($keys as $k => $v) { $ka = nwdcx_constfx($k); if (!empty($config[$ka])) { $val = $config[$ka]; + + // inverse + switch ($k) { + case 'rtconcatenatescripts': + $val = 'on' === $val ? 'off' : 'on'; + break; + } + if ('default' === $val) { continue; } @@ -338,7 +348,7 @@ public static function write_runtime() } } - $cons .= "if(!defined('".$v."')){define('".$v."', ".$val.");}else{\$GLOBALS['".$ka."_FALSE']=1;}".\PHP_EOL; + $cons .= "if(!defined('".$v."')){define('".$v."', ".$val.");}else{\$GLOBALS['DOCKET_CACHE_RUNTIME']['".$ka."_FALSE']=1;}".\PHP_EOL; } } diff --git a/languages/docket-cache.pot b/languages/docket-cache.pot index b712014..f59c60f 100644 --- a/languages/docket-cache.pot +++ b/languages/docket-cache.pot @@ -1,15 +1,15 @@ -# Copyright (C) 2022 Nawawi Jamili +# Copyright (C) 2023 Nawawi Jamili # This file is distributed under the MIT. msgid "" msgstr "" -"Project-Id-Version: Docket Cache 22.07.02\n" +"Project-Id-Version: Docket Cache 22.07.03\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/docket-cache\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2022-12-10T14:03:45+00:00\n" +"POT-Creation-Date: 2023-02-07T13:15:32+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.6.0\n" "X-Domain: docket-cache\n" @@ -99,7 +99,7 @@ msgid "Run Garbage Collector" msgstr "" #: includes/admin/config.php:18 -#: includes/src/Plugin.php:1485 +#: includes/src/Plugin.php:1563 #: includes/src/View.php:316 msgid "Configuration" msgstr "" @@ -121,7 +121,7 @@ msgstr "" #: includes/admin/config.php:51 #: includes/admin/log.php:21 #: includes/src/Canopt.php:82 -#: includes/src/Plugin.php:1474 +#: includes/src/Plugin.php:1552 #: includes/src/View.php:313 msgid "Cache Log" msgstr "" @@ -164,7 +164,7 @@ msgid "Optimisations" msgstr "" #: includes/admin/config.php:108 -#: includes/src/Canopt.php:111 +#: includes/src/Canopt.php:112 msgid "Optimize WP Query" msgstr "" @@ -179,18 +179,20 @@ msgid "Optimize Database Tables" msgstr "" #: includes/admin/config.php:126 -#: includes/admin/config.php:298 -#: includes/admin/config.php:315 -#: includes/admin/config.php:332 -#: includes/admin/config.php:349 -#: includes/admin/config.php:365 -#: includes/admin/config.php:381 -#: includes/admin/config.php:397 -#: includes/admin/config.php:416 -#: includes/admin/config.php:433 -#: includes/admin/config.php:453 -#: includes/admin/config.php:492 -#: includes/admin/config.php:521 +#: includes/admin/config.php:299 +#: includes/admin/config.php:316 +#: includes/admin/config.php:333 +#: includes/admin/config.php:350 +#: includes/admin/config.php:366 +#: includes/admin/config.php:382 +#: includes/admin/config.php:398 +#: includes/admin/config.php:414 +#: includes/admin/config.php:430 +#: includes/admin/config.php:449 +#: includes/admin/config.php:466 +#: includes/admin/config.php:486 +#: includes/admin/config.php:527 +#: includes/admin/config.php:556 #: includes/admin/log.php:31 #: includes/src/View.php:427 msgid "Default" @@ -243,7 +245,7 @@ msgstr "" #: includes/admin/config.php:172 #: includes/src/Canopt.php:96 -msgid "Deactivate WooCommerce Widget" +msgid "Deactivate WooCommerce Classic Widget" msgstr "" #: includes/admin/config.php:178 @@ -275,52 +277,52 @@ msgid "Remove WP Header Junk" msgstr "" #: includes/admin/config.php:213 -#: includes/src/Canopt.php:112 +#: includes/src/Canopt.php:113 msgid "Deactivate XML-RPC / Pingbacks" msgstr "" #: includes/admin/config.php:219 -#: includes/src/Canopt.php:114 +#: includes/src/Canopt.php:115 msgid "Deactivate WP Emoji" msgstr "" #: includes/admin/config.php:225 -#: includes/src/Canopt.php:116 +#: includes/src/Canopt.php:117 msgid "Deactivate WP Feed" msgstr "" #: includes/admin/config.php:231 -#: includes/src/Canopt.php:115 +#: includes/src/Canopt.php:116 msgid "Deactivate WP Embed" msgstr "" #: includes/admin/config.php:237 -#: includes/src/Canopt.php:117 +#: includes/src/Canopt.php:118 msgid "Deactivate WP Lazy Load" msgstr "" #: includes/admin/config.php:243 -#: includes/src/Canopt.php:118 +#: includes/src/Canopt.php:119 msgid "Deactivate WP Sitemap" msgstr "" #: includes/admin/config.php:249 -#: includes/src/Canopt.php:119 +#: includes/src/Canopt.php:120 msgid "Deactivate WP Application Passwords" msgstr "" #: includes/admin/config.php:255 -#: includes/src/Canopt.php:120 +#: includes/src/Canopt.php:121 msgid "Deactivate WP Events & News Feed Dashboard" msgstr "" #: includes/admin/config.php:261 -#: includes/src/Canopt.php:121 +#: includes/src/Canopt.php:122 msgid "Deactivate Browse Happy Checking" msgstr "" #: includes/admin/config.php:267 -#: includes/src/Canopt.php:122 +#: includes/src/Canopt.php:123 msgid "Deactivate Serve Happy Checking" msgstr "" @@ -329,213 +331,236 @@ msgid "Limit WP-Admin HTTP Requests" msgstr "" #: includes/admin/config.php:280 -#: includes/src/Canopt.php:131 +#: includes/src/Canopt.php:135 msgid "HTTP Request Expect header tweaks" msgstr "" -#: includes/admin/config.php:288 +#: includes/admin/config.php:289 msgid "Runtime Options" msgstr "" -#: includes/admin/config.php:292 -#: includes/src/Canopt.php:132 +#: includes/admin/config.php:293 +#: includes/src/Canopt.php:136 msgid "Auto Save Interval" msgstr "" -#: includes/admin/config.php:299 +#: includes/admin/config.php:300 msgid "Every Minute" msgstr "" -#: includes/admin/config.php:300 +#: includes/admin/config.php:301 #: includes/src/Event.php:62 msgid "Every 5 Minutes" msgstr "" -#: includes/admin/config.php:301 +#: includes/admin/config.php:302 msgid "Every 15 Minutes" msgstr "" -#: includes/admin/config.php:302 -#: includes/admin/config.php:319 -#: includes/admin/config.php:336 -#: includes/admin/config.php:351 -#: includes/admin/config.php:367 -#: includes/admin/config.php:383 -#: includes/admin/config.php:399 -#: includes/admin/config.php:418 -#: includes/admin/config.php:435 -#: includes/admin/config.php:455 +#: includes/admin/config.php:303 +#: includes/admin/config.php:320 +#: includes/admin/config.php:337 +#: includes/admin/config.php:352 +#: includes/admin/config.php:368 +#: includes/admin/config.php:384 +#: includes/admin/config.php:400 +#: includes/admin/config.php:416 +#: includes/admin/config.php:432 +#: includes/admin/config.php:451 +#: includes/admin/config.php:468 +#: includes/admin/config.php:488 #: includes/src/View.php:431 msgid "Disable" msgstr "" -#: includes/admin/config.php:309 -#: includes/src/Canopt.php:133 +#: includes/admin/config.php:310 +#: includes/src/Canopt.php:137 msgid "Post Revisions" msgstr "" -#: includes/admin/config.php:316 +#: includes/admin/config.php:317 msgid "Limit to 3 Revisions" msgstr "" -#: includes/admin/config.php:317 +#: includes/admin/config.php:318 msgid "Limit to 5 Revisions" msgstr "" -#: includes/admin/config.php:318 +#: includes/admin/config.php:319 msgid "No Limit" msgstr "" -#: includes/admin/config.php:326 -#: includes/src/Canopt.php:134 -#: includes/src/ReqAction.php:801 +#: includes/admin/config.php:327 +#: includes/src/Canopt.php:138 +#: includes/src/ReqAction.php:824 msgid "Trash Bin" msgstr "" -#: includes/admin/config.php:333 +#: includes/admin/config.php:334 msgid "Empty In 7 Days" msgstr "" -#: includes/admin/config.php:334 +#: includes/admin/config.php:335 msgid "Empty In 14 Days" msgstr "" -#: includes/admin/config.php:335 +#: includes/admin/config.php:336 msgid "Empty In 30 Days" msgstr "" -#: includes/admin/config.php:343 -#: includes/src/Canopt.php:137 +#: includes/admin/config.php:344 +#: includes/src/Canopt.php:141 msgid "Cleanup Image Edits" msgstr "" -#: includes/admin/config.php:350 -#: includes/admin/config.php:366 -#: includes/admin/config.php:382 -#: includes/admin/config.php:398 -#: includes/admin/config.php:417 -#: includes/admin/config.php:434 -#: includes/admin/config.php:454 +#: includes/admin/config.php:351 +#: includes/admin/config.php:367 +#: includes/admin/config.php:383 +#: includes/admin/config.php:399 +#: includes/admin/config.php:415 +#: includes/admin/config.php:431 +#: includes/admin/config.php:450 +#: includes/admin/config.php:467 +#: includes/admin/config.php:487 #: includes/src/View.php:430 msgid "Enable" msgstr "" -#: includes/admin/config.php:359 -#: includes/src/Canopt.php:141 +#: includes/admin/config.php:360 +#: includes/src/Canopt.php:145 msgid "Disallows WP Auto Update Core" msgstr "" -#: includes/admin/config.php:375 -#: includes/src/Canopt.php:135 +#: includes/admin/config.php:376 +#: includes/src/Canopt.php:139 msgid "Disallows Plugin / Theme Editor" msgstr "" -#: includes/admin/config.php:391 -#: includes/src/Canopt.php:136 +#: includes/admin/config.php:392 +#: includes/src/Canopt.php:140 msgid "Disallows Plugin / Theme Update and Installation" msgstr "" -#: includes/admin/config.php:410 -#: includes/src/Canopt.php:138 +#: includes/admin/config.php:408 +#: includes/src/Canopt.php:146 +msgid "Deactivate Concatenate WP-Admin Scripts" +msgstr "" + +#: includes/admin/config.php:424 +#: includes/src/Canopt.php:147 +msgid "Deactivate WP Cron" +msgstr "" + +#: includes/admin/config.php:443 +#: includes/src/Canopt.php:142 msgid "WP Debug" msgstr "" -#: includes/admin/config.php:427 -#: includes/src/Canopt.php:139 +#: includes/admin/config.php:460 +#: includes/src/Canopt.php:143 msgid "WP Debug Display" msgstr "" -#: includes/admin/config.php:447 -#: includes/src/Canopt.php:140 +#: includes/admin/config.php:480 +#: includes/src/Canopt.php:144 msgid "WP Debug Log" msgstr "" -#: includes/admin/config.php:470 +#: includes/admin/config.php:505 msgid "Storage Options" msgstr "" -#: includes/admin/config.php:474 +#: includes/admin/config.php:509 #: includes/admin/overview.php:162 -#: includes/src/Canopt.php:127 +#: includes/src/Canopt.php:128 msgid "Cache Files Limit" msgstr "" -#: includes/admin/config.php:503 +#: includes/admin/config.php:538 #: includes/admin/overview.php:167 -#: includes/src/Canopt.php:126 -#: includes/src/Command.php:493 -#: includes/src/ReqAction.php:751 +#: includes/src/Canopt.php:127 +#: includes/src/Command.php:575 +#: includes/src/ReqAction.php:769 msgid "Cache Disk Limit" msgstr "" -#: includes/admin/config.php:532 +#: includes/admin/config.php:567 #: includes/admin/overview.php:177 -#: includes/src/Canopt.php:128 +#: includes/src/Canopt.php:130 msgid "Chunk Cache Directory" msgstr "" -#: includes/admin/config.php:538 -#: includes/src/Canopt.php:129 +#: includes/admin/config.php:573 +msgid "Check file limits in real-time" +msgstr "" + +#: includes/admin/config.php:579 +#: includes/src/Canopt.php:131 msgid "Auto Remove Stale Cache" msgstr "" -#: includes/admin/config.php:545 +#: includes/admin/config.php:594 +#: includes/src/Canopt.php:133 +msgid "Exclude Empty Object Data" +msgstr "" + +#: includes/admin/config.php:601 msgid "Admin Interface" msgstr "" -#: includes/admin/config.php:549 +#: includes/admin/config.php:605 #: includes/src/Canopt.php:101 msgid "Admin Page Loader" msgstr "" -#: includes/admin/config.php:555 +#: includes/admin/config.php:611 #: includes/src/Canopt.php:106 msgid "Object Cache Data Stats" msgstr "" -#: includes/admin/config.php:561 +#: includes/admin/config.php:617 #: includes/src/Canopt.php:107 msgid "Garbage Collector Action Button" msgstr "" -#: includes/admin/config.php:567 +#: includes/admin/config.php:623 #: includes/src/Canopt.php:108 msgid "Additional Flush Cache Action Button" msgstr "" -#: includes/admin/config.php:574 +#: includes/admin/config.php:630 msgid "Plugin Options" msgstr "" -#: includes/admin/config.php:578 +#: includes/admin/config.php:634 msgid "Docket Cache Auto-Updates" msgstr "" -#: includes/admin/config.php:584 +#: includes/admin/config.php:640 msgid "Check Critical Version" msgstr "" -#: includes/admin/config.php:590 -#: includes/src/Canopt.php:124 +#: includes/admin/config.php:646 +#: includes/src/Canopt.php:125 msgid "Flush Object Cache During Deactivation" msgstr "" -#: includes/admin/config.php:596 -#: includes/src/Canopt.php:125 +#: includes/admin/config.php:652 +#: includes/src/Canopt.php:126 msgid "Flush OPcache During Deactivation" msgstr "" #: includes/admin/cronbot.php:20 #: includes/src/Plugin.php:176 -#: includes/src/Plugin.php:1673 -#: includes/src/Plugin.php:1674 -#: includes/src/Plugin.php:1681 -#: includes/src/Plugin.php:1683 +#: includes/src/Plugin.php:1747 +#: includes/src/Plugin.php:1748 +#: includes/src/Plugin.php:1755 +#: includes/src/Plugin.php:1757 msgid "Not Available" msgstr "" #: includes/admin/cronbot.php:32 -#: includes/src/Plugin.php:1448 +#: includes/src/Plugin.php:1526 #: includes/src/View.php:303 msgid "Cronbot" msgstr "" @@ -850,8 +875,8 @@ msgid "Web Proxy" msgstr "" #: includes/admin/overview.php:35 -#: includes/src/Plugin.php:1437 -#: includes/src/Plugin.php:1743 +#: includes/src/Plugin.php:1515 +#: includes/src/Plugin.php:1817 #: includes/src/View.php:300 msgid "Overview" msgstr "" @@ -1033,59 +1058,59 @@ msgstr "" msgid "Reset to default" msgstr "" -#: includes/admin/resource.php:96 +#: includes/admin/resource.php:97 msgid "Runtime Code" msgstr "" -#: includes/admin/resource.php:98 +#: includes/admin/resource.php:99 msgid "Code to handles WordPress constants." msgstr "" -#: includes/admin/resource.php:103 +#: includes/admin/resource.php:104 msgid "Install Runtime Code" msgstr "" -#: includes/admin/resource.php:103 +#: includes/admin/resource.php:104 msgid "Update Runtime Code" msgstr "" -#: includes/admin/resource.php:116 +#: includes/admin/resource.php:119 msgid "Resources" msgstr "" -#: includes/admin/resource.php:121 +#: includes/admin/resource.php:124 msgid "DOCUMENTATION" msgstr "" -#: includes/admin/resource.php:122 +#: includes/admin/resource.php:125 msgid "To adjust the plugin behaviour and manage through a command line." msgstr "" -#: includes/admin/resource.php:123 +#: includes/admin/resource.php:126 msgid "Documentation" msgstr "" -#: includes/admin/resource.php:127 +#: includes/admin/resource.php:130 msgid "FEEDBACK" msgstr "" -#: includes/admin/resource.php:128 +#: includes/admin/resource.php:131 msgid "Write a review of your experience using this plugin." msgstr "" -#: includes/admin/resource.php:129 +#: includes/admin/resource.php:132 msgid "Submit Review" msgstr "" -#: includes/admin/resource.php:134 +#: includes/admin/resource.php:137 msgid "SPONSOR" msgstr "" -#: includes/admin/resource.php:135 +#: includes/admin/resource.php:138 msgid "Fund Docket Cache one-off or recurring payment to support our open-source development efforts." msgstr "" -#: includes/admin/resource.php:136 +#: includes/admin/resource.php:139 msgid "Become Sponsor" msgstr "" @@ -1101,283 +1126,301 @@ msgstr "" msgid "Admin Page Cache Preloading" msgstr "" -#: includes/src/Canopt.php:109 +#: includes/src/Canopt.php:110 msgid "Docket Cache Auto Update" msgstr "" -#: includes/src/Canopt.php:110 +#: includes/src/Canopt.php:111 msgid "Critical Version Checking" msgstr "" -#: includes/src/Canopt.php:113 +#: includes/src/Canopt.php:114 msgid "Deactivate WP Header Junk" msgstr "" -#: includes/src/Canopt.php:123 +#: includes/src/Canopt.php:124 msgid "Suspend Object Cache" msgstr "" -#: includes/src/Canopt.php:130 +#: includes/src/Canopt.php:129 +msgid "Real-time File Limit Checking" +msgstr "" + +#: includes/src/Canopt.php:132 +msgid "Exclude Stale Cache" +msgstr "" + +#: includes/src/Canopt.php:134 msgid "Limit WP-Admin HTTP requests" msgstr "" -#: includes/src/Command.php:117 +#: includes/src/Command.php:142 msgid "Docket object cache already enabled." msgstr "" -#: includes/src/Command.php:120 +#: includes/src/Command.php:145 msgid "An unknown object cache Drop-In was found. To use Docket object cache, run: wp cache dropin:update." msgstr "" -#: includes/src/Command.php:124 -#: includes/src/ReqAction.php:536 +#: includes/src/Command.php:149 +#: includes/src/ReqAction.php:554 msgid "Object cache enabled." msgstr "" -#: includes/src/Command.php:127 -#: includes/src/ReqAction.php:540 +#: includes/src/Command.php:152 +#: includes/src/ReqAction.php:558 msgid "Object cache could not be enabled." msgstr "" -#: includes/src/Command.php:145 +#: includes/src/Command.php:170 msgid "No object cache Drop-In found." msgstr "" -#: includes/src/Command.php:149 +#: includes/src/Command.php:174 msgid "An unknown object cache Drop-In was found. To use Docket run: wp cache dropin:update." msgstr "" -#: includes/src/Command.php:153 -#: includes/src/ReqAction.php:543 +#: includes/src/Command.php:178 +#: includes/src/ReqAction.php:561 msgid "Object cache disabled." msgstr "" -#: includes/src/Command.php:156 -#: includes/src/ReqAction.php:547 +#: includes/src/Command.php:181 +#: includes/src/ReqAction.php:565 msgid "Object cache could not be disabled." msgstr "" -#: includes/src/Command.php:175 -#: includes/src/ReqAction.php:593 +#: includes/src/Command.php:200 +#: includes/src/ReqAction.php:611 msgid "Updated object cache Drop-In and enabled Docket object cache." msgstr "" -#: includes/src/Command.php:177 -#: includes/src/ReqAction.php:596 +#: includes/src/Command.php:202 +#: includes/src/ReqAction.php:614 msgid "Object cache Drop-In could not be updated." msgstr "" -#: includes/src/Command.php:193 +#: includes/src/Command.php:218 msgid "Flushing cache. Please wait.." msgstr "" #. translators: %d = seconds -#: includes/src/Command.php:204 -#: includes/src/ReqAction.php:576 +#: includes/src/Command.php:231 +#: includes/src/ReqAction.php:594 msgid "Process aborted. The object cache is not fully flushed. The maximum execution time of %d seconds was exceeded." msgstr "" -#: includes/src/Command.php:208 -#: includes/src/ReqAction.php:563 +#: includes/src/Command.php:235 +#: includes/src/ReqAction.php:581 msgid "The cache is empty, no cache needs to be flushed." msgstr "" #. translators: %d = count -#: includes/src/Command.php:212 +#: includes/src/Command.php:239 msgid "The cache was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:229 +#: includes/src/Command.php:256 msgid "The lock has been removed." msgstr "" -#: includes/src/Command.php:245 +#: includes/src/Command.php:272 msgid "Resetting cron event. Please wait.." msgstr "" -#: includes/src/Command.php:249 +#: includes/src/Command.php:280 msgid "Cron event has been reset." msgstr "" -#: includes/src/Command.php:266 +#: includes/src/Command.php:297 msgid "This command does not support Bedrock. Please manually remove the runtime code." msgstr "" -#: includes/src/Command.php:271 +#: includes/src/Command.php:302 msgid "The runtime code has been removed." msgstr "" -#: includes/src/Command.php:273 +#: includes/src/Command.php:304 msgid "Failed to remove runtime code." msgstr "" -#: includes/src/Command.php:290 +#: includes/src/Command.php:321 msgid "This command does not support Bedrock. Please manually install the runtime code." msgstr "" -#: includes/src/Command.php:295 +#: includes/src/Command.php:326 msgid "Updating wp-config.php file successful" msgstr "" -#: includes/src/Command.php:297 -#: includes/src/ReqAction.php:784 +#: includes/src/Command.php:328 +#: includes/src/ReqAction.php:807 msgid "Failed to update wp-config.php file." msgstr "" -#: includes/src/Command.php:314 -msgid "Precache could not be flushed." +#: includes/src/Command.php:345 +#: includes/src/ReqAction.php:896 +msgid "Object Precache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/Command.php:317 +#: includes/src/Command.php:348 msgid "Flushing precache. Please wait.." msgstr "" #. translators: %d = count -#: includes/src/Command.php:322 +#: includes/src/Command.php:355 msgid "The precache was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:339 -msgid "Transient could not be flushed." +#: includes/src/Command.php:372 +msgid "Transient could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/Command.php:342 +#: includes/src/Command.php:375 msgid "Flushing transient. Please wait.." msgstr "" #. translators: %d = couint -#: includes/src/Command.php:348 +#: includes/src/Command.php:382 msgid "The transient was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:365 -#: includes/src/ReqAction.php:891 -msgid "Advanced Post Cache could not be flushed." +#: includes/src/Command.php:399 +#: includes/src/ReqAction.php:914 +msgid "Advanced Post Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/Command.php:368 +#: includes/src/Command.php:402 msgid "Flushing Advanced Post Cache. Please wait.." msgstr "" #. translators: %d = count -#: includes/src/Command.php:373 +#: includes/src/Command.php:409 msgid "The Advanced Post Cache was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:390 -msgid "Menu Cache could not be flushed." +#: includes/src/Command.php:426 +msgid "Menu Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/Command.php:393 +#: includes/src/Command.php:429 msgid "Flushing Menu Cache. Please wait.." msgstr "" #. translators: %d = count -#: includes/src/Command.php:398 +#: includes/src/Command.php:436 msgid "The Menu Cache was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:415 -msgid "Translation Cache could not be flushed." +#: includes/src/Command.php:453 +msgid "Translation Cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/Command.php:418 +#: includes/src/Command.php:456 msgid "Flushing Translation Cache. Please wait.." msgstr "" #. translators: %d = count -#: includes/src/Command.php:423 +#: includes/src/Command.php:463 msgid "The Translation Cache was flushed. Total cache flushed: %d" msgstr "" -#: includes/src/Command.php:439 +#: includes/src/Command.php:479 msgid "Executing the cron event. Please wait.." msgstr "" -#: includes/src/Command.php:457 +#: includes/src/Command.php:501 msgid "Executing the cache stats. Please wait.." msgstr "" -#: includes/src/Command.php:461 +#: includes/src/Command.php:516 msgid "Object size" msgstr "" -#: includes/src/Command.php:462 +#: includes/src/Command.php:517 msgid "File size" msgstr "" -#: includes/src/Command.php:463 +#: includes/src/Command.php:518 msgid "Total file" msgstr "" -#: includes/src/Command.php:464 +#: includes/src/Command.php:520 msgid "Executing the cache stats completed." msgstr "" -#: includes/src/Command.php:481 -msgid "Garbage collector not available." +#: includes/src/Command.php:536 +msgid "Executing the optimizedb. Please wait.." msgstr "" -#: includes/src/Command.php:484 +#: includes/src/Command.php:543 +msgid "Executing the optimizedb completed." +msgstr "" + +#: includes/src/Command.php:559 msgid "Executing the garbage collector. Please wait.." msgstr "" -#: includes/src/Command.php:491 -#: includes/src/ReqAction.php:749 +#: includes/src/Command.php:568 +#: includes/src/ReqAction.php:800 +msgid "Process locked. The garbage collector is in process. Try again in a few seconds." +msgstr "" + +#: includes/src/Command.php:573 +#: includes/src/ReqAction.php:767 msgid "Cache MaxTTL" msgstr "" -#: includes/src/Command.php:492 -#: includes/src/ReqAction.php:750 +#: includes/src/Command.php:574 +#: includes/src/ReqAction.php:768 msgid "Cache File Limit" msgstr "" -#: includes/src/Command.php:495 -#: includes/src/ReqAction.php:752 +#: includes/src/Command.php:577 +#: includes/src/ReqAction.php:770 msgid "Cleanup Cache MaxTTL" msgstr "" -#: includes/src/Command.php:496 -#: includes/src/ReqAction.php:753 +#: includes/src/Command.php:578 +#: includes/src/ReqAction.php:771 msgid "Cleanup Cache File Limit" msgstr "" -#: includes/src/Command.php:497 -#: includes/src/ReqAction.php:754 +#: includes/src/Command.php:579 +#: includes/src/ReqAction.php:772 msgid "Cleanup Cache Disk Limit" msgstr "" -#: includes/src/Command.php:500 -#: includes/src/ReqAction.php:757 +#: includes/src/Command.php:582 +#: includes/src/ReqAction.php:775 msgid "Cleanup Cache Expire" msgstr "" -#: includes/src/Command.php:504 -#: includes/src/ReqAction.php:761 +#: includes/src/Command.php:586 +#: includes/src/ReqAction.php:779 msgid "Cleanup Precache Limit" msgstr "" -#: includes/src/Command.php:508 -#: includes/src/ReqAction.php:765 +#: includes/src/Command.php:590 +#: includes/src/ReqAction.php:783 msgid "Cleanup Stale Cache" msgstr "" -#: includes/src/Command.php:512 -#: includes/src/ReqAction.php:768 +#: includes/src/Command.php:594 +#: includes/src/ReqAction.php:786 msgid "Total Cache Cleanup" msgstr "" -#: includes/src/Command.php:513 -#: includes/src/ReqAction.php:769 +#: includes/src/Command.php:595 +#: includes/src/ReqAction.php:787 msgid "Total Cache Ignored" msgstr "" -#: includes/src/Command.php:514 -#: includes/src/ReqAction.php:770 +#: includes/src/Command.php:596 +#: includes/src/ReqAction.php:788 msgid "Total Cache File" msgstr "" -#: includes/src/Command.php:516 +#: includes/src/Command.php:598 msgid "Executing the garbage collector completed." msgstr "" @@ -1609,304 +1652,296 @@ msgid_plural "of %s Networks" msgstr[0] "" msgstr[1] "" -#: includes/src/Plugin.php:899 +#: includes/src/Plugin.php:905 msgid "Docket Cache plugin requires PHP 7.2.5 or greater." msgstr "" -#: includes/src/Plugin.php:1191 -#: includes/src/Plugin.php:1216 -msgid "No data available" +#: includes/src/Plugin.php:1212 +#: includes/src/Plugin.php:1238 +msgid "The log is empty. No data is available." msgstr "" -#: includes/src/Plugin.php:1460 +#: includes/src/Plugin.php:1538 #: includes/src/View.php:307 msgid "OPcache" msgstr "" #. translators: %s: url -#: includes/src/Plugin.php:1570 +#: includes/src/Plugin.php:1648 msgid "The object-cache.php Drop-In is outdated. Please click Re-Install to update it now.

Re-Install" msgstr "" #. translators: %1$s: url install, %2$s = url dismiss -#: includes/src/Plugin.php:1574 +#: includes/src/Plugin.php:1652 msgid "An unknown object-cache.php Drop-In was found. Please click Install to use Docket Cache.

Install Dismiss" msgstr "" -#: includes/src/Plugin.php:1579 +#: includes/src/Plugin.php:1657 msgid "The Object Cache feature has been disabled at runtime." msgstr "" #. translators: %s: version -#: includes/src/Plugin.php:1714 -#: includes/src/Plugin.php:1729 +#: includes/src/Plugin.php:1788 +#: includes/src/Plugin.php:1803 msgid "Version %s" msgstr "" -#: includes/src/Plugin.php:1744 +#: includes/src/Plugin.php:1818 msgid "Configure" msgstr "" -#: includes/src/Plugin.php:1756 +#: includes/src/Plugin.php:1830 msgid "Docs" msgstr "" -#: includes/src/Plugin.php:1757 +#: includes/src/Plugin.php:1831 msgid "Sponsor" msgstr "" -#: includes/src/Plugin.php:1772 -msgid "Configure auto-updates" -msgstr "" - -#: includes/src/ReqAction.php:506 +#: includes/src/ReqAction.php:524 msgid "Option" msgstr "" -#: includes/src/ReqAction.php:556 +#: includes/src/ReqAction.php:574 msgid "Object cache was flushed." msgstr "" -#: includes/src/ReqAction.php:558 -#: includes/src/ReqAction.php:578 -#: includes/src/ReqAction.php:829 -#: includes/src/ReqAction.php:847 -#: includes/src/ReqAction.php:865 -#: includes/src/ReqAction.php:883 -#: includes/src/ReqAction.php:901 +#: includes/src/ReqAction.php:576 +#: includes/src/ReqAction.php:596 +#: includes/src/ReqAction.php:852 +#: includes/src/ReqAction.php:870 +#: includes/src/ReqAction.php:888 +#: includes/src/ReqAction.php:906 +#: includes/src/ReqAction.php:924 msgid "Total cache flushed" msgstr "" -#: includes/src/ReqAction.php:579 +#: includes/src/ReqAction.php:597 msgid "Alternatively, you may try to flush the cache by doing:" msgstr "" -#: includes/src/ReqAction.php:580 +#: includes/src/ReqAction.php:598 msgid "Hit the \"Disable Object Cache\" button." msgstr "" -#: includes/src/ReqAction.php:581 +#: includes/src/ReqAction.php:599 msgid "Hit the \"Flush Object Cache\" button repeatedly until fully flushed." msgstr "" -#: includes/src/ReqAction.php:582 +#: includes/src/ReqAction.php:600 msgid "Or run the WP-CLI command \"wp cache flush\"." msgstr "" #. translators: %s = cache path -#: includes/src/ReqAction.php:585 +#: includes/src/ReqAction.php:603 msgid "Or manually remove the cache directory: %s" msgstr "" -#: includes/src/ReqAction.php:599 +#: includes/src/ReqAction.php:617 msgid "Cache log was flushed." msgstr "" -#: includes/src/ReqAction.php:602 +#: includes/src/ReqAction.php:620 msgid "Cache log could not be flushed." msgstr "" -#: includes/src/ReqAction.php:605 +#: includes/src/ReqAction.php:623 msgid "Cache file was flushed." msgstr "" -#: includes/src/ReqAction.php:608 +#: includes/src/ReqAction.php:626 msgid "Cache file could not be flushed." msgstr "" -#: includes/src/ReqAction.php:611 +#: includes/src/ReqAction.php:629 msgid "OPcache was flushed." msgstr "" -#: includes/src/ReqAction.php:614 +#: includes/src/ReqAction.php:632 msgid "OPcache could not be flushed." msgstr "" -#: includes/src/ReqAction.php:617 +#: includes/src/ReqAction.php:635 msgid "OPcache already flushed. Try again in a few seconds." msgstr "" -#: includes/src/ReqAction.php:620 +#: includes/src/ReqAction.php:638 msgid "OPcache could not be flushed, opcache_reset function disabled in PHP configuration." msgstr "" -#: includes/src/ReqAction.php:623 +#: includes/src/ReqAction.php:641 msgid "Process locked. Flushing OPcache is in process. Try again in a few seconds." msgstr "" -#: includes/src/ReqAction.php:626 +#: includes/src/ReqAction.php:644 msgid "Cronbot connected." msgstr "" #. translators: %s = error message -#: includes/src/ReqAction.php:632 +#: includes/src/ReqAction.php:650 msgid "Cronbot failed to connect%s" msgstr "" -#: includes/src/ReqAction.php:636 +#: includes/src/ReqAction.php:654 msgid "Cronbot disconnected." msgstr "" -#: includes/src/ReqAction.php:639 +#: includes/src/ReqAction.php:657 msgid "Cronbot failed to disconnect." msgstr "" #. translators: %1$s: cronbot endpoint, %2$s = error message -#: includes/src/ReqAction.php:647 +#: includes/src/ReqAction.php:665 msgid "Pong from %1$s: %2$s." msgstr "" #. translators: %s: cronbot endpoint -#: includes/src/ReqAction.php:650 +#: includes/src/ReqAction.php:668 msgid "Pong from %s : connected." msgstr "" -#: includes/src/ReqAction.php:654 +#: includes/src/ReqAction.php:672 msgid "Running cron successful." msgstr "" #. translators: %s = event hook -#: includes/src/ReqAction.php:672 +#: includes/src/ReqAction.php:690 msgid "Executed the %s event successful" msgstr "" #. translators: %d = cron event -#: includes/src/ReqAction.php:675 +#: includes/src/ReqAction.php:693 msgid "Executed a total of %d cron events" msgstr "" -#: includes/src/ReqAction.php:684 +#: includes/src/ReqAction.php:702 msgid "Failed to run cron." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:691 +#: includes/src/ReqAction.php:709 msgid "%s. Enabled." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:695 +#: includes/src/ReqAction.php:713 msgid "%s. Disabled." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:709 -#: includes/src/ReqAction.php:722 +#: includes/src/ReqAction.php:727 +#: includes/src/ReqAction.php:740 msgid "%s resets to default." msgstr "" #. translators: %1$s = option name, %2$s = option_value -#: includes/src/ReqAction.php:712 +#: includes/src/ReqAction.php:730 msgid "%1$s set to %2$s." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:717 +#: includes/src/ReqAction.php:735 msgid "%s updated." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:726 +#: includes/src/ReqAction.php:744 msgid "Failed to update option %s." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:730 +#: includes/src/ReqAction.php:748 msgid "%s constant already defined or exists in wp-config.php file. This update has no effects." msgstr "" -#: includes/src/ReqAction.php:733 +#: includes/src/ReqAction.php:751 msgid "The physical robots.txt file exists. This update only works with the WordPress robots.txt virtual file." msgstr "" #. translators: %s = option name -#: includes/src/ReqAction.php:737 +#: includes/src/ReqAction.php:755 msgid "%s requires runtime code to be installed. This update has no effects." msgstr "" -#: includes/src/ReqAction.php:740 +#: includes/src/ReqAction.php:758 msgid "Failed to execute the action request. Please try again." msgstr "" -#: includes/src/ReqAction.php:743 +#: includes/src/ReqAction.php:761 msgid "Executing the garbage collector successful" msgstr "" -#: includes/src/ReqAction.php:778 +#: includes/src/ReqAction.php:796 msgid "Failed to run the garbage collector." msgstr "" -#: includes/src/ReqAction.php:781 +#: includes/src/ReqAction.php:804 msgid "Updating wp-config.php file successful." msgstr "" -#: includes/src/ReqAction.php:787 +#: includes/src/ReqAction.php:810 msgid "Reset all configuration successful." msgstr "" -#: includes/src/ReqAction.php:790 +#: includes/src/ReqAction.php:813 msgid "Failed to reset configuration." msgstr "" -#: includes/src/ReqAction.php:793 +#: includes/src/ReqAction.php:816 msgid "Cleanup Post successful" msgstr "" -#: includes/src/ReqAction.php:799 +#: includes/src/ReqAction.php:822 msgid "Revisions" msgstr "" -#: includes/src/ReqAction.php:800 +#: includes/src/ReqAction.php:823 msgid "Auto Drafts" msgstr "" #. translators: %d = sites -#: includes/src/ReqAction.php:806 +#: includes/src/ReqAction.php:829 msgid "For %d sites" msgstr "" -#: includes/src/ReqAction.php:816 +#: includes/src/ReqAction.php:839 msgid "Failed to cleanup Post." msgstr "" -#: includes/src/ReqAction.php:819 +#: includes/src/ReqAction.php:842 msgid "Post already cleanup. Try again in a few seconds." msgstr "" -#: includes/src/ReqAction.php:822 +#: includes/src/ReqAction.php:845 msgid "Menu cache was flushed." msgstr "" -#: includes/src/ReqAction.php:837 -msgid "Menu cache could not be flushed." +#: includes/src/ReqAction.php:860 +msgid "Menu cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/ReqAction.php:840 +#: includes/src/ReqAction.php:863 msgid "Translation cache was flushed." msgstr "" -#: includes/src/ReqAction.php:855 -msgid "Translation cache could not be flushed." +#: includes/src/ReqAction.php:878 +msgid "Translation cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" -#: includes/src/ReqAction.php:858 +#: includes/src/ReqAction.php:881 msgid "Object Precache was flushed." msgstr "" -#: includes/src/ReqAction.php:873 -msgid "Object Precache could not be flushed." -msgstr "" - -#: includes/src/ReqAction.php:876 +#: includes/src/ReqAction.php:899 msgid "Advanced Post Cache was flushed." msgstr "" -#: includes/src/ReqAction.php:894 +#: includes/src/ReqAction.php:917 msgid "Transient cache was flushed." msgstr "" -#: includes/src/ReqAction.php:909 -msgid "Transient cache could not be flushed." +#: includes/src/ReqAction.php:932 +msgid "Transient cache could not be flushed. This action require Docket Cache object-cache.php Drop-in." msgstr "" #. translators: %s: file name @@ -1963,7 +1998,7 @@ msgid "OPcache Viewer allows you to view OPcache status and usage." msgstr "" #: includes/src/View.php:577 -msgid "Cache WP Queries for a post which results in faster data retrieval and reduced database workload. By default only for Post Type post, page and attachment." +msgid "Cache WP Queries for a post which results in faster data retrieval and reduced database workload. By default only for built-in Post Types." msgstr "" #: includes/src/View.php:578 @@ -2015,7 +2050,7 @@ msgid "WooCommerce Admin or Analytics page is a new JavaScript-driven interface msgstr "" #: includes/src/View.php:590 -msgid "Deactivate WooCommerce Widget feature." +msgid "Deactivate WooCommerce Classic Widget feature." msgstr "" #: includes/src/View.php:591 @@ -2123,104 +2158,124 @@ msgid "The maximum cache file can be stored on a disk. The cache file will free msgstr "" #: includes/src/View.php:617 -msgid "Enable this option to chunk cache files into a smaller directory to avoid an excessive number of cache files in a single directory. Only enable this option if you have difficulty when manually clearing the cache or experience a slowdown when the cache becomes too large." +msgid "Enable this option to allow Docket Cache to monitor the cache file limit in real-time." msgstr "" #: includes/src/View.php:618 -msgid "Enable this option to immediately remove the stale cache abandoned by WordPress, WooCommerce and others after doing cache invalidation. By default, it will be removed by GC within 4 days. This option may cause exessive usage of I/O and CPU. Only enable this option if you require to keep storage space in check." +msgid "Enable this option to chunk cache files into smaller directories to avoid an excessive number of cache files in one directory. Only enable it if you have difficulty clearing the cache manually or experience slowdowns when the cache becomes too large." msgstr "" #: includes/src/View.php:619 -msgid "Limit HTTP requests in WP Admin." +msgid "Enable this option to allow GC immediately remove the stale cache abandoned by WordPress, WooCommerce and others after doing cache invalidation." msgstr "" #: includes/src/View.php:620 -msgid "By default, cURL sends the \"Expect\" header all the time which severely impacts performance. Enable this option, only send it if the body is larger than 1 MB." +msgid "Enable this option to exclude stale cache created by WordPress, WooCommerce, and others from being stored on disk. Only enable it if you have an issue with inode limits." msgstr "" #: includes/src/View.php:621 -msgid "WordPress by default automatically saves a draft every 1 minute when editing or create a new post. Changing this behaviour can reduce the usage of server resource." +msgid "Enable this option to exclude empty caches from being stored on disk. Only enable it if you have an issue with inode limits." msgstr "" #: includes/src/View.php:622 -msgid "Post revision is a copy of each edit made to a post or page, allowing the possibility of reverting to a previous version. However, have a revision too much can create a bad impact on database performance. Changing this behaviour can reduce the usage of server resource." +msgid "Limit HTTP requests in WP Admin." msgstr "" #: includes/src/View.php:623 -msgid "This option allows you to change the number of days before WordPress permanently deletes posts, pages, attachments, and comments, from the trash bin. The default is 30 days. There is no confirmation alert when someone clicks on \"Delete Permanently\" if this option is set to \"Disable Trash Bin\"." +msgid "By default, cURL sends the \"Expect\" header all the time which severely impacts performance. Enable this option, only send it if the body is larger than 1 MB." msgstr "" #: includes/src/View.php:624 -msgid "This option will completely disable the use of plugin and theme editor. If this option enabled, no plugins or theme file can be edited." +msgid "WordPress by default automatically saves a draft every 1 minute when editing or create a new post. Changing this behaviour can reduce the usage of server resource." msgstr "" #: includes/src/View.php:625 -msgid "This option will block users being able to use the plugin and theme installation/update functionality from the WordPress admin area." +msgid "Post revision is a copy of each edit made to a post or page, allowing the possibility of reverting to a previous version. However, have a revision too much can create a bad impact on database performance. Changing this behaviour can reduce the usage of server resource." msgstr "" #: includes/src/View.php:626 -msgid "By default, WordPress creates a new set of images every time you edit image and restore the original. It leaves all the edits on the server. Enable this option to change this behaviour." +msgid "This option allows you to change the number of days before WordPress permanently deletes posts, pages, attachments, and comments, from the trash bin. The default is 30 days. There is no confirmation alert when someone clicks on \"Delete Permanently\" if this option is set to \"Disable Trash Bin\"." msgstr "" #: includes/src/View.php:627 -msgid "Enable this option to turn on WordPress debugging." +msgid "This option will completely disable the use of plugin and theme editor. If this option enabled, no plugins or theme file can be edited." msgstr "" #: includes/src/View.php:628 -msgid "Enable this option to print debug info." +msgid "This option will block users being able to use the plugin and theme installation/update functionality from the WordPress admin area." msgstr "" #: includes/src/View.php:629 -msgid "Enable this option to log debug info." +msgid "By default, WordPress creates a new set of images every time you edit image and restore the original. It leaves all the edits on the server. Enable this option to change this behaviour." msgstr "" #: includes/src/View.php:630 +msgid "Enable this option to turn on WordPress debugging." +msgstr "" + +#: includes/src/View.php:631 +msgid "Enable this option to print debug info." +msgstr "" + +#: includes/src/View.php:632 +msgid "Enable this option to log debug info." +msgstr "" + +#: includes/src/View.php:633 msgid "This option will disable all core updates." msgstr "" +#: includes/src/View.php:634 +msgid "Enable this option to disable compression and concatenation of WP-Admin Scripts and CSS." +msgstr "" + #: includes/src/View.php:635 +msgid "Enable this option to disable the WP pseudo-cron. Only enable it if your site is already set up with real Cron." +msgstr "" + +#: includes/src/View.php:640 msgid "No info available" msgstr "" #. translators: %s = option name -#: includes/src/WpConfig.php:378 +#: includes/src/WpConfig.php:388 msgid "%s resets to WordPress default." msgstr "" #. translators: %s = option name -#: includes/src/WpConfig.php:386 -#: includes/src/WpConfig.php:398 -#: includes/src/WpConfig.php:410 -#: includes/src/WpConfig.php:424 +#: includes/src/WpConfig.php:396 +#: includes/src/WpConfig.php:408 +#: includes/src/WpConfig.php:420 +#: includes/src/WpConfig.php:434 msgid "%s set to disable." msgstr "" #. translators: %1$s = option name, %2$s = option_value -#: includes/src/WpConfig.php:389 +#: includes/src/WpConfig.php:399 msgid "%1$s set to every %2$s minutes." msgstr "" #. translators: %s = option name -#: includes/src/WpConfig.php:392 +#: includes/src/WpConfig.php:402 msgid "%s set to every minute." msgstr "" #. translators: %s = option name -#: includes/src/WpConfig.php:401 +#: includes/src/WpConfig.php:411 msgid "%s set to no limit." msgstr "" #. translators: %1$s = option name, %2$s = option_value -#: includes/src/WpConfig.php:404 +#: includes/src/WpConfig.php:414 msgid "%1$s set limit to %2$s revisions." msgstr "" #. translators: %1$s = option name, %2$s = option_value -#: includes/src/WpConfig.php:413 +#: includes/src/WpConfig.php:423 msgid "%1$s set to empty in %2$s days." msgstr "" #. translators: %s = option name -#: includes/src/WpConfig.php:427 +#: includes/src/WpConfig.php:437 msgid "%s set to enable." msgstr "" diff --git a/readme.txt b/readme.txt index ee41873..dcc3b51 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: object cache, OPcache, fastcgi, cache, database, Optimisation, performance Requires at least: 5.4 Tested up to: 6.1 Requires PHP: 7.2.5 -Stable tag: 22.07.02 +Stable tag: 22.07.03 License: MIT License URI: https://github.com/nawawi/docket-cache/blob/master/LICENSE.txt @@ -73,10 +73,11 @@ A heartful thanks and appreciation. - [Jimat Hosting](https://jimathosting.com/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [Themecloud](https://www.themecloud.io/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [Websavers Inc](https://websavers.ca/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) +- [Avunu LLC](https://avu.nu/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [Linqru](https://linqru.jp/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) +- [SecurePay](https://www.securepay.my/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [DNSVault](https://dnsvault.net/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [Exnano Creative](https://exnano.io/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) -- [SecurePay](https://www.securepay.my/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) - [Cun Host](https://cunhost.com/?utm_source=docketcache&utm_campaign=plugin-uri&utm_medium=wporg) @@ -131,7 +132,7 @@ The Cronbot is an external service that pings your website every hour to keep Wo This service offered as an alternative option and is not compulsory to use. By default, this service not connected to the [end-point server](https://cronbot.docketcache.com/). You can completely disable it at the configuration page. = What is Garbage Collector in Docket Cache? = -Garbage Collector is a Cron Events than run every 5 minutes to monitoring cache file purposely for cleanup and collecting stats. +Garbage Collector is a Cron Event that runs every 5 minutes to monitor cache files purposely for cleanup and collecting stats. = What is a RAM disk in Docket Cache? = A RAM disk is a representation of a hard disk using RAM resources, and it can take the form of a hardware device or a virtual disk. @@ -158,12 +159,18 @@ To use it in Windows OS, create RAM Disk and change [DOCKET_CACHE_PATH](https:// = What is the minimum RAM required to use with shared hosting? = By default, WordPress allocates the memory limit to 256 MB. Combined with MySQL and Web Server, you need more than 256 MB. If you're using a cheap hosting plan that allocates only 256 MB for totals usage. It is not enough, and Docket Cache can't improve your website performance. -= What’s the difference with the other object cache plugins? = += What's the difference with the other object cache plugins? = Docket Cache is an Object Cache Accelerator. It does some optimization of caching like cache post queries, comments counting, WordPress translation and more before storing the object caches. = Can I pair using it with other cache plugin? = Yes and No. You can pair using it with page caching plugin, but not with the object cache plugin. += Can I pair using it with LiteSpeed Cache? = +Yes, you can. The LiteSpeed Cache plugin has an Object Cache feature. Currently, by default, it will prompt a notice asking to disable Docket Cache. You only need to turn off LiteSpeed Cache Object Cache in order to use Docket Cache. + += Can I use Docket Cache for heavy WooCommerce stores? = +Yes and No. As suggested, Docket Cache is an alternative to in-memory caches like Redis and Memcached. It depends on how your store has been setups. It may require further tuning to the configuration and may involve other optimisation. + = I'm using a VPS server. Can I use Docket Cache to replace Redis? = Yes, you can. It can boost more your WordPress performance since there is no network connection need to makes and no worry about memory burst, cache-key conflict and error-prone caused by the improper settings. @@ -171,6 +178,36 @@ Yes, you can. It can boost more your WordPress performance since there is no net Please do manually remove wp-content/object-cache.php and wp-content/cache/docket-cache if an error occurs during updates. Thanks. == Changelog == += 22.07.03 = +- Fixed: Tweaks::woocommerce_misc() -> Check if action_scheduler_migration_status is complete to prevent the list on the Scheduled Actions page from disappearing. +- Fixed: Tweaks::woocommerce_widget_remove() -> The classic widget is not disabled. +- Fixed: Plugin::get_precache_maxfile() -> Invalid constant, replace maxfile with precache_maxfile. +- Fixed: Filesystem::sanitize_precache_maxfile() -> Set the limit to 100 by default. +- Fixed: Becache::export() -> Invalid expiration time. Already in timestamp format not in seconds. +- Fixed: WP_Object_Cache::dc_save() -> Serialize twice when checking object size. +- Fixed: Configuration -> A notice is not shown when the constant is already defined. +- Added: Configuration -> Storage Options, Check file limits in real-time and Exclude Empty Object Data. +- Added: Configuration -> Runtime Options, Deactivate Concatenate WP-Admin Scripts and Deactivate WP Cron. +- Added: WP-CLI command -> run:optimizedb. +- Added: DOCKET_CACHE_MAXFILE_LIVECHECK constant to enable checking file limits in real-time. +- Added: DOCKET_CACHE_PRECACHE_MAXKEY, DOCKET_CACHE_PRECACHE_MAXGROUP constant to limit cache keys and groups. +- Added: DOCKET_CACHE_STALECACHE_IGNORE constant to enable excluding stale cache from being stored on disk. +- Added: DOCKET_CACHE_EMPTYCACHE constant to enable excluding empty caches from being stored on disk. +- Added: DOCKET_CACHE_AUTOUPDATE_TOGGLE constant, only to sync with WordPress auto_update_plugins option. +- Added: DOCKET_CACHE_GCRON_DISABLED constant to disable garbage collector cron event. +- Added: Filesystem::suspend_cache_write() -> Temporarily suspends new cache from being stored on disk. +- Changed: DOCKET_CACHE_AUTOUPDATE constant can only be defined manually to force an automatic update. +- Improved: Increase timeout limit if lower than 180 seconds. +- Improved: Constans::maybe_define() -> Keep track of constants that have been defined in the $GLOBAL['DOCKET_CACHE_RUNTIME'] list. +- Improved: WP_Object_Cache::maybe_expire() -> Set expiration to 1 day for key/group matches with the stale cache. +- Improved: Event::garbage_collector() -> Improve wc_cache filtering and other possible stale caches. +- Improved: WP_Object_Cache::dc_code() -> Use native var_export for data type objects and arrays if only have stdClass. +- Removed: Event::watchproc() -> No longer needed. +- Updated: DOCKET_CACHE_ADVCPOST_POSTTYPE -> Set the built-in Post Type as the default. +- Updated: Filesystem::get_max_execution_time() -> Accept value to set time limit. + +Thanks to Kevin Shenk of Avunu LLC for providing access to the staging server for testing purposes. + = 22.07.02 = - Fixed: Tweaks::cache_http_response() -> Default TTL. - Fixed: Tweaks::wpservehappy() -> missing array key.